:root {
  --bg-0: #06060f;
  --bg-1: #0d0e22;
  --ink: #f3f4ff;
  --ink-dim: #b6b9d8;
  --ink-faint: #6a6e94;
  --line: rgba(255,255,255,0.10);
  --line-strong: rgba(255,255,255,0.55);
  --c-l0: #ff9b5a;
  --c-l1: #ffd166;
  --c-l2: #9ce37d;
  --c-l3: #5be3d4;
  --c-l4: #6aa9ff;
  --c-l5: #b07bff;
  --c-l6: #ff7bd1;
  --c-l7: #ff5d6c;
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; height: 100%; overflow: hidden; }
body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
    "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
  background:
    radial-gradient(1200px 800px at 30% 10%, #1b1d4a 0%, transparent 60%),
    radial-gradient(900px 700px at 80% 90%, #2a1244 0%, transparent 55%),
    linear-gradient(180deg, var(--bg-0), var(--bg-1));
  color: var(--ink);
  user-select: none;
  -webkit-user-select: none;
}

/* 星空背景 */
.stars { position: fixed; inset: 0; z-index: 0; pointer-events: none; opacity: .55; }
.particles { position: fixed; inset: 0; z-index: 2; pointer-events: none; }

/* 顶栏 */
.topbar {
  position: fixed; top: 0; left: 0; right: 0; z-index: 30;
  display: flex; align-items: center; gap: 16px; padding: 14px 22px;
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  background: linear-gradient(180deg, rgba(8,8,18,.8), rgba(8,8,18,.25));
  border-bottom: 1px solid rgba(255,255,255,.06);
}
.brand {
  display: flex; align-items: center; gap: 12px; min-width: 0;
}
.brand-mark {
  width: 38px; height: 38px; border-radius: 12px;
  background: conic-gradient(from 210deg,
    var(--c-l0), var(--c-l1), var(--c-l2), var(--c-l3),
    var(--c-l4), var(--c-l5), var(--c-l6), var(--c-l7), var(--c-l0));
  display: grid; place-items: center;
  color: #100c20; font-weight: 800; font-size: 18px;
  box-shadow: 0 6px 22px rgba(123,107,255,.45), inset 0 0 0 2px rgba(255,255,255,.18);
}
.brand-title { font-size: 16px; font-weight: 700; letter-spacing: .02em; }
.brand-sub { font-size: 11px; color: var(--ink-faint); margin-top: 2px; letter-spacing: .04em; }

.top-spacer { flex: 1; }

.search {
  position: relative; display: flex; align-items: center;
  background: rgba(255,255,255,.05); border: 1px solid rgba(255,255,255,.08);
  border-radius: 10px; padding: 6px 10px; min-width: 240px;
  transition: border-color .2s, background .2s;
}
.search:focus-within { border-color: rgba(180,170,255,.55); background: rgba(255,255,255,.08); }
.search input {
  background: transparent; border: 0; outline: 0; color: var(--ink);
  font: inherit; font-size: 13px; width: 100%;
}
.search input::placeholder { color: var(--ink-faint); }
.search .icn { color: var(--ink-faint); margin-right: 6px; font-size: 14px; }

.btn {
  background: rgba(255,255,255,.05); border: 1px solid rgba(255,255,255,.08);
  color: var(--ink); padding: 7px 12px; border-radius: 10px;
  font: inherit; font-size: 12px; cursor: pointer;
  transition: background .15s, transform .15s;
}
.btn:hover { background: rgba(255,255,255,.1); }
.btn:active { transform: scale(.97); }

.hint { font-size: 11px; color: var(--ink-faint); }

/* 图例 */
.legend {
  position: fixed; left: 18px; bottom: 18px; z-index: 20;
  background: rgba(10,10,22,.55); border: 1px solid rgba(255,255,255,.07);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  border-radius: 14px; padding: 12px 14px; max-width: 280px;
}
.legend h3 { font-size: 12px; margin: 0 0 8px; color: var(--ink-dim); font-weight: 600; letter-spacing: .08em; }
.legend-row { display: flex; align-items: center; gap: 8px; font-size: 12px; padding: 3px 0; cursor: pointer; }
.legend-row .dot { width: 10px; height: 10px; border-radius: 50%; box-shadow: 0 0 8px currentColor; }
.legend-row .name { flex: 1; }
.legend-row .count { color: var(--ink-faint); font-variant-numeric: tabular-nums; }
.legend-row.muted { opacity: .35; }
.legend-divider { height: 1px; background: rgba(255,255,255,.07); margin: 8px 0; }
.legend-types { display: flex; gap: 10px; font-size: 11px; color: var(--ink-dim); }
.legend-type { display: inline-flex; align-items: center; gap: 5px; }
.lt-mark {
  width: 10px; height: 10px; border-radius: 50%;
  background: #f3f4ff;
}
.lt-mark.ext { background: transparent; border: 1.5px solid #f3f4ff; }
.lt-mark.fro { background: transparent; border: 1.5px dashed #f3f4ff; box-shadow: 0 0 8px #f3f4ff; }

/* 提示气泡 */
.tooltip {
  position: fixed; z-index: 40; pointer-events: none;
  background: rgba(10,10,22,.92); border: 1px solid rgba(255,255,255,.10);
  backdrop-filter: blur(8px);
  color: var(--ink); padding: 8px 12px; border-radius: 10px;
  font-size: 12px; max-width: 260px;
  transform: translate(-50%, calc(-100% - 12px));
  opacity: 0; transition: opacity .12s;
  box-shadow: 0 12px 30px rgba(0,0,0,.45);
}
.tooltip.show { opacity: 1; }
.tooltip .tt-name { font-weight: 600; font-size: 13px; }
.tooltip .tt-meta { color: var(--ink-faint); margin-top: 4px; font-size: 11px; }

/* 详情侧栏 */
.panel {
  position: fixed; top: 70px; bottom: 18px; right: 18px; width: 380px; max-width: calc(100vw - 36px);
  background: rgba(10,10,22,.92);
  border: 1px solid rgba(255,255,255,.08);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  border-radius: 18px; padding: 22px; z-index: 25;
  transform: translateX(calc(100% + 28px)); opacity: 0;
  transition: transform .35s cubic-bezier(.2,.8,.2,1), opacity .35s;
  overflow-y: auto;
  box-shadow: 0 30px 80px rgba(0,0,0,.5);
}
.panel.open { transform: translateX(0); opacity: 1; }
.panel-close {
  position: absolute; top: 14px; right: 14px;
  width: 28px; height: 28px; border-radius: 50%;
  background: rgba(255,255,255,.06); border: 0; color: var(--ink);
  cursor: pointer; font-size: 16px; line-height: 1;
}
.panel-close:hover { background: rgba(255,255,255,.12); }
.panel-stage {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11px; padding: 3px 9px; border-radius: 999px;
  background: rgba(255,255,255,.06); color: var(--ink-dim);
}
.panel-stage .dot { width: 8px; height: 8px; border-radius: 50%; box-shadow: 0 0 6px currentColor; }
.panel h2 { font-size: 22px; margin: 12px 0 6px; line-height: 1.25; font-weight: 700; }
.panel .panel-id { font-size: 12px; color: var(--ink-faint); font-family: ui-monospace, "SF Mono", Menlo, monospace; }
.panel .row { display: flex; gap: 10px; margin-top: 14px; font-size: 13px; align-items: flex-start; }
.panel .row .k { width: 78px; flex-shrink: 0; color: var(--ink-faint); }
.panel .row .v { color: var(--ink); }
.panel .desc { font-size: 13px; line-height: 1.6; color: var(--ink-dim); margin-top: 14px; }
.panel .pill {
  display: inline-block; font-size: 11px; padding: 3px 9px;
  border-radius: 999px; background: rgba(255,255,255,.06);
  color: var(--ink-dim); margin-right: 6px;
}
.panel .pill.core { background: rgba(255,255,255,.95); color: #100c20; }
.panel .pill.extension { background: transparent; border: 1px solid rgba(255,255,255,.6); color: var(--ink); }
.panel .pill.frontier {
  background: linear-gradient(90deg, var(--c-l5), var(--c-l7));
  color: #fff; box-shadow: 0 0 12px rgba(176,123,255,.5);
}
.panel .related { margin-top: 16px; }
.panel .related h4 { font-size: 12px; color: var(--ink-faint); margin: 0 0 8px; font-weight: 500; letter-spacing: .06em; }
.related-item {
  display: block; padding: 8px 10px; border-radius: 8px;
  font-size: 12px; color: var(--ink-dim); cursor: pointer;
  background: rgba(255,255,255,.03); margin-bottom: 4px;
  transition: background .15s, color .15s;
  border: 1px solid transparent;
}
.related-item:hover { background: rgba(255,255,255,.07); color: var(--ink); border-color: rgba(255,255,255,.08); }

/* 主 SVG */
#graph {
  position: fixed; inset: 0;
  cursor: grab;
  z-index: 1;
}
#graph.dragging { cursor: grabbing; }
.nodes circle { transition: stroke-width .2s, filter .2s; }
.node { cursor: pointer; }
.node text {
  pointer-events: none;
  font-size: 11px;
  fill: var(--ink-dim);
  paint-order: stroke;
  stroke: rgba(8,8,20,.75); stroke-width: 3px;
  transition: opacity .2s, fill .2s;
}
.node.stage text { font-size: 14px; font-weight: 700; fill: var(--ink); }
.node.group text { font-size: 12px; font-weight: 600; fill: var(--ink); }
.links path { fill: none; transition: stroke-opacity .2s, stroke-width .2s; }

/* 高亮态 */
.dimmed .node:not(.hl) { opacity: .12; }
.dimmed .links path:not(.hl) { opacity: .04; }
.node.hl text { fill: #fff; opacity: 1 !important; }
.node.selected circle { stroke: #fff; stroke-width: 2; filter: drop-shadow(0 0 10px currentColor); }

/* 中心节点呼吸 */
@keyframes coreBreathe {
  0%, 100% { transform: scale(1); filter: drop-shadow(0 0 18px rgba(180,170,255,.6)); }
  50% { transform: scale(1.06); filter: drop-shadow(0 0 28px rgba(180,170,255,.95)); }
}
.node.core-root > * { transform-origin: center; transform-box: fill-box; animation: coreBreathe 4s ease-in-out infinite; }

/* 入场 */
.node, .links path, .prereq-links path { opacity: 0; }
.node.in, .links path.in, .prereq-links path.in { opacity: 1; transition: opacity .8s ease-out; }

/* 跨阶段先修虚线 */
.prereq-links path {
  fill: none; stroke-width: 1; stroke-dasharray: 4 5;
  stroke-opacity: 0; pointer-events: none;
  transition: stroke-opacity .25s, stroke-width .25s;
}
.prereq-links path.in { stroke-opacity: .14; }
.prereq-links.show path.in { stroke-opacity: .42; }
.prereq-links path.hl { stroke-opacity: .9 !important; stroke-width: 2.4; }

/* 流光粒子（在主连线上移动） */
.flow circle { pointer-events: none; }

/* 路径模式 */
.path-mode-bar {
  position: fixed; top: 70px; left: 50%; transform: translateX(-50%);
  z-index: 22; display: none;
  background: rgba(10,10,22,.85); backdrop-filter: blur(14px);
  border: 1px solid rgba(255,255,255,.10);
  border-radius: 14px; padding: 10px 14px;
  box-shadow: 0 16px 40px rgba(0,0,0,.45);
  align-items: center; gap: 10px; font-size: 12px;
  cursor: grab;
  touch-action: none;
}
.path-mode-bar.show { display: flex; }
.path-mode-bar.dragging { cursor: grabbing; }
.path-mode-bar::before {
  content: "⋮⋮";
  color: rgba(243,244,255,.42);
  font-weight: 800;
  letter-spacing: -2px;
}
.path-mode-bar button,
.path-mode-bar .path-chip {
  cursor: pointer;
}
.path-chip {
  display: inline-flex; align-items: center; gap: 6px;
  background: rgba(255,255,255,.05); padding: 5px 10px; border-radius: 999px;
  border: 1px dashed rgba(255,255,255,.18);
  color: var(--ink-dim); min-width: 100px; justify-content: center;
}
.path-chip.set { color: var(--ink); border-style: solid; border-color: rgba(180,170,255,.55); background: rgba(180,170,255,.12); }
.path-chip .x { margin-left: 6px; cursor: pointer; opacity: .6; }
.path-chip .x:hover { opacity: 1; }
.path-arrow { color: var(--ink-faint); }
.path-info { color: var(--ink-faint); font-size: 11px; }

/* 选点模式光标 */
body.picking #graph .node { cursor: crosshair; }
body.picking #graph .node.topic:hover circle { stroke: #fff; stroke-width: 2; }

/* 路径高亮 */
.path-layer path { fill: none; stroke: #fff; stroke-width: 2.6; opacity: 0; transition: opacity .35s; }
.path-layer path.show { opacity: .9; filter: drop-shadow(0 0 8px rgba(255,255,255,.7)); }
.path-layer .path-pulse { fill: #fff; opacity: .9; filter: drop-shadow(0 0 10px #fff); }

.node.path-step circle { stroke: #fff; stroke-width: 2.5; filter: drop-shadow(0 0 10px currentColor); }
.node.path-step text { fill: #fff !important; opacity: 1 !important; }
.node.path-endpoint circle { stroke: #fff; stroke-width: 3; r: 10; }

/* LOD：基于 svg 上的 zoom-level class，按类型分层显示标签 */
.node.topic text { transition: opacity .25s; }
/* 默认（中等缩放）：core 显示，extension/frontier 隐藏 */
.node.topic.type-core text { opacity: .9; font-size: 10.5px; }
.node.topic.type-extension text,
.node.topic.type-frontier text { opacity: 0; }
/* 近：所有 topic 标签显示 */
#graph.zoom-near .node.topic text { opacity: 1 !important; }
/* 远：topic 全隐藏，group 也淡化 */
#graph.zoom-far .node.topic text { opacity: 0 !important; }
#graph.zoom-far .node.group text { opacity: .35; }

/* 地图模式：标签密度大幅降低（必须放在 zoom 规则之后才能胜过 cascading） */
#graph.layout-map .node.topic text,
#graph.layout-map.zoom-near .node.topic text,
#graph.layout-map.zoom-mid .node.topic text,
#graph.layout-map.zoom-far .node.topic text { opacity: 0 !important; }
#graph.layout-map.zoom-near .node.topic.type-core text { opacity: .8 !important; }
#graph.layout-map .node.group text { opacity: .6; font-size: 10px; }
#graph.layout-map .node.stage text { font-size: 13px; }

/* 已掌握 / 收藏（预留） */
.node.done circle { filter: drop-shadow(0 0 8px gold); }

/* 跳转按钮 */
.panel-jump {
  display: inline-flex; align-items: center; gap: 6px;
  margin-top: 16px; padding: 9px 14px;
  background: linear-gradient(135deg, rgba(180,170,255,.25), rgba(120,180,255,.2));
  border: 1px solid rgba(180,170,255,.45);
  border-radius: 10px; color: var(--ink); cursor: pointer;
  font: inherit; font-size: 12px; text-decoration: none;
  transition: transform .15s, background .2s;
}
.panel-jump:hover { background: linear-gradient(135deg, rgba(180,170,255,.4), rgba(120,180,255,.35)); transform: translateY(-1px); }
.panel-jump .arrow { font-size: 14px; }

/* 顶栏按钮激活态 */
.btn.active { background: linear-gradient(135deg, rgba(180,170,255,.35), rgba(120,180,255,.3)); border-color: rgba(180,170,255,.6); }

/* === 3D 立体星图 === */
body { perspective: 2000px; perspective-origin: 50% 50%; }
#graph {
  transform-origin: 50% 50%;
  will-change: transform;
  transition: transform 60ms linear;
}

/* === 虫洞模式 === */
body.wormhole #graph .node { transition: transform .9s cubic-bezier(.7,0,.3,1), opacity .9s; }
body.wormhole #graph .links,
body.wormhole #graph .prereq-links,
body.wormhole #graph .flow { opacity: 0; transition: opacity .4s; pointer-events: none; }
body.wormhole #graph .node.wh-far { opacity: 0; }
body.wormhole #graph .node.wh-center circle { transition: r .9s, stroke-width .3s; }

.wormhole-hint {
  position: fixed; bottom: 70px; left: 50%; transform: translateX(-50%);
  background: rgba(10,10,22,.82); backdrop-filter: blur(10px);
  border: 1px solid rgba(255,255,255,.10); border-radius: 999px;
  padding: 8px 16px; font-size: 12px; color: var(--ink-dim);
  z-index: 25; opacity: 0; transition: opacity .3s; pointer-events: none;
}
.wormhole-hint.show { opacity: 1; }
.wormhole-hint kbd { background: rgba(255,255,255,.10); padding: 2px 6px; border-radius: 4px; font-size: 11px; color: var(--ink); margin: 0 2px; }

/* 虫洞涟漪 */
.wormhole-ripple {
  position: fixed; left: 50%; top: 50%; transform: translate(-50%,-50%);
  width: 50px; height: 50px; border-radius: 50%;
  border: 2px solid rgba(180,170,255,.7);
  z-index: 22; pointer-events: none;
  animation: rippleOut 1.1s cubic-bezier(.2,.6,.3,1) forwards;
}
@keyframes rippleOut {
  0% { width: 30px; height: 30px; opacity: 1; border-width: 2px; }
  100% { width: 1600px; height: 1600px; opacity: 0; border-width: 0.5px; }
}

/* === 公式悬浮 (KaTeX) === */
.tt-formula {
  margin-top: 8px; padding-top: 8px;
  border-top: 1px solid rgba(255,255,255,.08);
  color: #fff; font-size: 14px;
  overflow-x: auto; max-width: 100%;
}
.tt-formula .katex { font-size: 1.05em; }
.tt-formula.fallback {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 11px; color: var(--ink-dim);
}
.tooltip { transition: opacity .12s, transform .15s; max-width: 320px; }
.tooltip.show { transform: translate(-50%, calc(-100% - 12px)) scale(1); }

/* === 公式挑战 === */
.challenge-panel {
  position: fixed; left: 50%; top: 80px; transform: translateX(-50%) translateY(-30px);
  width: 520px; max-width: calc(100vw - 36px);
  background: rgba(10,10,22,.95); backdrop-filter: blur(16px);
  border: 1px solid rgba(255,209,102,.35); border-radius: 14px;
  padding: 16px 20px; z-index: 30;
  opacity: 0; pointer-events: none;
  transition: opacity .3s, transform .3s cubic-bezier(.2,.7,.2,1);
  box-shadow: 0 30px 80px rgba(0,0,0,.55), 0 0 30px rgba(255,209,102,.2);
}
.challenge-panel.show { opacity: 1; pointer-events: auto; transform: translateX(-50%) translateY(0); }
.challenge-head {
  display: flex; justify-content: space-between; align-items: center;
  margin-bottom: 8px; font-size: 11px; color: var(--ink-faint); letter-spacing: .08em;
}
.challenge-head .ch-score strong { color: #ffd166; font-size: 14px; font-variant-numeric: tabular-nums; }
.challenge-head .ch-time strong { color: #ff5d6c; font-size: 14px; font-variant-numeric: tabular-nums; }
.challenge-formula {
  text-align: center; padding: 14px;
  background: rgba(255,255,255,.04); border-radius: 8px;
  margin-bottom: 6px; min-height: 50px;
  color: #fff; font-size: 18px;
}
.challenge-prompt {
  font-size: 12px; color: var(--ink-dim); text-align: center;
  margin-bottom: 10px;
}
.challenge-controls { display: flex; justify-content: center; gap: 8px; }
.challenge-controls .btn { padding: 6px 14px; font-size: 12px; }
.challenge-result {
  margin-top: 10px; padding: 10px; border-radius: 8px;
  text-align: center; font-size: 13px;
  background: rgba(255,255,255,.05);
}
.challenge-result.correct { color: #5be3d4; background: rgba(91,227,212,.12); }
.challenge-result.wrong { color: #ff5d6c; background: rgba(255,93,108,.12); }
.challenge-leaderboard {
  margin-top: 10px; padding-top: 10px;
  border-top: 1px solid rgba(255,255,255,.08);
  font-size: 11px; color: var(--ink-dim);
}
.challenge-leaderboard h4 { font-size: 10px; color: var(--ink-faint); margin: 0 0 6px; letter-spacing: .08em; }
.lb-row { display: flex; justify-content: space-between; padding: 2px 0; }
.lb-rank { color: #ffd166; font-weight: 700; min-width: 22px; }

/* === 世界地图（地理布局） === */
.world-map {
  transition: opacity .8s;
  pointer-events: none;
}
.world-map path {
  fill: rgba(180,170,255,.05);
  stroke: rgba(180,170,255,.3);
  stroke-width: 1;
  stroke-dasharray: 2 3;
}
.world-map.show { opacity: 1 !important; }

/* === 黑洞 === */
.black-hole { cursor: pointer; transform-origin: center; transform-box: fill-box; }
.black-hole .bh-accretion { animation: accretionSpin 18s linear infinite; transform-origin: center; transform-box: fill-box; }
.black-hole .bh-disk { transition: r .3s; }
.black-hole .bh-event { transition: r .3s; }
.black-hole .bh-label { fill: rgba(255,255,255,.45); font-size: 11px; letter-spacing: .15em; }
.black-hole:hover .bh-disk { r: 42; }
.black-hole:hover .bh-event { r: 28; filter: drop-shadow(0 0 12px #9c00ff); }
.black-hole:hover .bh-label { fill: #fff; }
@keyframes accretionSpin { to { transform: rotate(360deg); } }

/* === 数学家照片墙 === */
.portrait-wall {
  position: fixed; right: 18px; top: 80px; z-index: 22;
  width: 260px; max-height: calc(100vh - 110px); overflow: hidden;
  background: rgba(10,10,22,.86); backdrop-filter: blur(14px);
  border: 1px solid rgba(255,255,255,.08); border-radius: 14px;
  padding: 12px; opacity: 0; transform: translateX(20px);
  transition: opacity .4s, transform .4s; pointer-events: none;
}
.portrait-wall.show { opacity: 1; transform: translateX(0); pointer-events: auto; }
.portrait-wall h4 {
  margin: 0 0 8px; font-size: 11px; color: var(--ink-faint);
  letter-spacing: .08em; font-weight: 500; padding: 0 4px;
}
.portrait-wall h4 .pw-count { color: #ffd166; font-weight: 700; }
.portrait-grid {
  position: relative;
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px;
  padding: 4px;
}
.portrait {
  position: relative; aspect-ratio: 1;
  background: linear-gradient(135deg, rgba(255,209,102,.12), rgba(180,170,255,.08));
  border: 1px solid rgba(255,209,102,.3);
  border-radius: 50%; cursor: pointer;
  display: grid; place-items: center;
  transition: transform .25s, box-shadow .25s, border-color .25s;
  overflow: hidden;
}
.portrait:hover {
  transform: scale(1.15); border-color: #ffd166;
  box-shadow: 0 0 14px rgba(255,209,102,.6);
  z-index: 5;
}
.portrait .p-emoji { font-size: 22px; }
.portrait .p-tooltip {
  position: absolute; bottom: -28px; left: 50%; transform: translateX(-50%);
  font-size: 10px; white-space: nowrap; color: #fff;
  background: rgba(0,0,0,.85); padding: 3px 6px; border-radius: 4px;
  opacity: 0; transition: opacity .15s; pointer-events: none; z-index: 10;
}
.portrait:hover .p-tooltip { opacity: 1; }
.portrait.young { border-color: #5be3d4; }
.portrait.elder { border-color: #ff7bd1; opacity: .75; }
.portrait.dying { animation: portraitDying 1.2s ease-out; }
@keyframes portraitDying {
  0% { opacity: 1; }
  100% { opacity: 0; transform: scale(.6); }
}
.portrait.born { animation: portraitBorn 1s cubic-bezier(.2,.8,.2,1); }
@keyframes portraitBorn {
  0% { opacity: 0; transform: scale(.2); }
  60% { opacity: 1; transform: scale(1.3); }
  100% { transform: scale(1); }
}
.lineage-svg {
  position: absolute; inset: 0; pointer-events: none; z-index: 1;
}
.lineage-svg line {
  stroke: rgba(255,209,102,.4); stroke-width: 1.5;
  stroke-dasharray: 3 3;
  opacity: 0; animation: lineageIn .6s ease-out forwards;
}
@keyframes lineageIn { to { opacity: 1; } }

/* === 节点引力波 / 思维链 === */
.ripple-layer circle {
  fill: none; stroke: #fff; pointer-events: none;
  animation: rippleOut 1.4s cubic-bezier(.2,.7,.3,1) forwards;
}
@keyframes rippleOut {
  0% { stroke-opacity: .9; stroke-width: 3; r: 4; }
  100% { stroke-opacity: 0; stroke-width: 0.5; r: 380; }
}
.node.chain-pulse circle {
  animation: chainPulse .9s cubic-bezier(.4,.0,.2,1);
}
@keyframes chainPulse {
  0% { transform: scale(1); filter: drop-shadow(0 0 0 currentColor); }
  40% { transform: scale(1.7); filter: drop-shadow(0 0 14px currentColor); }
  100% { transform: scale(1); filter: drop-shadow(0 0 0 currentColor); }
}
.node.chain-pulse circle { transform-origin: center; transform-box: fill-box; }

/* === 数学之旅 === */
.story-panel {
  position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%) translateY(50px);
  width: 640px; max-width: calc(100vw - 36px);
  background: rgba(10,10,22,.92); backdrop-filter: blur(16px);
  border: 1px solid rgba(255,255,255,.10); border-radius: 16px;
  padding: 16px 20px 18px; z-index: 28;
  opacity: 0; pointer-events: none;
  transition: opacity .5s, transform .5s cubic-bezier(.2,.7,.2,1);
  box-shadow: 0 30px 80px rgba(0,0,0,.55);
}
.story-panel.show { opacity: 1; pointer-events: auto; transform: translateX(-50%) translateY(0); }
.story-progress-bar {
  height: 2px; background: rgba(255,255,255,.08); border-radius: 2px;
  overflow: hidden; margin: -8px -10px 10px;
}
.story-progress-bar > div {
  height: 100%; width: 0;
  background: linear-gradient(90deg, #ff9b5a, #ffd166, #5be3d4, #b07bff);
  transition: width .8s cubic-bezier(.2,.8,.2,1);
}
.story-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
.story-station-tag {
  font-size: 11px; color: var(--ink-faint); letter-spacing: .08em;
  text-transform: uppercase;
}
.story-controls { display: flex; gap: 4px; }
.story-btn {
  width: 28px; height: 28px; border-radius: 50%;
  background: rgba(255,255,255,.06); border: 0; color: #fff;
  cursor: pointer; font-size: 14px;
  display: grid; place-items: center;
}
.story-btn:hover { background: rgba(255,255,255,.14); }
.story-btn.close { background: rgba(255,90,90,.15); }
.story-btn.close:hover { background: rgba(255,90,90,.3); }
.story-title {
  margin: 4px 0 8px; font-size: 22px; font-weight: 700;
  background: linear-gradient(90deg, #ffd166, #ff9b5a);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
}
.story-formula {
  margin: 8px 0; padding: 10px 12px;
  background: rgba(255,255,255,.04); border-radius: 8px;
  text-align: center; min-height: 30px;
  color: #fff;
}
.story-formula:empty { display: none; }
.story-text {
  margin: 8px 0 0; font-size: 14px; line-height: 1.7;
  color: var(--ink); min-height: 56px;
}
.story-text::after {
  content: '▌'; color: #ffd166;
  animation: caretBlink .9s steps(2) infinite;
}
.story-text.done::after { display: none; }
@keyframes caretBlink { 50% { opacity: 0; } }

/* === 数学家 === */
.tt-author {
  margin-top: 6px; padding-top: 6px; border-top: 1px solid rgba(255,255,255,.06);
  font-size: 11px; color: var(--ink-dim);
  display: flex; align-items: center; gap: 6px;
}
.tt-author .au-emoji { font-size: 14px; }
.tt-author .au-name { color: #ffd166; font-weight: 600; }

.panel-author {
  margin-top: 14px; padding: 10px 12px;
  background: linear-gradient(135deg, rgba(255,209,102,.08), rgba(255,209,102,.02));
  border: 1px solid rgba(255,209,102,.25); border-radius: 10px;
  display: flex; align-items: center; gap: 10px;
}
.panel-author .au-emoji { font-size: 24px; }
.panel-author .au-name { color: #ffd166; font-weight: 700; font-size: 14px; }
.panel-author .au-life { color: var(--ink-faint); font-size: 11px; }

/* 当代数学家浮窗（时光机播放时） */
.living-mathematicians {
  position: fixed; right: 18px; top: 80px; z-index: 22;
  width: 220px; max-height: 50vh; overflow-y: auto;
  background: rgba(10,10,22,.85); backdrop-filter: blur(12px);
  border: 1px solid rgba(255,255,255,.08); border-radius: 14px;
  padding: 12px 14px; opacity: 0; transform: translateX(20px);
  transition: opacity .4s, transform .4s; pointer-events: none;
}
.living-mathematicians.show { opacity: 1; transform: translateX(0); pointer-events: auto; }
.living-mathematicians h4 {
  margin: 0 0 8px; font-size: 11px; color: var(--ink-faint);
  letter-spacing: .08em; font-weight: 500;
}
.lm-row {
  display: flex; align-items: center; gap: 8px; padding: 5px 0;
  font-size: 12px; cursor: pointer; transition: opacity .2s;
}
.lm-row:hover { color: #ffd166; }
.lm-row .lm-emoji { font-size: 14px; }
.lm-row .lm-name { flex: 1; }
.lm-row .lm-age { font-size: 10px; color: var(--ink-faint); }
.lm-empty { color: var(--ink-faint); font-size: 11px; font-style: italic; }

/* === 布局切换 === */
.layout-switch {
  display: inline-flex; gap: 2px;
  background: rgba(255,255,255,.04); border: 1px solid rgba(255,255,255,.08);
  border-radius: 10px; padding: 3px;
}
.layout-switch button {
  background: transparent; border: 0; color: var(--ink-dim);
  padding: 5px 10px; border-radius: 7px; font: inherit; font-size: 11px;
  cursor: pointer; transition: background .15s, color .15s;
}
.layout-switch button:hover { color: var(--ink); background: rgba(255,255,255,.06); }
.layout-switch button.active {
  background: linear-gradient(135deg, rgba(180,170,255,.35), rgba(120,180,255,.3));
  color: #fff;
}

/* === 宇宙诞生开场 === */
.cosmo-overlay {
  position: fixed; inset: 0; z-index: 90;
  background: radial-gradient(circle at 50% 50%, #0a0a18 0%, #000 70%);
  display: grid; place-items: center; overflow: hidden;
  transition: opacity 1.4s cubic-bezier(.4,0,.7,.4);
}
.cosmo-overlay.gone { opacity: 0; pointer-events: none; }
.cosmo-spark {
  position: absolute; left: 50%; top: 50%;
  width: 6px; height: 6px; border-radius: 50%;
  background: #fff; transform: translate(-50%,-50%) scale(0);
  box-shadow: 0 0 30px 6px rgba(255,255,255,.9);
  animation: sparkBirth 2s cubic-bezier(.2,.6,.2,1) forwards;
}
@keyframes sparkBirth {
  0% { transform: translate(-50%,-50%) scale(0); opacity: 0; }
  8% { transform: translate(-50%,-50%) scale(1); opacity: 1; box-shadow: 0 0 20px 4px #fff; }
  35% { transform: translate(-50%,-50%) scale(2); opacity: 1; box-shadow: 0 0 80px 30px #fff, 0 0 200px 60px rgba(180,170,255,.8); }
  65% { transform: translate(-50%,-50%) scale(1.2); opacity: 1; box-shadow: 0 0 60px 20px rgba(255,255,255,.5), 0 0 300px 120px rgba(180,170,255,.4); }
  100% { transform: translate(-50%,-50%) scale(0.5); opacity: 0; }
}
.cosmo-shockwave {
  position: absolute; left: 50%; top: 50%;
  width: 0; height: 0; border-radius: 50%;
  border: 2px solid rgba(180,170,255,.85);
  transform: translate(-50%,-50%);
  animation: shockwave 2.4s cubic-bezier(.05,.7,.3,1) forwards;
  animation-delay: .4s;
}
@keyframes shockwave {
  0% { width: 10px; height: 10px; border-width: 3px; opacity: 1; }
  100% { width: 200vmax; height: 200vmax; border-width: 0.5px; opacity: 0; }
}
.cosmo-title {
  position: relative; z-index: 1; font-size: 38px; font-weight: 800;
  letter-spacing: .15em; color: #fff; opacity: 0;
  background: linear-gradient(90deg, #ff9b5a, #ffd166, #5be3d4, #b07bff, #ff5d6c);
  background-size: 300% 100%; -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
  text-shadow: 0 0 40px rgba(180,170,255,.4);
  animation: titleIn 1.4s cubic-bezier(.2,.7,.2,1) forwards, titleShine 6s linear infinite;
  animation-delay: 1.6s, 1.6s;
  transform: translateY(20px);
}
.cosmo-sub {
  position: relative; z-index: 1; margin-top: 14px;
  font-size: 12px; letter-spacing: .25em; color: rgba(255,255,255,.55);
  opacity: 0;
  animation: titleIn 1.2s cubic-bezier(.2,.7,.2,1) forwards;
  animation-delay: 2s;
  transform: translateY(20px);
}
@keyframes titleIn { to { opacity: 1; transform: translateY(0); } }
@keyframes titleShine { to { background-position: -300% 50%; } }

/* === 进度系统 === */
.progress-pod {
  display: flex; flex-direction: column; gap: 5px;
  background: rgba(255,255,255,.05); border: 1px solid rgba(255,255,255,.08);
  padding: 7px 11px; border-radius: 10px; min-width: 110px; cursor: pointer;
  transition: background .2s, border-color .2s;
}
.progress-pod:hover { background: rgba(255,255,255,.10); border-color: rgba(255,209,102,.4); }
.progress-pct { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.progress-pct strong { font-size: 14px; color: #ffd166; font-variant-numeric: tabular-nums; }
.progress-pct span { font-size: 10px; color: var(--ink-faint); }
.progress-bar { height: 3px; background: rgba(255,255,255,.08); border-radius: 2px; overflow: hidden; }
.progress-bar > div {
  height: 100%; width: 0;
  background: linear-gradient(90deg, #ffd166, #ff9b5a);
  transition: width .6s cubic-bezier(.2,.8,.2,1);
  box-shadow: 0 0 8px rgba(255,209,102,.6);
}

/* 已掌握节点：金色光晕 */
.node.topic.mastered circle {
  stroke: #ffd166;
  stroke-width: 2.2;
  filter: drop-shadow(0 0 8px rgba(255,209,102,.85));
}
.node.topic.mastered text { fill: #ffd166 !important; }

/* 详情面板的"标记掌握"按钮 */
.panel-mark {
  display: inline-flex; align-items: center; gap: 6px;
  margin-top: 14px; margin-right: 8px;
  padding: 8px 14px;
  background: transparent; border: 1px solid rgba(255,209,102,.55);
  color: #ffd166; border-radius: 10px; cursor: pointer;
  font: inherit; font-size: 12px; transition: background .2s;
}
.panel-mark:hover { background: rgba(255,209,102,.12); }
.panel-mark.done { background: rgba(255,209,102,.2); }

/* 成就 toast */
.toast {
  position: fixed; top: 78px; left: 50%;
  transform: translateX(-50%) translateY(-30px);
  background: rgba(10,10,22,.92); backdrop-filter: blur(14px);
  padding: 14px 24px; border-radius: 14px;
  border: 1px solid rgba(255,209,102,.55);
  font-size: 13px; color: #fff; z-index: 50;
  opacity: 0; transition: all .5s cubic-bezier(.2,.8,.2,1);
  box-shadow: 0 16px 40px rgba(0,0,0,.5), 0 0 30px rgba(255,209,102,.25);
  max-width: 90vw;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.toast .t-title { font-weight: 700; color: #ffd166; }
.toast .t-sub { font-size: 11px; color: var(--ink-dim); margin-top: 4px; }

/* 星座连线 */
.constellation line {
  pointer-events: none;
  transition: opacity .8s;
  stroke-linecap: round;
}
@keyframes constShimmer {
  0%, 100% { stroke-opacity: .85; }
  50% { stroke-opacity: 1; }
}
.constellation line.active { animation: constShimmer 2s ease-in-out infinite; }

/* === 数学时光机 === */
.time-machine {
  position: fixed; left: 50%; bottom: 18px; transform: translateX(-50%);
  z-index: 22; display: none;
  background: rgba(10,10,22,.78); backdrop-filter: blur(14px);
  border: 1px solid rgba(255,255,255,.08); border-radius: 14px;
  padding: 10px 14px; gap: 10px; align-items: center;
  box-shadow: 0 16px 40px rgba(0,0,0,.5);
}
.time-machine.show { display: flex; }
.time-machine .tm-btn {
  width: 32px; height: 32px; border-radius: 50%;
  background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.10);
  color: #fff; cursor: pointer; font-size: 14px;
  display: grid; place-items: center;
}
.time-machine .tm-btn:hover { background: rgba(255,255,255,.12); }
.time-machine input[type=range] {
  width: 360px; accent-color: #ffd166; cursor: pointer;
}
.time-machine .tm-year {
  min-width: 96px; text-align: center; font-variant-numeric: tabular-nums;
  font-weight: 700; font-size: 14px; color: #ffd166;
  text-shadow: 0 0 8px rgba(255,209,102,.4);
}
.time-machine .tm-era { font-size: 10px; color: var(--ink-faint); margin-top: 2px; text-align: center; }

.node.era-future { opacity: 0.04 !important; transition: opacity .5s; }
.node.era-future text { display: none; }
.links path.era-future, .prereq-links path.era-future { opacity: 0.02 !important; }
.node.era-just-born circle { animation: bornFlash 1.2s ease-out; }
@keyframes bornFlash {
  0% { filter: drop-shadow(0 0 0 #fff); transform: scale(0.6); }
  50% { filter: drop-shadow(0 0 16px #fff); transform: scale(1.4); }
  100% { filter: drop-shadow(0 0 0 transparent); transform: scale(1); }
}

/* === 音效按钮的小波纹 === */
.btn.sound-on {
  background: linear-gradient(135deg, rgba(255,180,120,.3), rgba(255,120,180,.25));
  border-color: rgba(255,180,120,.6);
}
@keyframes soundPulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255,180,120,.6); }
  50% { box-shadow: 0 0 0 6px rgba(255,180,120,0); }
}
.btn.sound-on { animation: soundPulse 1.5s ease-in-out infinite; }

/* 缩放控制 */
.zoom-ctrl {
  position: fixed; right: 18px; bottom: 18px; z-index: 20;
  display: flex; flex-direction: column; gap: 6px;
}
.zoom-ctrl .btn { width: 36px; height: 36px; padding: 0; font-size: 16px; }

/* 标题栏中的统计 */
.stats { display: flex; gap: 14px; }
.stat { font-size: 11px; color: var(--ink-faint); }
.stat strong { display: block; color: var(--ink); font-size: 15px; font-variant-numeric: tabular-nums; }

@media (max-width: 720px) {
  .panel { width: calc(100vw - 24px); right: 12px; left: 12px; top: 80px; }
  .legend { display: none; }
  .stats { display: none; }
  .search { min-width: 140px; }
}
