/* ==========================================================================
   ilikestudyai · 教学动画样式 (v3)
   - 滚动渐入(reveal)
   - 各概念动画演示(与 demos.js 对应)
   配色沿用设计系统 token(见 style.css)
   ========================================================================== */

/* ---------- 滚动渐入 ---------- */
.reveal { opacity: 0; transform: translateY(16px); transition: opacity .55s ease, transform .55s ease; }
.reveal.in { opacity: 1; transform: none; }

/* ---------- 动画演示通用外壳 ---------- */
.ademo { --ad-accent: var(--accent); }
.ademo .demo-head { display: flex; align-items: center; gap: 8px; }
.ademo .dh-icon { font-size: 15px; }
.demo-ctrl { margin-left: auto; display: flex; gap: 6px; }
.dctl { width: 30px; height: 30px; border-radius: 8px; border: 1px solid var(--border-strong);
  background: var(--bg); cursor: pointer; font-size: 14px; line-height: 1; color: var(--text-2);
  display: grid; place-items: center; transition: all .15s ease; }
.dctl:hover { background: var(--accent-soft); border-color: var(--accent); color: var(--accent-dark); transform: translateY(-1px); }
.dctl:active { transform: none; }
.demo-hint { padding: 10px 18px 14px; font-size: 13px; color: var(--text-3); border-top: 1px dashed var(--border); background: #fffdf5; }
.ademo.paused .pipe-stage, .ademo.paused .tf-layer, .ademo.paused .ag-node,
.ademo.paused .rag-node, .ademo.paused .emb-dot, .ademo.paused .tr-curve,
.ademo.paused .curve, .ademo.paused .pe-wave, .ademo.paused .of-stop { animation-play-state: paused !important; }

/* 分词器 token 弹入 */
.tok.pop { animation: tokPop .32s cubic-bezier(.34,1.56,.64,1) backwards; }
.tok-count { align-self: center; }
@keyframes tokPop { from { opacity: 0; transform: scale(.6) translateY(6px); } to { opacity: 1; transform: none; } }

/* ==========================================================================
   pipeline · 数字化流水线
   ========================================================================== */
.pipe { display: flex; flex-direction: column; gap: 4px; }
.pipe-stage { display: flex; align-items: center; gap: 14px; padding: 12px 16px; border-radius: 12px;
  border: 1px solid var(--border); background: var(--bg-subtle); transition: all .4s ease; }
.pipe-stage .ps-label { font-size: 13px; font-weight: 600; color: var(--text-3); width: 130px; flex-shrink: 0; }
.pipe-stage .ps-val { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; opacity: .35; transition: opacity .4s ease; }
.pipe-stage.lit { border-color: var(--hf-yellow-dark); background: #fffdf3; box-shadow: 0 0 0 3px rgba(255,210,30,.18); }
.pipe-stage.lit .ps-label { color: var(--hf-yellow-dark); }
.pipe-stage.lit .ps-val { opacity: 1; }
.pipe-arrow { text-align: center; color: var(--border-strong); font-size: 15px; transition: color .3s; line-height: 1; }
.pipe-arrow.flow { color: var(--hf-orange); animation: arrowBounce .6s ease; }
@keyframes arrowBounce { 0%,100% { transform: translateY(0); } 50% { transform: translateY(3px); } }
.pv-text { font-size: 16px; color: var(--text-1); }
.pv-tok { padding: 3px 9px; border-radius: 7px; background: #ffe0cc; font-size: 14px; }
.pv-id { padding: 3px 9px; border-radius: 7px; background: #e0e7ff; font-family: "Source Code Pro", monospace; font-size: 14px; color: var(--accent-dark); }
.pv-vec { padding: 3px 8px; border-radius: 7px; background: #d9f2e3; font-family: "Source Code Pro", monospace; font-size: 12.5px; color: #166534; }

/* ==========================================================================
   embedding · 语义空间散点
   ========================================================================== */
.emb-map { position: relative; height: 300px; border-radius: 14px; overflow: hidden;
  background: radial-gradient(circle at 30% 30%, #f6f8ff, #fbfbfd 60%, #f4f5f7);
  border: 1px solid var(--border); }
.emb-link { position: absolute; inset: 0; width: 100%; height: 100%; }
.emb-link line { stroke-width: .5; opacity: 0; transition: opacity .6s ease; }
.emb-link .lnear { stroke: var(--green); stroke-dasharray: 2 1; }
.emb-link .lfar { stroke: var(--red); stroke-dasharray: 2 1; }
.emb-map.linked .lnear, .emb-map.linked .lfar { opacity: .8; }
.emb-dot { position: absolute; transform: translate(-50%,-50%) scale(.4); padding: 5px 11px; border-radius: 999px;
  font-size: 13.5px; font-weight: 600; opacity: 0; transition: all .5s cubic-bezier(.34,1.4,.64,1); white-space: nowrap;
  box-shadow: var(--shadow-sm); }
.emb-dot.show { opacity: 1; transform: translate(-50%,-50%) scale(1); }
.emb-dot.g-animal { background: #fff3c4; color: #92610a; border: 1px solid #ffe08a; }
.emb-dot.g-vehicle { background: #e0e7ff; color: var(--accent-dark); border: 1px solid #c7d0fb; }
.emb-dot.g-royal { background: #fde2f3; color: #a0276b; border: 1px solid #f9c6e3; }
.emb-legend { position: absolute; left: 12px; bottom: 10px; right: 12px; display: flex; flex-direction: column; gap: 4px; font-size: 12px; color: var(--text-3); }
.emb-legend span { display: flex; align-items: center; gap: 6px; }
.emb-legend .sw { width: 16px; height: 0; border-top: 2px dashed; display: inline-block; }
.emb-legend .sw.near { border-color: var(--green); }
.emb-legend .sw.far { border-color: var(--red); }

/* ==========================================================================
   attention · 注意力权重
   ========================================================================== */
.attn-q { font-size: 13.5px; color: var(--text-2); margin-bottom: 14px; }
.attn-qcur { color: var(--accent-dark); background: var(--accent-soft); padding: 1px 8px; border-radius: 6px; font-size: 14px; }
.attn-row { display: flex; gap: 6px; align-items: flex-end; justify-content: space-between; }
.attn-col { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 6px; min-width: 0; }
.attn-bar { width: 100%; max-width: 34px; height: 90px; background: var(--bg-muted); border-radius: 8px; display: flex; align-items: flex-end; overflow: hidden; }
.attn-bar span { display: block; width: 100%; height: 4%; border-radius: 8px 8px 0 0;
  background: linear-gradient(180deg, var(--accent), var(--accent-dark)); transition: height .5s cubic-bezier(.4,0,.2,1); }
.attn-col.hi .attn-bar span { background: linear-gradient(180deg, var(--hf-yellow), var(--hf-orange)); }
.attn-col.is-q .attn-bar span { background: linear-gradient(180deg, #86efac, var(--green)); }
.attn-w { font-size: 11.5px; color: var(--text-3); font-variant-numeric: tabular-nums; }
.attn-col.hi .attn-w { color: var(--hf-orange); font-weight: 700; }
.attn-tok { width: 100%; padding: 5px 2px; border-radius: 8px; border: 1px solid var(--border);
  background: var(--bg); cursor: pointer; font-size: 13px; color: var(--text-1); transition: all .15s; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.attn-tok:hover { border-color: var(--accent); background: var(--accent-soft); }
.attn-col.is-q .attn-tok { border-color: var(--green); background: var(--green-soft); font-weight: 700; }
.attn-col.hi .attn-tok { border-color: var(--hf-yellow-dark); }
@media (max-width: 620px) { .attn-bar { height: 60px; } .attn-tok { font-size: 11px; } }

/* ==========================================================================
   transformer · 层堆叠数据流
   ========================================================================== */
.tf-stack { display: flex; flex-direction: column; gap: 8px; }
.tf-layer { position: relative; padding: 12px 16px 12px 40px; border-radius: 12px; border: 1px solid var(--border);
  background: var(--bg-subtle); font-size: 14px; color: var(--text-2); transition: all .35s ease; }
.tf-layer .tf-dot { position: absolute; left: 15px; top: 50%; transform: translateY(-50%); width: 12px; height: 12px;
  border-radius: 50%; background: var(--border-strong); transition: all .35s ease; }
.tf-layer.emb { border-color: #ffe08a; }
.tf-layer.blk { border-color: #c7d0fb; }
.tf-layer.rep { text-align: center; padding-left: 16px; font-style: italic; color: var(--text-4); border-style: dashed; }
.tf-layer.rep .tf-dot { display: none; }
.tf-layer.done { background: #f2f4ff; color: var(--text-2); }
.tf-layer.done .tf-dot { background: var(--accent); }
.tf-layer.pulse { border-color: var(--hf-orange); background: #fff6f1; box-shadow: 0 0 0 4px rgba(255,107,53,.16); transform: translateX(3px); }
.tf-layer.pulse .tf-dot { background: var(--hf-orange); box-shadow: 0 0 0 5px rgba(255,107,53,.25); animation: dotPing .65s ease; }
.tf-layer.io { border-color: var(--green); }
.tf-layer.io.pulse { border-color: var(--green); background: var(--green-soft); box-shadow: 0 0 0 4px rgba(22,163,74,.15); }
.tf-layer.io.pulse .tf-dot { background: var(--green); box-shadow: 0 0 0 5px rgba(22,163,74,.2); }
@keyframes dotPing { 0% { transform: translateY(-50%) scale(.7); } 60% { transform: translateY(-50%) scale(1.5); } 100% { transform: translateY(-50%) scale(1); } }

/* ==========================================================================
   training · 训练循环 + loss 曲线
   ========================================================================== */
.tr-wrap { display: grid; grid-template-columns: 130px 1fr; gap: 18px; align-items: center; }
.tr-loop { display: flex; flex-direction: column; gap: 8px; }
.tr-step { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-radius: 10px; font-size: 13px;
  border: 1px solid var(--border); background: var(--bg-subtle); color: var(--text-3); transition: all .3s ease; }
.tr-step .ts-n { width: 20px; height: 20px; border-radius: 50%; background: var(--border); color: #fff; display: grid; place-items: center; font-size: 11px; font-weight: 700; }
.tr-step.act { border-color: var(--hf-orange); background: #fff6f1; color: var(--hf-orange); font-weight: 600; transform: translateX(2px); }
.tr-step.act .ts-n { background: var(--hf-orange); }
.tr-chart { position: relative; }
.tr-chart svg { width: 100%; height: 150px; display: block; }
.tr-chart .axis { stroke: var(--border-strong); stroke-width: 1.5; }
.tr-curve { fill: none; stroke: var(--accent); stroke-width: 3; stroke-linecap: round; }
.tr-ylabel { position: absolute; left: 2px; top: 4px; font-size: 11px; color: var(--text-4); }
.tr-xlabel { position: absolute; right: 6px; bottom: 2px; font-size: 11px; color: var(--text-4); }
.tr-loss { position: absolute; right: 8px; top: 8px; font-size: 13px; color: var(--text-2); background: var(--accent-soft); padding: 3px 10px; border-radius: 8px; }
.tr-loss b { color: var(--accent-dark); font-variant-numeric: tabular-nums; }
@media (max-width: 620px) { .tr-wrap { grid-template-columns: 1fr; } }

/* ==========================================================================
   decode · 自回归生成
   ========================================================================== */
.dec-line { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; min-height: 48px; }
.dec-tag { font-size: 12px; color: var(--text-4); border: 1px solid var(--border); border-radius: 6px; padding: 2px 8px; }
.dec-seq { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.dec-tok { padding: 6px 12px; border-radius: 9px; font-size: 15px; border: 1px solid var(--border); background: var(--bg-subtle); }
.dec-tok.gen { background: var(--accent-soft); border-color: #c7d0fb; color: var(--accent-dark); font-weight: 600; }
.dec-tok.new { animation: decPop .45s cubic-bezier(.34,1.56,.64,1); box-shadow: 0 0 0 4px rgba(107,127,243,.2); }
@keyframes decPop { from { opacity: 0; transform: translateY(8px) scale(.7); } to { opacity: 1; transform: none; } }
.dec-status { margin-top: 12px; font-size: 13px; color: var(--text-3); }

/* ==========================================================================
   agent · ReAct 循环
   ========================================================================== */
.ag-cycle { display: flex; align-items: stretch; gap: 8px; flex-wrap: wrap; position: relative; }
.ag-node { flex: 1; min-width: 120px; display: flex; flex-direction: column; gap: 4px; padding: 14px; border-radius: 12px;
  border: 1px solid var(--border); background: var(--bg-subtle); transition: all .35s ease; position: relative; }
.ag-node .ag-n { position: absolute; top: -9px; left: 12px; width: 20px; height: 20px; border-radius: 50%; background: var(--border-strong);
  color: #fff; font-size: 11px; font-weight: 700; display: grid; place-items: center; transition: all .35s; }
.ag-node b { font-size: 14px; color: var(--text-1); }
.ag-node .ag-d { font-size: 12px; color: var(--text-3); }
.ag-node.past { border-color: #c7d0fb; background: #f5f7ff; }
.ag-node.past .ag-n { background: var(--accent); }
.ag-node.act { border-color: var(--hf-orange); background: #fff6f1; box-shadow: 0 4px 14px rgba(255,107,53,.18); transform: translateY(-3px); }
.ag-node.act .ag-n { background: var(--hf-orange); }
.ag-arrow { align-self: center; color: var(--border-strong); font-size: 18px; }
.ag-loop { flex-basis: 100%; text-align: center; font-size: 12.5px; color: var(--accent-dark); margin-top: 6px; }

/* ==========================================================================
   rag · 检索增强流程
   ========================================================================== */
.rag-flow { display: flex; align-items: stretch; gap: 6px; flex-wrap: wrap; }
.rag-node { flex: 1; min-width: 92px; display: flex; flex-direction: column; gap: 3px; align-items: center; text-align: center;
  padding: 12px 8px; border-radius: 12px; border: 1px solid var(--border); background: var(--bg-subtle); transition: all .35s ease; }
.rag-node b { font-size: 13.5px; color: var(--text-1); }
.rag-node span { font-size: 11px; color: var(--text-4); font-family: "Source Code Pro", monospace; }
.rag-node.past { border-color: #ffe08a; background: #fffdf3; }
.rag-node.act { border-color: var(--hf-orange); background: #fff6f1; box-shadow: 0 4px 14px rgba(255,107,53,.16); transform: translateY(-3px); }
.rag-arrow { align-self: center; color: var(--border-strong); font-size: 20px; }
.rag-note { margin-top: 12px; text-align: center; font-size: 12px; color: var(--text-3); }

/* ==========================================================================
   v3.1 · 通用流程组件 gflow
   ========================================================================== */
.gflow { display: flex; align-items: stretch; gap: 6px; flex-wrap: wrap; }
.gflow-v { flex-direction: column; }
.gf-node { flex: 1; min-width: 96px; display: flex; align-items: center; gap: 9px; padding: 12px 13px;
  border-radius: 12px; border: 1px solid var(--border); background: var(--bg-subtle); transition: all .35s ease; position: relative; }
.gf-ic { font-size: 20px; flex-shrink: 0; }
.gf-n { width: 22px; height: 22px; border-radius: 50%; background: var(--border-strong); color: #fff; font-size: 12px;
  font-weight: 700; display: grid; place-items: center; flex-shrink: 0; transition: all .35s; }
.gf-txt { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.gf-txt b { font-size: 13.5px; color: var(--text-1); }
.gf-d { font-size: 11.5px; color: var(--text-3); }
.gf-arrow { align-self: center; color: var(--border-strong); font-size: 19px; }
.gf-node.past { border-color: #ffe08a; background: #fffdf3; }
.gf-node.past .gf-n { background: var(--hf-yellow-dark); }
.gf-node.act { border-color: var(--hf-orange); background: #fff6f1; box-shadow: 0 4px 14px rgba(255,107,53,.16); transform: translateY(-3px); }
.gf-node.act .gf-n { background: var(--hf-orange); }
.gf-node.gf-good.act { border-color: var(--green); background: var(--green-soft); box-shadow: 0 4px 14px rgba(22,163,74,.16); }
.gf-node.gf-good.act .gf-n { background: var(--green); }
.gf-node.gf-bad { border-color: #f3c9c9; }
.gf-node.gf-warn.act { border-color: var(--hf-yellow-dark); background: #fffdf3; box-shadow: 0 4px 14px rgba(255,157,11,.18); }
.gf-note { margin-top: 12px; text-align: center; font-size: 12px; color: var(--text-3); }

/* ==========================================================================
   v3.1 · 通用对比组件 vs
   ========================================================================== */
.vs-wrap { display: grid; grid-template-columns: 1fr auto 1fr; gap: 12px; align-items: stretch; }
.vs-col { border-radius: 14px; border: 1px solid var(--border); background: var(--bg-subtle); padding: 14px 16px; transition: all .4s ease; opacity: .68; }
.vs-col.act { opacity: 1; transform: translateY(-3px); }
.vs-bad.act { border-color: var(--red); background: var(--red-soft); box-shadow: 0 4px 16px rgba(239,68,68,.14); }
.vs-good.act { border-color: var(--green); background: var(--green-soft); box-shadow: 0 4px 16px rgba(22,163,74,.14); }
.vs-head { display: flex; align-items: center; gap: 7px; font-size: 14.5px; font-weight: 700; color: var(--text-1); margin-bottom: 10px; }
.vs-tag { margin-left: auto; font-style: normal; font-size: 11px; font-weight: 600; padding: 2px 8px; border-radius: 999px; background: rgba(0,0,0,.05); color: var(--text-3); }
.vs-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 7px; }
.vs-list li { font-size: 12.5px; color: var(--text-2); padding-left: 16px; position: relative; line-height: 1.5; }
.vs-bad .vs-list li::before { content: "✕"; position: absolute; left: 0; color: var(--red); font-size: 11px; }
.vs-good .vs-list li::before { content: "✓"; position: absolute; left: 0; color: var(--green); font-size: 11px; }
.vs-mid { align-self: center; font-size: 15px; font-weight: 800; color: var(--text-4); letter-spacing: .5px; }
@media (max-width: 620px) { .vs-wrap { grid-template-columns: 1fr; } .vs-mid { text-align: center; } }

/* ==========================================================================
   align · 3H 支柱(l6-1)
   ========================================================================== */
.al-wrap { display: flex; gap: 10px; flex-wrap: wrap; }
.al-pillar { flex: 1; min-width: 130px; display: flex; flex-direction: column; align-items: center; text-align: center; gap: 6px;
  padding: 18px 14px; border-radius: 14px; border: 1px solid var(--border); background: var(--bg-subtle); transition: all .4s ease; }
.al-pillar .al-ic { font-size: 26px; }
.al-pillar b { font-size: 14.5px; color: var(--text-1); }
.al-pillar .al-d { font-size: 12px; color: var(--text-3); }
.al-pillar.past { border-color: #c7d0fb; background: #f5f7ff; }
.al-pillar.act { border-color: var(--accent); background: var(--accent-soft); box-shadow: 0 6px 18px rgba(107,127,243,.18); transform: translateY(-4px); }
.al-note { margin-top: 12px; text-align: center; font-size: 12.5px; color: var(--accent-dark); }

/* ==========================================================================
   posenc · 位置编码(l1-4)
   ========================================================================== */
.pe-toks { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 14px; }
.pe-tok { position: relative; padding: 8px 14px 8px; border-radius: 10px; border: 1px solid var(--border); background: var(--bg-subtle);
  font-size: 15px; transition: all .35s ease; }
.pe-tok i { position: absolute; top: -9px; left: 8px; font-style: normal; font-size: 10px; padding: 1px 6px; border-radius: 999px;
  background: var(--border-strong); color: #fff; }
.pe-tok.act { border-color: var(--accent); background: var(--accent-soft); box-shadow: 0 0 0 4px rgba(107,127,243,.16); transform: translateY(-2px); }
.pe-tok.act i { background: var(--accent); }
.pe-plus { margin-left: auto; font-size: 12px; color: var(--text-4); }
.pe-waves svg { width: 100%; height: 84px; display: block; border-radius: 10px; background: var(--bg-subtle); border: 1px solid var(--border); }
.pe-wave { fill: none; stroke-width: 2; opacity: .35; transition: opacity .4s; }
.pe-run .pe-wave { stroke-dasharray: 6 4; animation: peDash 3s linear infinite; }
.pe-wave.hi { opacity: 1; }
@keyframes peDash { to { stroke-dashoffset: -60; } }
.pe-legend { display: flex; gap: 14px; flex-wrap: wrap; margin-top: 8px; font-size: 11.5px; color: var(--text-3); }
.pe-legend span { display: flex; align-items: center; gap: 5px; }
.pe-legend i { width: 14px; height: 3px; border-radius: 2px; display: inline-block; }

/* ==========================================================================
   multihead · 多头注意力(l2-4)
   ========================================================================== */
.mh-q { font-size: 13.5px; color: var(--text-2); margin-bottom: 12px; }
.mh-q b { color: var(--accent-dark); background: var(--accent-soft); padding: 1px 8px; border-radius: 6px; }
.mh-heads { display: flex; flex-direction: column; gap: 8px; }
.mh-head { display: grid; grid-template-columns: 96px 1fr; gap: 12px; align-items: center; padding: 10px 14px;
  border-radius: 12px; border: 1px solid var(--border); background: var(--bg-subtle); transition: all .35s ease; }
.mh-name { display: flex; flex-direction: column; gap: 2px; }
.mh-name b { font-size: 13px; color: var(--text-1); }
.mh-name span { font-size: 11px; color: var(--text-3); }
.mh-cells { display: flex; gap: 8px; }
.mh-cell { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 3px; min-width: 0; }
.mh-track { width: 100%; height: 8px; border-radius: 5px; background: var(--bg-muted); overflow: hidden; }
.mh-track i { display: block; height: 100%; border-radius: 5px; background: var(--border-strong); transition: width .5s ease, background .35s; }
.mh-tok { font-size: 12.5px; color: var(--text-2); }
.mh-cell.self .mh-tok { color: var(--text-4); }
.mh-pct { font-size: 10.5px; color: var(--text-4); font-variant-numeric: tabular-nums; }
.mh-accent.act { border-color: var(--accent); background: var(--accent-soft); box-shadow: 0 4px 14px rgba(107,127,243,.15); }
.mh-accent .mh-track i { background: var(--accent); }
.mh-orange.act { border-color: var(--hf-orange); background: #fff6f1; box-shadow: 0 4px 14px rgba(255,107,53,.15); }
.mh-orange .mh-track i { background: var(--hf-orange); }
.mh-green.act { border-color: var(--green); background: var(--green-soft); box-shadow: 0 4px 14px rgba(22,163,74,.15); }
.mh-green .mh-track i { background: var(--green); }
.mh-head.past { opacity: .8; }
.mh-concat { margin-top: 12px; display: flex; align-items: center; justify-content: center; gap: 10px; padding: 11px;
  border-radius: 12px; border: 1px dashed var(--border-strong); font-size: 13px; color: var(--text-3); transition: all .35s; }
.mh-concat .mh-arrow { color: var(--border-strong); }
.mh-concat.act { border-style: solid; border-color: var(--hf-yellow-dark); background: #fffdf3; color: var(--text-1); box-shadow: 0 0 0 3px rgba(255,210,30,.18); }
.mh-concat.act .mh-wo { color: var(--hf-orange); font-weight: 700; }
@media (max-width: 620px) { .mh-head { grid-template-columns: 1fr; } .mh-pct { display: none; } }

/* ==========================================================================
   ffn · 前馈网络与残差(l2-5)
   ========================================================================== */
.ffn-wrap { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; position: relative; }
.ffn-node { flex: 1; min-width: 78px; display: flex; flex-direction: column; align-items: center; gap: 3px; padding: 12px 8px;
  border-radius: 12px; border: 1px solid var(--border); background: var(--bg-subtle); transition: all .35s ease; }
.ffn-node b { font-size: 13px; color: var(--text-1); }
.ffn-node span { font-size: 11px; color: var(--text-3); font-family: "Source Code Pro", monospace; }
.ffn-ar { color: var(--border-strong); font-size: 17px; }
.ffn-node.past { border-color: #c7d0fb; background: #f5f7ff; }
.ffn-node.act { border-color: var(--hf-orange); background: #fff6f1; box-shadow: 0 4px 14px rgba(255,107,53,.16); transform: translateY(-3px); }
.ffn-node.up.act { border-color: var(--accent); background: var(--accent-soft); box-shadow: 0 4px 14px rgba(107,127,243,.16); }
.ffn-res { flex-basis: 100%; margin-top: 10px; text-align: center; font-size: 12.5px; color: var(--text-3);
  padding: 9px; border-radius: 10px; border: 1px dashed var(--border-strong); transition: all .35s; }
.ffn-res.act { border-style: solid; border-color: var(--green); background: var(--green-soft); color: #166534; font-weight: 600; }
@media (max-width: 620px) { .ffn-ar { display: none; } .ffn-node { min-width: 44%; } }

/* ==========================================================================
   layernorm · 归一化(l2-6)
   ========================================================================== */
.ln-row { display: flex; align-items: center; gap: 12px; }
.ln-tag { font-size: 12px; color: var(--text-3); width: 62px; flex-shrink: 0; }
.ln-bars { flex: 1; display: flex; align-items: center; gap: 6px; height: 60px; }
.ln-bar { flex: 1; display: flex; align-items: center; justify-content: center; height: 100%; }
.ln-bar i { display: block; width: 100%; max-width: 26px; height: 4%; border-radius: 5px; background: var(--border-strong);
  transition: height .6s cubic-bezier(.4,0,.2,1), background .4s; }
.ln-bars.before .ln-bar.pos.grow i { background: linear-gradient(180deg, #f9a8a8, var(--red)); }
.ln-bars.before .ln-bar.neg.grow i { background: linear-gradient(180deg, #fca5a5, #dc2626); opacity: .7; }
.ln-bars.after .ln-bar.grow i { background: linear-gradient(180deg, #86efac, var(--green)); }
.ln-bar.grow i { height: var(--h, 40%); }
.ln-stat { font-size: 11.5px; color: var(--text-4); width: 96px; text-align: right; flex-shrink: 0; }
.ln-arrow { text-align: center; font-size: 12px; color: var(--text-4); margin: 10px 0; transition: color .3s; }
.ln-arrow.act { color: var(--accent-dark); font-weight: 600; }
@media (max-width: 620px) { .ln-stat { display: none; } }

/* ==========================================================================
   nexttoken · Next-Token Prediction(l4-1)
   ========================================================================== */
.nt-ctx { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; margin-bottom: 16px; }
.nt-tag { font-size: 11.5px; color: var(--text-4); border: 1px solid var(--border); border-radius: 6px; padding: 2px 8px; }
.nt-tok { padding: 6px 12px; border-radius: 9px; font-size: 15px; border: 1px solid var(--border); background: var(--bg-subtle); }
.nt-tok.pred { border-style: dashed; color: var(--text-4); background: var(--bg); min-width: 44px; text-align: center; transition: all .35s; }
.nt-tok.pred.solved { border-style: solid; border-color: var(--accent); background: var(--accent-soft); color: var(--accent-dark); font-weight: 700; animation: decPop .45s cubic-bezier(.34,1.56,.64,1); }
.nt-dist { display: flex; gap: 10px; align-items: flex-end; justify-content: space-between; }
.nt-cand { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 5px; max-width: 62px; }
.nt-bar { width: 100%; height: 92px; background: var(--bg-muted); border-radius: 8px; display: flex; align-items: flex-end; overflow: hidden; }
.nt-bar span { display: block; width: 100%; height: 0; border-radius: 8px 8px 0 0; background: linear-gradient(180deg, #c7d0fb, var(--accent)); transition: height .5s cubic-bezier(.4,0,.2,1); }
.nt-cand.grow .nt-bar span { height: var(--h); }
.nt-cand.top.grow .nt-bar span { background: linear-gradient(180deg, var(--hf-yellow), var(--hf-orange)); }
.nt-p { font-size: 11px; color: var(--text-3); font-variant-numeric: tabular-nums; }
.nt-t { font-size: 14px; color: var(--text-1); padding: 3px 10px; border-radius: 7px; border: 1px solid var(--border); background: var(--bg); }
.nt-cand.top .nt-t { border-color: var(--hf-yellow-dark); background: #fffdf3; font-weight: 700; }
.nt-out { margin-top: 14px; text-align: center; font-size: 13px; color: var(--text-4); transition: all .35s; }
.nt-out.act { color: var(--text-1); }
.nt-out b { color: var(--hf-orange); font-size: 15px; }

/* ==========================================================================
   crossentropy · 交叉熵损失(l4-2)
   ========================================================================== */
.ce-prob { font-size: 14px; color: var(--text-2); margin-bottom: 12px; }
.ce-p { color: var(--accent-dark); font-variant-numeric: tabular-nums; font-size: 16px; }
.ce-gauge { position: relative; }
.ce-fill { height: 26px; border-radius: 8px; background: var(--bg-muted); overflow: hidden; border: 1px solid var(--border); }
.ce-fill span { display: block; height: 100%; width: 0; border-radius: 8px; transition: width .6s cubic-bezier(.4,0,.2,1), background .4s; background: var(--accent); }
.ce-fill span.bad { background: linear-gradient(90deg, var(--hf-orange), var(--red)); }
.ce-fill span.mid { background: linear-gradient(90deg, var(--hf-yellow), var(--hf-orange)); }
.ce-fill span.good { background: linear-gradient(90deg, #86efac, var(--green)); }
.ce-scale { display: flex; justify-content: space-between; margin-top: 4px; }
.ce-scale i { font-style: normal; font-size: 10.5px; color: var(--text-4); }
.ce-loss { margin-top: 12px; font-size: 15px; color: var(--text-2); }
.ce-l { color: var(--text-1); font-variant-numeric: tabular-nums; font-size: 20px; font-weight: 700; }
.ce-note { margin-top: 6px; font-size: 12.5px; padding: 6px 12px; border-radius: 8px; display: inline-block; transition: all .4s; }
.ce-note.bad { color: #b91c1c; background: var(--red-soft); }
.ce-note.mid { color: #92610a; background: #fff8e1; }
.ce-note.good { color: #166534; background: var(--green-soft); }

/* ==========================================================================
   batchsize / overfit · 曲线图(l4-4 / l4-6)
   ========================================================================== */
.bs-chart, .of-chart { position: relative; }
.bs-chart svg, .of-chart svg { width: 100%; height: 154px; display: block; }
.bs-chart .axis, .of-chart .axis { stroke: var(--border-strong); stroke-width: 1.5; }
.curve { fill: none; stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: var(--len, 300); stroke-dashoffset: var(--len, 300); animation: drawPath 3.4s ease-in-out infinite; }
@keyframes drawPath { 0% { stroke-dashoffset: var(--len, 300); } 60%, 100% { stroke-dashoffset: 0; } }
.bs-ylabel { position: absolute; left: 2px; top: 2px; font-size: 11px; color: var(--text-4); }
.bs-legend, .of-legend { display: flex; flex-direction: column; gap: 4px; margin-top: 10px; font-size: 12px; color: var(--text-3); }
.bs-legend span, .of-legend span { display: flex; align-items: center; gap: 6px; }
.bs-legend i, .of-legend i { width: 16px; height: 3px; border-radius: 2px; display: inline-block; }
.of-stop { stroke: var(--hf-yellow-dark); stroke-width: 1.6; stroke-dasharray: 4 3; opacity: 0; }
.of-chart.run .of-stop { animation: stopIn 3.4s ease-in-out infinite; }
@keyframes stopIn { 0%, 55% { opacity: 0; } 70%, 100% { opacity: .9; } }
.of-stoplabel { position: absolute; top: 6px; left: 62%; font-size: 11px; color: var(--hf-yellow-dark); font-weight: 600; opacity: 0; transition: opacity .4s; }
.of-chart.run .of-stoplabel { animation: stopIn 3.4s ease-in-out infinite; }

/* ==========================================================================
   lora · 低秩旁路(l5-4)
   ========================================================================== */
.lora-wrap { display: flex; flex-direction: column; align-items: center; gap: 10px; }
.lora-in { width: 40px; height: 40px; border-radius: 50%; display: grid; place-items: center; font-size: 16px; font-weight: 700;
  background: var(--bg-muted); border: 1px solid var(--border-strong); color: var(--text-2); }
.lora-branches { display: flex; gap: 20px; align-items: center; justify-content: center; flex-wrap: wrap; }
.lora-main { display: flex; flex-direction: column; align-items: center; gap: 3px; padding: 16px 22px; border-radius: 14px;
  border: 2px solid var(--border-strong); background: var(--bg-subtle); position: relative; transition: all .4s; opacity: .75; }
.lora-main b { font-size: 22px; color: var(--text-2); }
.lora-main .lora-lock { position: absolute; top: -10px; right: -8px; font-size: 15px; }
.lora-dim { font-size: 11px; color: var(--text-4); font-family: "Source Code Pro", monospace; }
.lora-main.act { opacity: 1; border-color: var(--text-3); box-shadow: 0 4px 14px rgba(0,0,0,.08); }
.lora-side { display: flex; align-items: center; gap: 8px; padding: 12px 16px; border-radius: 14px;
  border: 2px dashed var(--accent); background: var(--accent-soft); position: relative; transition: all .4s; }
.lora-side .lora-b, .lora-side .lora-a { display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 8px 12px;
  border-radius: 9px; background: #fff; border: 1px solid #c7d0fb; }
.lora-side b { font-size: 17px; color: var(--accent-dark); }
.lora-side span { font-size: 10px; color: var(--text-4); font-family: "Source Code Pro", monospace; }
.lora-x { color: var(--accent-dark); font-size: 15px; }
.lora-r { position: absolute; bottom: -19px; left: 0; right: 0; text-align: center; font-style: normal; font-size: 10.5px; color: var(--accent-dark); }
.lora-side.act { box-shadow: 0 6px 18px rgba(107,127,243,.24); transform: translateY(-3px); border-style: solid; }
.lora-sum { font-size: 13px; color: var(--text-3); padding: 5px 14px; border-radius: 999px; border: 1px solid var(--border); transition: all .4s; }
.lora-sum.act { border-color: var(--hf-orange); background: #fff6f1; color: var(--hf-orange); font-weight: 700; }
.lora-out { font-size: 14px; font-family: "Source Code Pro", monospace; color: var(--text-2); padding: 8px 16px;
  border-radius: 10px; background: var(--bg-subtle); border: 1px solid var(--border); transition: all .4s; }
.lora-out.act { border-color: var(--green); background: var(--green-soft); color: #166534; font-weight: 700; }

/* ==========================================================================
   rewardmodel · 奖励模型(l6-2)
   ========================================================================== */
.rm-prompt { font-size: 13.5px; color: var(--text-2); margin-bottom: 12px; padding: 8px 12px; background: var(--bg-subtle); border-radius: 9px; border: 1px solid var(--border); }
.rm-resps { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.rm-resp { padding: 12px 14px; border-radius: 12px; border: 1px solid var(--border); background: var(--bg-subtle); transition: all .4s; opacity: .72; }
.rm-resp p { font-size: 12.5px; color: var(--text-2); margin: 8px 0 10px; line-height: 1.5; }
.rm-tag { font-size: 12px; font-weight: 600; }
.rm-chosen, .rm-resp.chosen .rm-tag { color: #166534; }
.rm-resp.chosen.act { opacity: 1; border-color: var(--green); background: var(--green-soft); box-shadow: 0 4px 14px rgba(22,163,74,.15); transform: translateY(-3px); }
.rm-resp.rejected .rm-tag { color: #b91c1c; }
.rm-resp.rejected.act { opacity: 1; border-color: var(--red); background: var(--red-soft); box-shadow: 0 4px 14px rgba(239,68,68,.13); transform: translateY(-3px); }
.rm-score { display: flex; align-items: center; gap: 8px; }
.rm-bar { flex: 1; height: 10px; border-radius: 5px; background: rgba(0,0,0,.06); overflow: hidden; }
.rm-bar i { display: block; height: 100%; width: 0; border-radius: 5px; transition: width .7s cubic-bezier(.4,0,.2,1); }
.rm-resp.chosen .rm-bar i { background: var(--green); }
.rm-resp.rejected .rm-bar i { background: var(--red); }
.rm-resp.act .rm-bar i { width: var(--h); }
.rm-score b { font-size: 15px; font-variant-numeric: tabular-nums; }
.rm-goal { margin-top: 12px; text-align: center; font-size: 12.5px; color: var(--text-4); padding: 8px; border-radius: 9px; border: 1px dashed var(--border-strong); transition: all .4s; }
.rm-goal.act { border-style: solid; border-color: var(--accent); background: var(--accent-soft); color: var(--accent-dark); font-weight: 600; }
@media (max-width: 620px) { .rm-resps { grid-template-columns: 1fr; } }

/* ==========================================================================
   sampling · 采样策略(l7-3)
   ========================================================================== */
.sp-mode { font-size: 13.5px; color: var(--text-2); margin-bottom: 14px; }
.sp-name { color: var(--accent-dark); background: var(--accent-soft); padding: 2px 10px; border-radius: 7px; font-size: 14px; }
.sp-dist { display: flex; gap: 8px; align-items: flex-end; justify-content: space-between; }
.sp-cand { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 5px; max-width: 54px; transition: opacity .4s, filter .4s; }
.sp-bar { width: 100%; height: 96px; background: var(--bg-muted); border-radius: 8px; display: flex; align-items: flex-end; overflow: hidden; }
.sp-bar span { display: block; width: 100%; height: var(--h); border-radius: 8px 8px 0 0; background: linear-gradient(180deg, #c7d0fb, var(--accent)); transition: background .4s; }
.sp-p { font-size: 11px; color: var(--text-3); font-variant-numeric: tabular-nums; }
.sp-t { font-size: 14px; color: var(--text-1); padding: 3px 9px; border-radius: 7px; border: 1px solid var(--border); background: var(--bg); }
.sp-cand.keep .sp-bar span { background: linear-gradient(180deg, var(--hf-yellow), var(--hf-orange)); }
.sp-cand.keep .sp-t { border-color: var(--hf-yellow-dark); background: #fffdf3; font-weight: 700; }
.sp-cand.drop { opacity: .3; filter: grayscale(.7); }
.sp-cand.drop .sp-t { text-decoration: line-through; }

/* ==========================================================================
   kvcache · KV Cache(l7-4)
   ========================================================================== */
.kv-wrap { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.kv-title { font-size: 12.5px; color: var(--text-2); margin-bottom: 10px; font-weight: 600; }
.kv-grid { display: flex; flex-direction: column; gap: 4px; }
.kv-row { display: flex; gap: 4px; }
.kv-cell { width: 26px; height: 22px; border-radius: 5px; background: var(--bg-muted); border: 1px solid var(--border); transition: all .3s; }
.kv-cell.idle { background: #eef0f4; opacity: .5; }
.kv-cell.compute { background: linear-gradient(180deg, var(--hf-yellow), var(--hf-orange)); border-color: var(--hf-orange); box-shadow: 0 0 0 2px rgba(255,107,53,.2); }
.kv-cell.cached { background: var(--green-soft); border-color: #b7e4c7; }
.kv-cell.cached::after { content: "✓"; display: grid; place-items: center; height: 100%; font-size: 11px; color: var(--green); }
.kv-cost { margin-top: 10px; font-size: 11.5px; color: var(--text-3); font-family: "Source Code Pro", monospace; }
@media (max-width: 620px) { .kv-wrap { grid-template-columns: 1fr; } .kv-cell { width: 20px; } }

/* ==========================================================================
   quant · 量化(l7-5)
   ========================================================================== */
.qt-modes { display: flex; gap: 8px; margin-bottom: 16px; }
.qt-mode { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 10px; border-radius: 11px;
  border: 1px solid var(--border); background: var(--bg-subtle); transition: all .35s; opacity: .6; }
.qt-mode b { font-size: 14px; color: var(--text-1); }
.qt-mode span { font-size: 10.5px; color: var(--text-3); text-align: center; }
.qt-mode.act { opacity: 1; transform: translateY(-3px); }
.qt-mode.fp16.act { border-color: var(--accent); background: var(--accent-soft); box-shadow: 0 4px 12px rgba(107,127,243,.15); }
.qt-mode.int8.act { border-color: var(--hf-yellow-dark); background: #fffdf3; box-shadow: 0 4px 12px rgba(255,157,11,.15); }
.qt-mode.int4.act { border-color: var(--green); background: var(--green-soft); box-shadow: 0 4px 12px rgba(22,163,74,.15); }
.qt-mem { display: flex; align-items: center; gap: 10px; margin-bottom: 16px; }
.qt-mem-label { font-size: 12px; color: var(--text-3); flex-shrink: 0; }
.qt-mem-bar { flex: 1; height: 20px; border-radius: 7px; background: var(--bg-muted); overflow: hidden; border: 1px solid var(--border); }
.qt-mem-bar i { display: block; height: 100%; border-radius: 7px; transition: width .6s cubic-bezier(.4,0,.2,1), background .4s; background: var(--accent); }
.qt-mem-bar i.int8 { background: linear-gradient(90deg, var(--hf-yellow), var(--hf-yellow-dark)); }
.qt-mem-bar i.int4 { background: linear-gradient(90deg, #86efac, var(--green)); }
.qt-mem-val { font-size: 15px; font-weight: 700; color: var(--text-1); width: 48px; text-align: right; font-variant-numeric: tabular-nums; }
.qt-blocks { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; min-height: 40px; }
.qt-block { border-radius: 5px; transition: all .4s; animation: tokPop .35s cubic-bezier(.34,1.56,.64,1) backwards; }
.qt-block.fp16 { background: linear-gradient(135deg, #c7d0fb, var(--accent)); }
.qt-block.int8 { background: linear-gradient(135deg, #ffe08a, var(--hf-yellow-dark)); }
.qt-block.int4 { background: linear-gradient(135deg, #86efac, var(--green)); }
.qt-note { font-size: 11.5px; color: var(--text-3); font-style: normal; margin-left: 4px; }

/* ---------- 降低动效偏好 ---------- */
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
  .tok.pop, .dec-tok.new, .tf-layer.pulse .tf-dot, .nt-tok.pred.solved, .qt-block { animation: none; }
  .curve, .pe-run .pe-wave, .of-chart.run .of-stop, .of-chart.run .of-stoplabel { animation: none; }
  .curve { stroke-dashoffset: 0; }
  .of-stop, .of-stoplabel { opacity: .9; }
  .pipe-stage, .tf-layer, .ag-node, .rag-node, .emb-dot, .attn-bar span,
  .gf-node, .vs-col, .al-pillar, .mh-head, .ffn-node, .ln-bar i, .nt-bar span,
  .ce-fill span, .lora-side, .rm-bar i, .sp-cand, .kv-cell, .qt-mem-bar i { transition-duration: .01ms; }
}
