/* ============================================================
   REACTOR · LED + Glass effects (见 course/DESIGN-SYSTEM.md §5)
   点阵 · 发光 · Glyph 灯带 · 通电动画 · 天赋树电路
   ============================================================ */

/* ── Boot line 通电自检行 ── */
.bootline{font-family:var(--font-mono);font-size:.72rem;letter-spacing:.1em;
  color:var(--accent);text-shadow:0 0 6px color-mix(in srgb,var(--accent-glow) 45%,transparent);
  white-space:nowrap;overflow:hidden}
/* 纸白上不要发光文字，糊 */
:root[data-theme="light"] .bootline{text-shadow:none}
.bootline .cursor{display:inline-block;width:.5em;height:1em;vertical-align:-.15em;
  background:currentColor;animation:blink 1s steps(1) infinite}
@keyframes blink{50%{opacity:0}}
.bootline.typing{width:0;animation:type 1.6s steps(38) forwards}
@keyframes type{to{width:100%}}

/* ── LED dot 通用发光点 ── */
.led{width:9px;height:9px;border-radius:50%;background:var(--line-2);display:inline-block}
.led.on{background:var(--accent);box-shadow:0 0 6px var(--accent-glow),0 0 14px var(--accent-glow)}
.led.pulse{box-shadow:0 0 8px var(--accent-glow),0 0 16px var(--accent-glow);
  animation:led-pulse 2.4s ease-in-out infinite}
/* 性能红线：呼吸灯只动 opacity（合成器动画，不触发每帧样式重算/重绘）。
   之前的版本在关键帧里插值 box-shadow，全站每个常亮呼吸灯都在以 60Hz 逼浏览器
   重算样式+重绘——静置页面白烧 15% CPU 的元凶。光晕改为静态阴影，用透明度呼吸。 */
@keyframes led-pulse{0%,100%{opacity:.45}50%{opacity:1}}

/* ── Glyph 灯带 = 品牌标识：两盏白灯 + 红黄蓝绿（三分支 + 汇流）──
   从左到右逐个点亮；灭掉时是中性灯珠，看不出自己是什么颜色。
   每盏灯把自己的颜色存进 --_lamp，共用一条 keyframe（var() 在关键帧里按元素解析）。*/
.glyph-strip{display:flex;gap:5px;align-items:center}
/* 性能红线：追逐灯只动 opacity（合成器）。旧版逐帧插值 background+box-shadow，
   灯带在每个页面的 header 里常驻，等于全站永续 60Hz 样式重算。
   现在灯珠常亮自己的颜色+静态光晕，靠透明度 .22↔1 实现「点亮/熄灭」。 */
.glyph-strip .led{width:6px;height:6px;background:var(--_lamp,var(--line-2));
  box-shadow:0 0 5px var(--_glow);opacity:.22;
  animation:glyph-chase 3.6s steps(1) infinite}
.glyph-strip .led.l-w     {--_lamp:var(--white);         --_glow:color-mix(in srgb,var(--white) 70%,transparent)}
.glyph-strip .led.l-red   {--_lamp:var(--branch-red);    --_glow:var(--red-glow)}
.glyph-strip .led.l-yellow{--_lamp:var(--branch-yellow); --_glow:var(--yellow-glow)}
.glyph-strip .led.l-blue  {--_lamp:var(--branch-blue);   --_glow:var(--blue-glow)}
.glyph-strip .led.l-green {--_lamp:var(--branch-green);  --_glow:var(--green-glow)}
.glyph-strip .led:nth-child(1){animation-delay:0s}
.glyph-strip .led:nth-child(2){animation-delay:.14s}
.glyph-strip .led:nth-child(3){animation-delay:.28s}
.glyph-strip .led:nth-child(4){animation-delay:.42s}
.glyph-strip .led:nth-child(5){animation-delay:.56s}
.glyph-strip .led:nth-child(6){animation-delay:.70s}
@keyframes glyph-chase{
  0%,20%  {opacity:1}
  21%,100%{opacity:.22}}
/* 亮色主题下白灯要改成深色，否则纸白上两盏灯亮起来等于没亮 */
:root[data-theme="light"] .glyph-strip .led.l-w{--_lamp:var(--ink-800);
  --_glow:color-mix(in srgb,var(--ink-800) 45%,transparent)}
/* 关掉动画时（reduced-motion）就常亮，不然灯带全灭看不出是什么 */
@media (prefers-reduced-motion:reduce){
  .glyph-strip .led{opacity:1;box-shadow:0 0 5px var(--_glow)}}

/* ── Progress spine 进度脊（Glyph 灯带竖版）── */
.spine{position:fixed;left:14px;top:50%;transform:translateY(-50%);z-index:40;
  display:flex;flex-direction:column;gap:7px}
.spine .led{width:7px;height:7px}
@media (max-width:960px){.spine{display:none}}

/* ============================================================
   Talent Tree（天赋树本体）
   full = 首页全屏主导航；mini = 课程页左侧导轨
   ============================================================ */
.tree-viewport{position:relative;width:100%;height:min(78vh,760px);
  border:1px solid var(--line);border-radius:var(--radius-panel);overflow:hidden;
  background:var(--bg-2);
  background-image:radial-gradient(var(--dot) 1px,transparent 1.4px);
  background-size:var(--dot-gap) var(--dot-gap);cursor:grab;
  touch-action:pan-y}
.tree-viewport.dragging{cursor:grabbing}
.tree-stage{position:absolute;top:0;left:0;transform-origin:0 0;will-change:transform}
.tree-stage.gliding{transition:transform .45s cubic-bezier(.22,.9,.3,1)}
.tree-svg{position:absolute;top:0;left:0;overflow:visible;pointer-events:none}

/* ── 首页全屏形态:导航条 → 介绍横条 → 树占满剩余(用户裁决:竖栏挤占内容,并入顶部) ── */
.tree-full{position:relative;display:flex;flex-direction:column;height:calc(100dvh - var(--headh))}
.tree-full .tree-viewport{flex:1;height:auto;min-height:0;border:0;border-radius:0;
  background-color:var(--bg);touch-action:none;
  /* 点阵底纹与全站一致(用户裁决):.tree-viewport 基类已带 radial-gradient,
     这里只覆写底色,不要覆写 background-image */
  background-image:radial-gradient(var(--dot) 1px,transparent 1.4px);
  background-size:var(--dot-gap) var(--dot-gap)}
/* 横条:空间不足时换行(英文比中文长,宁可两行也不许胶囊被 CTA 压住) */
.intro-strip{display:flex;align-items:center;gap:8px clamp(12px,2vw,28px);flex-wrap:wrap;
  padding:10px clamp(14px,2.5vw,32px);border-bottom:1px solid var(--line);
  background:color-mix(in srgb,var(--bg-2) 60%,var(--bg))}
/* 标题区可收缩:英文标题比中文长得多,不能 nowrap 独占宽度把胶囊挤没。
   两行封顶 + 省略号,横条高度保持稳定。 */
.is-title{display:flex;flex-direction:column;gap:2px;min-width:0;flex:0 1 auto;max-width:min(34ch,29vw)}
.is-title h1{font-size:1.02rem;line-height:1.28;margin:0;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.is-sub{font-family:var(--font-mono);font-size:.58rem;letter-spacing:.06em;color:var(--text-mute);
  display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical;overflow:hidden}
.is-map{display:flex;gap:6px;flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;min-width:0;flex:1 1 auto}
.is-map::-webkit-scrollbar{display:none}
.im-pill{display:inline-flex;align-items:center;gap:.45em;flex:none;
  background:none;border:1px solid var(--line);border-radius:999px;
  padding:.34em .8em;cursor:pointer;font-family:inherit;color:var(--text-2);
  font-size:.76rem;transition:border-color .15s,color .15s}
.im-pill:hover{border-color:var(--text-2);color:var(--text)}
.im-pill .im-dot{width:8px;height:8px;border-radius:2px}
.im-pill .im-name{font-weight:700;color:var(--text)}
.im-pill .im-n{font-family:var(--font-mono);font-size:.6rem;color:var(--text-mute)}
.is-actions{display:flex;align-items:center;gap:10px;margin-left:auto;flex:none}
.is-actions .btn{font-size:.66rem;padding:.55em .9em;white-space:nowrap}
/* 介绍卡：窄长竖栏，贴视口上下边；地图控制钮并入卡底（树=绝对核心,卡=它的仪表柱）*/
.tree-intro{position:absolute;left:clamp(14px,2vw,28px);top:14px;
  bottom:14px;z-index:6;width:min(330px,calc(100vw - 28px));
  display:flex;flex-direction:column;overflow-y:auto;overscroll-behavior:contain}
.tree-intro h1{font-size:1.24rem;line-height:1.35;margin:.55em 0 .4em}
.tree-intro .lede{font-size:.8rem;line-height:1.68;color:var(--text-2);margin:0 0 .9em}
/* 内容总览：两行式分支导览=图例+跳转+说明三合一（窄栏下说明退居第二行）*/
.intro-map{display:block;margin:0 0 1em;border-bottom:1px solid var(--line)}
.im-row{display:grid;grid-template-columns:auto auto 1fr;align-items:center;
  column-gap:.55em;row-gap:.15em;width:100%;background:none;border:0;
  border-top:1px solid var(--line);padding:.45em 2px;cursor:pointer;text-align:left;
  font-family:inherit;color:var(--text-2);transition:background .12s,color .12s}
.im-row:hover{background:color-mix(in srgb,var(--text) 6%,transparent);color:var(--text)}
.im-dot{width:9px;height:9px;border-radius:2px}
.im-name{font-weight:700;font-size:.8rem;color:var(--text)}
.im-n{font-family:var(--font-mono);font-size:.58rem;letter-spacing:.08em;
  color:var(--text-mute);justify-self:end}
.im-desc{grid-column:2 / -1;font-size:.7rem;color:var(--text-mute)}
.im-row:hover .im-desc{color:var(--text-2)}
.tree-intro .intro-cta{display:flex;flex-wrap:wrap;gap:calc(var(--u)*1.25)}
.tree-intro .intro-cta .btn{font-size:.68rem;padding:.6em .9em}
.intro-spacer{flex:1;min-height:12px}
/* 地图控制钮 */
.intro-controls{display:flex;gap:6px;font-family:var(--font-mono)}
.intro-controls button{background:color-mix(in srgb,var(--bg-2) 90%,transparent);
  border:1px solid var(--glass-brd);color:var(--text-2);border-radius:var(--radius);
  font-family:var(--font-mono);font-size:.64rem;letter-spacing:.06em;
  padding:.45em .7em;cursor:pointer;min-width:30px}
.intro-controls button:hover{color:var(--accent);border-color:var(--accent)}
.tree-intro .intro-hint{font-family:var(--font-mono);font-size:.58rem;letter-spacing:.08em;
  color:var(--text-mute);margin:.8em 0 0}
@media (max-width:860px){
  .intro-strip{flex-wrap:wrap;gap:8px 12px}
  .is-title h1{white-space:normal;font-size:.98rem}
  .is-actions{margin-left:0;width:100%;justify-content:space-between}
}

/* 连线（电路走线：正交总线，默认压暗；跨支虚线；悬停/点亮才上色）*/
.edge{fill:none;stroke:var(--line-2);stroke-width:1.5;opacity:.5}
.edge.cross{stroke-dasharray:4 4}
.edge.lit{opacity:.8}
.edge.lit[data-branch="red"]   {stroke:var(--branch-red)}
.edge.lit[data-branch="blue"]  {stroke:var(--branch-blue)}
.edge.lit[data-branch="yellow"]{stroke:var(--branch-yellow)}
.edge.lit[data-branch="green"]{stroke:var(--branch-green)}
.edge.lit[data-branch="converge"],.edge.lit[data-branch="case"]{stroke:var(--text-2)}
.edge.hot{opacity:1;stroke-width:2.5}
.edge.hot[data-branch="red"]   {stroke:var(--branch-red);filter:drop-shadow(0 0 3px var(--branch-red-glow))}
.edge.hot[data-branch="blue"]  {stroke:var(--branch-blue);filter:drop-shadow(0 0 3px var(--branch-blue-glow))}
.edge.hot[data-branch="yellow"]{stroke:var(--branch-yellow);filter:drop-shadow(0 0 3px var(--branch-yellow-glow))}
.edge.hot[data-branch="green"] {stroke:var(--branch-green);filter:drop-shadow(0 0 3px var(--branch-green-glow))}
.edge.hot[data-branch="converge"],.edge.hot[data-branch="case"]{stroke:var(--text);filter:drop-shadow(0 0 3px var(--glass-hi))}

/* 节点芯片 */
.node{position:absolute;width:190px;height:134px;transform:translate(-50%,-50%);
  display:flex;flex-direction:column;gap:6px;padding:12px 14px;cursor:pointer;
  /* 统一尺寸(用户裁决):恒为「两行中文+两行英文」的高度,视觉整齐划一 */
  border:1px solid var(--line);border-radius:var(--radius-panel);
  /* 性能红线：芯片不用 backdrop-filter——58 个模糊层叠在整块可平移的 stage 上,
     每帧平移/缩放都要重采样 58 次,GPU 内存与合成时间双爆。近似色直接混进背景色。 */
  background:color-mix(in srgb,var(--panel) 88%,var(--bg));
  text-decoration:none;transition:transform .15s,border-color .15s}
.node:hover{transform:translate(-50%,-50%) scale(1.05);text-decoration:none}
.node .n-head{display:flex;align-items:center;justify-content:space-between;
  font-family:var(--font-mono);font-size:.8rem;letter-spacing:.1em;color:var(--text-2)}
.node .n-id{color:var(--accent)}
.node .n-zh{font-family:var(--font-display);font-weight:700;font-size:1.26rem;line-height:1.18;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
  color:var(--text)}
.node .n-en{font-family:var(--font-mono);font-size:.72rem;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;letter-spacing:.06em;
  color:var(--text-mute);text-transform:uppercase;line-height:1.2}
.node[data-branch]{}
/* 汇流舱：里程碑异形卡（横条，白色微光，与普通芯片形制不同——异形而非放大）*/
.node.node-cap{width:auto;min-width:300px;max-width:360px;height:auto;min-height:76px;
  flex-direction:row;align-items:center;gap:12px;padding:14px 18px;
  border-color:color-mix(in srgb,var(--text) 45%,var(--line));
  box-shadow:0 0 0 1px color-mix(in srgb,var(--text) 12%,transparent),
             0 0 18px color-mix(in srgb,var(--glass-hi) 60%,transparent)}
.node-cap .n-id{font-family:var(--font-mono);font-size:.8rem;color:var(--text)}
.node-cap .cap-txt{display:flex;flex-direction:column;gap:2px}
.node-cap .n-zh{font-size:1.26rem}
.node-cap.locked{opacity:.8}

/* 难度分层线与标签 */
.level-line{stroke:var(--line-2);stroke-width:1;stroke-dasharray:7 9;opacity:.5}
.level-label{fill:var(--text-mute);font-family:var(--font-mono);font-size:13px;
  letter-spacing:.14em}
.mini .level-line{opacity:.28}

/* 状态三档(用户裁决 2026-07-22):亮度阶梯 completed > available > locked,
   语义靠右上角徽章清晰区分——locked 素点 / available 空心环(可读未读) / completed 实心对勾(已读)。
   locked 的正文保持满对比度(未点亮也要读得清),淡化只作用于外框/编号行/徽章。 */
.node.locked{border-color:color-mix(in srgb,var(--accent) 16%,var(--line))}
.node.locked .n-zh{color:var(--text)}
.node.locked .n-en{color:var(--text-mute)}
.node.locked .n-head{opacity:.45}
/* available=可读未读完:整块相对低调(边框半亮、无脉冲),但徽章明确标出「可读」 */
.node.available{border-color:color-mix(in srgb,var(--accent) 52%,var(--line))}
.node.available .n-head{opacity:.78}
/* completed=已读:最醒目——满亮边框 + 内发光 + 放大的对勾徽章 */
.node.completed{border-color:var(--accent);
  box-shadow:0 0 0 1px var(--accent) inset,0 0 16px color-mix(in srgb,var(--accent-glow) 30%,transparent)}

/* ── 右上角状态徽章 ── */
.node .n-led{position:absolute;top:-11px;right:-11px;width:22px;height:22px;border-radius:50%;
  box-sizing:border-box;display:grid;place-items:center;
  background:var(--panel);border:2px solid var(--line-2);
  font-family:var(--font-mono);font-size:14px;font-weight:800;line-height:1;color:transparent;
  transition:background .15s,border-color .15s}
.node.locked .n-led{width:9px;height:9px;top:-4px;right:-4px;border:none;
  background:var(--line-2);opacity:.55}
.node.available .n-led{border-color:var(--accent);background:var(--bg);
  box-shadow:0 0 7px var(--accent-glow)}
.node.completed .n-led{background:var(--accent);border-color:var(--accent);color:var(--bg);
  box-shadow:0 0 8px var(--accent-glow)}
.node.completed .n-led::after{content:"✓"}
/* 徽章可点=切换已读/未读:光标+悬停放大;::before 扩出点击热区(照顾 locked 的小圆点) */
.node .n-led.badge-btn{cursor:pointer}
.node .n-led.badge-btn::before{content:"";position:absolute;inset:-8px;border-radius:50%}
.node .n-led.badge-btn:hover{transform:scale(1.18)}
.node.locked .n-led.badge-btn:hover{transform:scale(1.7)}
.node .n-led.badge-btn:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

/* 分支色作用（节点自带 data-branch，tokens.css 已映射 --accent）*/
/* 案例带节点＝证据卡片：虚线边框区别于理论节点 */
.node[data-branch="case"]{border-style:dashed}
.mini .dot[data-branch="case"]{border-style:dashed}

/* Tree HUD */
.tree-hud{position:absolute;left:12px;bottom:12px;z-index:5;display:flex;gap:8px;
  font-family:var(--font-mono);font-size:.66rem}
.tree-hud button{background:color-mix(in srgb,var(--bg-2) 90%,transparent);
  border:1px solid var(--glass-brd);color:var(--text-2);border-radius:var(--radius);
  padding:.4em .7em;cursor:pointer}
.tree-hud button:hover{color:var(--accent);border-color:var(--accent)}
.tree-legend{position:absolute;right:12px;bottom:12px;z-index:5;display:flex;flex-direction:column;
  gap:2px;font-family:var(--font-mono);font-size:.64rem;color:var(--text-2);
  background:color-mix(in srgb,var(--bg-2) 90%,transparent);border:1px solid var(--glass-brd);
  border-radius:var(--radius);padding:6px 8px}
/* 图例即分支跳转按钮 */
.tree-legend .k{display:flex;align-items:center;gap:.5em;background:none;border:0;
  color:inherit;font:inherit;letter-spacing:inherit;cursor:pointer;padding:.3em .2em;
  border-radius:var(--radius);text-align:left}
.tree-legend button.k:hover{color:var(--text);background:color-mix(in srgb,var(--text) 8%,transparent)}
.tree-legend .sw{width:20px;height:3px;border-radius:2px}
@media (max-width:720px){
  .tree-viewport{height:min(62vh,520px)}
  /* 触摸目标最小 44px */
  .tree-hud button{min-width:44px;min-height:44px;font-size:.72rem}
}

/* ============================================================
   课程页左侧导轨（lesson-shell = 左树右文）
   ============================================================ */
.lesson-shell{display:grid;grid-template-columns:clamp(240px,20vw,300px) minmax(0,1fr)}
.tree-rail{position:sticky;top:var(--headh);height:calc(100dvh - var(--headh));
  border-right:1px solid var(--line);display:flex;flex-direction:column;
  background:color-mix(in srgb,var(--bg-2) 55%,transparent)}
.rail-head{display:flex;align-items:center;gap:.6em;padding:10px 14px;
  border-bottom:1px solid var(--line);font-family:var(--font-mono);font-size:.64rem;
  letter-spacing:.12em;text-transform:uppercase;color:var(--text-2)}
.rail-head .rh-id{color:var(--accent)}
.rail-head .rh-count{margin-left:auto;color:var(--text-mute)}
.tree-viewport.mini{flex:1;height:auto;border:0;border-radius:0;background:transparent;
  background-image:none;cursor:default;touch-action:auto}
.rail-foot{display:flex;align-items:center;justify-content:space-between;gap:.6em;
  padding:9px 14px;border-top:1px solid var(--line);
  font-family:var(--font-mono);font-size:.66rem;letter-spacing:.1em}
.rail-foot a{color:var(--text-2)}
.rail-foot a:hover{color:var(--accent);text-decoration:none}
@media (max-width:1080px){.lesson-shell{display:block}.tree-rail{display:none}}

/* 迷你树点阵：详细度分级——
   当前节点=发光边框的迷你芯片(内嵌标号)；直接前置/后继=挂标号的点；其余=素点 */
.mini .dot{position:absolute;width:14px;height:14px;transform:translate(-50%,-50%);
  border-radius:3px;border:1.5px solid color-mix(in srgb,var(--accent) 80%,var(--line-2));
  background:color-mix(in srgb,var(--accent) 14%,var(--panel));cursor:pointer}
.mini .dot:hover{border-color:var(--accent);z-index:3}
.mini .dot.available{border-color:var(--accent)}
.mini .dot.completed{background:var(--accent);border-color:var(--accent)}
.mini .dot.locked{opacity:.85}
.mini .dot.near{border-color:var(--accent);z-index:2}
.mini .dot.current{width:34px;height:20px;border:1px solid var(--accent);z-index:4;
  display:flex;align-items:center;justify-content:center;background:var(--bg-2);
  box-shadow:0 0 0 2px color-mix(in srgb,var(--accent) 30%,transparent),
             0 0 12px var(--accent-glow)}
.mini .dot-id{font-family:var(--font-mono);font-size:.6rem;letter-spacing:.06em;
  color:var(--accent);font-weight:700}
.mini .dot-tag{position:absolute;top:-15px;left:50%;transform:translateX(-50%);
  font-family:var(--font-mono);font-size:.54rem;letter-spacing:.06em;white-space:nowrap;
  color:var(--accent);opacity:.85}
.mini .edge{stroke-width:1.2;opacity:.6}
.mini .edge.hot{stroke-width:1.8;opacity:1}

@media (prefers-reduced-motion:reduce){
  .glyph-strip .led,.led.pulse,.bootline.typing{animation:none}
  .bootline.typing{width:100%}
  .tree-stage.gliding{transition:none}
}


/* 亮色主题:点阵回归(用户新裁决 2026-07:隐约灰点,浓度见 tokens.css 的 --dot)。
   .bg-dots 不再隐藏;树导轨/视口仍保持无背景纹理(纯白托盘)。 */
:root[data-theme="light"] .tree-rail{background:transparent}
/* 注意:不要给 .tree-viewport 加 background-image:none —— 那条规则权重(0,3,0)高过
   .tree-full .tree-viewport(0,2,0),会把首页树的点阵整个压掉,亮色下看着像纯色板。 */


/* 亮色主题:连背景渐变彩斑也不要——纯白就是纯白(用户裁决) */
:root[data-theme="light"] .bg-field{display:none}


/* 迷你树悬浮卡片:节点旁跟一张极简卡,只显示 编号 + 标题(如 R05 可读性) */
.mini-tip{position:absolute;z-index:20;pointer-events:none;opacity:0;
  transform:translateY(3px);transition:opacity .12s,transform .12s;
  display:flex;align-items:baseline;gap:.5em;white-space:nowrap;
  padding:.4em .7em;border:1px solid var(--accent);border-radius:var(--radius);
  background:var(--bg-2);box-shadow:0 4px 14px rgba(0,0,0,.35),0 0 0 1px var(--bg) inset}
.mini-tip.show{opacity:1;transform:translateY(0)}
.mini-tip .mt-id{font-family:var(--font-mono);font-size:.66rem;letter-spacing:.06em;color:var(--accent)}
.mini-tip .mt-zh{font-weight:700;font-size:.82rem;color:var(--text)}
