/* /roadmap/ 学习路线图 —— 版式沿用 /learning/,状态色挂在 .rm-shell 上不污染其他页 */
.rm-shell { padding-bottom: 56px; }

/* 头部三块:统计行(.rm-sub)、说明句(.rm-lead)、筛选行(.rm-filters)。
   统计行和说明句在同一个左轴的文本块里,说明句靠 margin-top: 8px 跟统计行隔开;
   筛选行是另一个 flex 子项,靠容器的 row-gap 跟说明句隔开 —— 两个 8px 才对得上,
   之前 row-gap 是 18px,筛选行跟说明句之间明显比统计行松,中间像少了一档。
   row-gap: 8px 之后两处间距一致。
   头部底下压一条通栏横线,把"标题区"和下面的依赖图分开 —— 横线宽度跟画布
   (同一块容器)等宽,两端对齐画布的圆角框边缘。 */
.rm-head {
  display: flex; align-items: flex-end; gap: 18px; row-gap: 8px; flex-wrap: wrap;
  padding: 26px 0 14px;
  border-bottom: 1px solid var(--line);
}
.rm-head__text { min-width: 0; }
/* 视觉隐藏、语义保留 —— 给 h1 用。
   路线图正文里的大标题对读者是冗余的(顶栏有站点名、浏览器标签有标题),
   但把 h1 整个删掉会让搜索引擎和读屏软件失去页面主标题。
   1×1px + clip: 屏幕上完全看不见,读屏软件和爬虫照常能读到。 */
.rm-sr-only {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden; white-space: nowrap;
  clip: rect(0 0 0 0); clip-path: inset(50%);
}
/* 统计行:页面最实质的一块信息(模块数/课程数/目标数/课时数/我的进度),
   所以它是整个头部的重点行 —— 左边挂竖条 + 图标 + 深一点的墨色 + 稍大的字号。
   图标和主题导航栏 book-nav-roadmap__icon 是同一枚图形(两个圆点 + 一条 S 形路线),
   正文大标题去掉后,图标加竖条就是这一块的视觉锚点。
   文字被 JS 写进里面的 span,所以 svg 不会被 innerHTML 冲掉。 */
.rm-sub {
  margin: 0; padding-left: 12px;
  border-left: 3px solid var(--rm-module-line);
  display: flex; align-items: center; gap: 8px;
  font-size: 13.5px; color: var(--ink-soft); line-height: 1.6;
}
.rm-sub__icon { flex: 0 0 auto; width: 19px; height: 19px; }
/* 统计行里的「门课程」链接到课程中心。统计行整体是 --ink-soft 的弱层级,
   链接沿用 .rm-hint a 的同一套强调色(--accent / --accent-hover),
   加下划线是为了在弱层级里把"这几个字能点"说清楚 —— 只靠颜色区分,
   在米色底上不够显眼。 */
.rm-sub__link,
.rm-sub__link:visited {
  color: var(--accent);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
}
.rm-sub__link:hover { color: var(--accent-hover); }
.rm-sub__link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }
/* 路线图的用法说明 —— 放在统计行下面、图表上面:
   模块里并列挂着好几门课,不看这句会以为得全学完才往下走。
   它是软提示,不是要点,所以只留字号和颜色的弱层级,竖条让给上面的统计行。 */
.rm-lead {
  margin: 8px 0 0;
  font-size: 13px; color: var(--muted); line-height: 1.6;
}

/* 筛选按钮跟标题、统计行共用一条左轴 —— 之前 margin-left:auto 把它推到最右,
   左边空一大块,整块头部看着是散的。 */
/* align-items: center —— 引导语套上框之后比下面的胶囊高几像素,
   容器默认的 stretch 会把六个胶囊一起拉高,这里统一居中,各自保持自己的高度。 */
.rm-filters { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
/* 引导语 + 竖线分隔 —— 竖线沿用图例里 .rm-legend__sep 的画法(1px 实色竖条),
   高度 16px,跟 15px 的字面齐平。 */
.rm-filters__label {
  /* 引导语是这一行的**标题**,不是按钮的注脚 —— 字号抬到 15px、墨色抬到 --ink。
     之前用 --muted(13.5px),那个色跟页面上那句说明(.rm-lead)同级,
     整行最重的却是右边的实心按钮,视线第一下落在按钮上,而不是先读懂这行在干嘛。
     字重保持 600(中等) —— 再往上加粗,配上底框反而像一颗按钮。 */
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 15px; color: var(--ink); font-weight: 600;
  align-self: center; white-space: nowrap;
  /* 引导语不套框 —— 只留图标 + 文字。
     它跟右边的选项本来就不是一类东西:右边是"可以选的",它是"这行在干嘛"的说明,
     套上底框反而像又多一个可点的控件(试过胶囊和米白圆角矩形,都太像按钮)。
     只靠字号(15px)、墨色(--ink,12.4:1)、字重(600)和指南针图标跟右边拉开层级 ——
     右边那排选项已经改成幽灵态(未选中只有文字),不再有六个闭合形状跟它抢。 */
}
/* 指南针图标:描边用 currentColor,跟文字同色、跟着深色模式一起变 */
.rm-filters__icon { flex: 0 0 auto; width: 19px; height: 19px; }
.rm-filters__sep {
  /* 竖线原来用 --line-strong(rgba(110,79,54,.22)),在纸底上几乎看不见,
     分隔感没立起来 —— 换成实色 --accent,分隔才真的成立。 */
  width: 1px; height: 16px; background: var(--accent);
  align-self: center; margin: 0 4px;
}
/* 未选中的按钮是**幽灵态**:不描边、不填底,只剩 12.5px 的深棕文字。
   右边原本是六个带框的胶囊连成一条约 600px 的带子 —— 眼睛对"闭合图形"的
   敏感度远高于对单段文字的敏感度,所以左边就算给引导语套了米白框,整行的
   重量还是压在那条带子上(实测视觉重心只从 45% 挪到 43%)。
   把右侧的形状撤掉,它就退化成一行次级文字,重心才真的回到引导语上。
   边框宽度照旧留着(transparent),hover 时形状浮现不会让整行横向抖一下。 */
.rm-filter {
  font: inherit; font-size: 12.5px; cursor: pointer; white-space: nowrap;
  padding: 6px 11px; border-radius: 999px;
  border: 1px solid transparent; background: transparent; color: var(--ink-soft);
  transition: background .15s, border-color .15s, color .15s;
}
/* 悬停时形状才浮现 —— 既保住"这是能点的"的提示,又不用一直摆着六个框。 */
.rm-filter:hover { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }
/* 幽灵态没有边框撑着,焦点环得自己画一条,否则键盘用户看不出停在哪。 */
.rm-filter:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.rm-filter[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: var(--accent-fg); font-weight: 600; }
/* 「全部」常驻行首,表示"没选方向"。它要是也用实心深色,整行最重的色块就贴在
   引导语右边 —— 引导语永远抢不过它。所以「全部」选中时改成浅底深字(跟页面里
   "未开始"徽标同一套画法),实心深色留给用户真正选定的那个方向:
   深色块只在"用户已经做出选择"之后才出现,首屏最重的元素就是引导语本身。
   顺带把「全部」当成本组唯一的"胶囊":没选方向时它是浅色胶囊,选了某个方向
   之后胶囊挪到那个方向上 —— 同一时刻整行只有一个胶囊,当前状态一眼可见。 */
.rm-filter--all[aria-pressed="true"] {
  background: var(--accent-soft); border-color: var(--accent); color: var(--accent);
}

/* ── 画布 ── */
/* 横线跟画布之间留一段呼吸 —— 横线是头部的下边界,紧贴画布上沿会跟画布自己的
   边框撞在一起,看着像两条线叠着。 */
.rm-stage { position: relative; margin-top: 18px; }
.rm-canvas {
  position: relative; width: 100%; max-width: 1240px; margin: 0 auto;
  /* 画布高度 1240/1160 —— 原来 1240/1250,底部多出 90 单位(≈9%)是纯空白:
     最后一行是职业目标(药丸底边在 y≈1139),画布却画到 1250,底下挂了一条
     什么都没有的带子,整张图看上去头重脚轻、页面也白占一屏。
     收到 1160 之后,底部留白 ≈20 单位,和顶部留白(≈16)基本齐平。
     ⚠️ 改这个比例,data/roadmap.yaml 里所有节点的 y 都要按「旧高/新高」换算,
        否则节点位置会跟着画布一起缩放(整体被压扁),而不是像现在这样原地不动。 */
  aspect-ratio: 1240 / 1160;
  background: var(--paper-card); border: 1px solid var(--line); border-radius: 16px;
}
.rm-canvas > svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
/* 只给「连线」上样式:之前写成 `.rm-canvas path` 会连 <marker> 里的箭头头部一起命中,
   而 `.rm-canvas path`(0,1,1) 的特异性高于 `.rm-arrow--*(0,1,0)`,导致箭头 fill 被
   覆盖成 none —— 线画出来了,箭头头部一直是隐形的。 */
.rm-edge { fill: none; stroke-width: 2; stroke-linecap: round; }
/* 箭头头部叫 rm-arrowhead 而不是 rm-head —— 页面标题栏已经占了 .rm-head */
.rm-arrowhead { stroke: none; }
.rm-edge--done { stroke: var(--rm-edge-done); }
.rm-edge--live { stroke: var(--rm-edge-live); }
.rm-edge--idle { stroke: var(--rm-idle-line); stroke-dasharray: 5 6; }
.rm-edge--dim  { opacity: .14; }
.rm-arrowhead--done { fill: var(--rm-edge-done); }
.rm-arrowhead--live { fill: var(--rm-edge-live); }
.rm-arrowhead--idle { fill: var(--rm-idle-line); }

.rm-loading, .rm-error {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  margin: 0; font-size: 13px; color: var(--muted); text-align: center; padding: 0 24px;
}
.rm-error { color: #b3261e; }

/* ── 模块(外框) + 课程(药丸) + 目标 ── */
.rm-module, .rm-goal {
  position: absolute; transform: translate(-50%, -50%); z-index: 2;
}
.rm-node--dim { opacity: .18; }
.rm-node--dim:hover { opacity: .85; }

/* 模块外框 —— 分组容器,线型永远是实线(药丸才有虚线/实线之分)。
   边框颜色跟着**模块状态**走:里面有人在学 → 橙,学完了 → 绿,没动 → 灰。
   这套颜色和药丸、出线箭头是同一套语言(箭头本来就按来源模块的状态着色),
   所以「药丸橙 + 出线橙 + 外框灰」不会再出现 —— 三个颜色各说各话,
   看着像三种不同状态。 */
.rm-module {
  display: flex; gap: 8px; padding: 11px 12px;
  border: 1px solid var(--rm-module-line); border-radius: 16px;
  background: color-mix(in srgb, var(--paper-card) 88%, var(--ink) 4%);
  transition: border-color .15s;
}
/* 边框比药丸淡一档(见 --rm-module-line 的色阶说明),但不能淡到看不见 ——
   容器太淡会让整张图读成一堆散落的药丸,分组感全无。
   idle(还没开始)和 gap(内容建设中)保持中性灰,只有真有进度时才上状态色。 */
.rm-module--done { border-color: var(--rm-done); }
.rm-module--live { border-color: var(--rm-live); }
/* 竖排时 flex-basis 会作用在高度上,所以只在横排时锁 132px 宽,竖排让药丸走内容高度 */
.rm-module--col { flex-direction: column; align-items: center; }

/* 课程药丸 —— 进度条 / 徽标 / 计数都挂在这一层 */
.rm-module--row > .rm-course { flex: 0 0 132px; }
.rm-course {
  width: 132px;
  display: flex; flex-direction: column; gap: 4px;
  padding: 8px 9px 9px;
  border: 1px solid var(--line-strong); border-radius: 12px;
  background: var(--paper-card); color: var(--ink); text-decoration: none;
  transition: transform .15s, box-shadow .15s, border-color .15s;
}
a.rm-course:hover, a.rm-course:focus-visible {
  transform: translateY(-2px); box-shadow: var(--shadow-hover); outline: none;
}
a.rm-course:focus-visible { border-color: var(--accent); }
.rm-course__title { font-size: 12.5px; font-weight: 600; line-height: 1.32; text-align: center; }
.rm-course__bar { height: 3px; border-radius: 999px; overflow: hidden; background: color-mix(in srgb, var(--ink) 12%, transparent); }
.rm-course__bar > i { display: block; height: 100%; border-radius: 999px; background: var(--rm-idle); }
.rm-course__meta { display: flex; align-items: center; gap: 5px; white-space: nowrap; }
.rm-course__count { font-size: 10.5px; color: var(--muted); font-variant-numeric: tabular-nums; }
.rm-course__flag { font-size: 9.5px; font-weight: 700; white-space: nowrap; padding: 1px 7px; border-radius: 999px; }

.rm-flag--done { background: var(--rm-done); color: #fff; }
.rm-flag--live { background: var(--rm-live); color: #fff; }
.rm-flag--idle { background: var(--accent-soft); color: var(--accent); }
.rm-flag--gap  { background: transparent; border: 1px dashed var(--line-strong); color: var(--muted); }

.rm-course--done { background: var(--rm-done-bg); border-color: var(--rm-done); }
.rm-course--done .rm-course__title { color: var(--rm-done); }
.rm-course--done .rm-course__bar > i { background: var(--rm-done); }

.rm-course--live { background: var(--rm-live-bg); border-color: var(--rm-live); box-shadow: 0 0 0 3px color-mix(in srgb, var(--rm-live) 16%, transparent); }
.rm-course--live .rm-course__title { color: var(--rm-live); }
.rm-course--live .rm-course__bar > i { background: var(--rm-live); }

.rm-course--idle { border-color: var(--accent); }
.rm-course--idle .rm-course__bar > i { background: var(--accent); }

/* 已上线就高亮——「未开始」也是已上线,没上线的才虚线。
   尚未学习(0/N)由进度条和徽标文字表达,不再额外降透明度——早期版外框也降 .72,
   两者叠乘成 0.43,同为未开始的界面两倍暗。 */

.rm-course--gap { background: transparent; border-style: dashed; }
.rm-course--gap .rm-course__title { color: var(--muted); font-weight: 500; }

/* 职业目标 —— 不套外框,独立药丸 */
/* 目标只是路线的终点标记,不可点,所以没有 hover / focus 变态。
   它没有状态徽标,也不随进度变色 —— 「这条线走完了没」算不出唯一答案,
   让读者自己判定;描边用 accent 提一下,表示这是终点而不是普通模块。 */
.rm-goal {
  min-width: 158px; padding: 9px 16px 10px;
  display: flex; flex-direction: column; gap: 5px; align-items: center; text-align: center;
  border: 1px solid color-mix(in srgb, var(--accent) 42%, transparent); border-radius: 999px;
  background: var(--paper-strong); color: var(--ink); text-decoration: none;
}
.rm-goal__title { font-size: 13px; font-weight: 700; line-height: 1.32; }

/* ── 图例 ── */
.rm-legend {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 18px;
  max-width: 1240px; margin: 16px auto 0; font-size: 11.5px; color: var(--muted);
}
.rm-legend > span { display: inline-flex; align-items: center; gap: 6px; }
.rm-legend__sep { width: 1px; height: 12px; background: var(--line-strong); }
.rm-swatch { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }
.rm-swatch--done { background: var(--rm-done); }
.rm-swatch--live { background: var(--rm-live); }
.rm-swatch--idle { background: var(--paper-card); border: 1px solid var(--accent); }
.rm-swatch--gap  { background: transparent; border: 1px dashed var(--muted); }
.rm-line { width: 24px; height: 0; display: inline-block; border-top: 2px solid; }
.rm-line--done { border-color: var(--rm-edge-done); }
.rm-line--live { border-color: var(--rm-edge-live); }
.rm-line--idle { border-color: var(--rm-idle-line); border-top-style: dashed; }

.rm-hint {
  max-width: 1240px; margin: 18px auto 0; padding: 11px 14px;
  border: 1px solid var(--line); border-radius: 10px; background: var(--paper-card);
  font-size: 12.5px; color: var(--muted);
}
.rm-hint a { color: var(--accent); font-weight: 600; }

/* ── 订阅提示横条(页面最下方)────────────────────────────────
   进度条本身是「学习记录」的投影:登录后 roadmap.js 拿
   GET /api/v1/learning/status 的已完成文章集,按课程算出 done/lessons
   画进度条和节点状态;学习记录写入要订阅才持续有效(注册后 7 天试用到期
   即停写)。所以横条放在页面最下方,对着图讲清楚"进度从哪来"。

   横幅本身是页面里的一张普通卡片,不是浮在上面的促销块 —— 底色和描边
   直接用 --paper-card / --line,和上面的 .rm-canvas、.rm-hint 同一套,
   改设计变量时三块一起跟着变。
   块内配色取自设计稿:图标底 #e9ddcc / 主棕 #79583d / 标题 #493827 /
   说明 #795f46 / 特性行 #654e37。 */
.rm-upgrade {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 20px;
  max-width: 1240px;
  margin: 20px auto 0;
  padding: 12px 22px;
  background: var(--paper-card);
  border: 1px solid var(--line);
  border-radius: 16px;
}
.rm-upgrade__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  flex: 0 0 46px;
  color: #79583d;
  background: #e9ddcc;
  border-radius: 14px;
}
.rm-upgrade__icon svg {
  width: 24px;
  height: 24px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.rm-upgrade__body { min-width: 0; }
.rm-upgrade__title {
  margin: 0 0 5px;
  font-size: 15px;
  font-weight: 600;
  color: #493827;
  letter-spacing: 0.01em;
}
.rm-upgrade__desc {
  margin: 0;
  font-size: 13px;
  color: #795f46;
  line-height: 1.6;
}
.rm-upgrade__list {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 22px;
  margin: 6px 0 0;
  padding: 0;
  list-style: none;
}
.rm-upgrade__list li {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12.5px;
  color: #654e37;
}
.rm-upgrade__list svg {
  width: 15px;
  height: 15px;
  flex: 0 0 15px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.rm-upgrade__cta,
.rm-upgrade__cta:visited,
.rm-upgrade__cta:hover,
.rm-upgrade__cta:focus,
.rm-upgrade__cta:active {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 10px 20px;
  background: #79583d;
  color: #fff !important;
  border: none;
  border-radius: 12px;
  font-size: 13.5px;
  font-weight: 600;
  font-family: inherit;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.15s ease, transform 0.15s ease;
}
.rm-upgrade__cta:hover { background: #65452e; }
.rm-upgrade__cta:active { transform: translateY(1px); }
.rm-upgrade__cta-arrow {
  width: 14px;
  height: 14px;
  flex: 0 0 14px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ── 窄屏:按目标分组 ── */
/* 窄屏说明条 —— ≤860px 时画布藏掉(太窄,模块框和连线会挤成一团),
   换成按目标分组的课程清单。不说一声,读者打开手机看到的是一堆列表,
   会以为「路线图功能坏了」。文案上不写「请在电脑端使用」——
   清单本身是能用的,只交代「这里是简化版,完整依赖图在宽屏上」。 */
.rm-narrow-note {
  display: none;
  max-width: 460px; margin: 0 auto 14px;
  padding: 10px 12px;
  border: 1px solid var(--line-strong); border-radius: 12px;
  background: var(--paper-card);
  font-size: 12.5px; line-height: 1.65; color: var(--muted);
}
.rm-narrow-note__body { display: flex; align-items: flex-start; gap: 9px; }
.rm-narrow-note__icon { flex: 0 0 auto; width: 17px; height: 17px; margin-top: 2px; color: var(--rm-module-line); }
.rm-narrow-note b { color: var(--ink-soft); font-weight: 600; }

.rm-narrow { display: none; max-width: 460px; margin: 0 auto; }
.rm-group { border: 1px solid var(--line-strong); border-radius: 12px; background: var(--paper-card); overflow: hidden; margin-bottom: 10px; }
.rm-group--trunk { border-color: var(--accent); }
.rm-group__head { display: flex; align-items: center; gap: 8px; padding: 11px 13px; background: var(--paper-strong); }
.rm-group__title { font-size: 13.5px; font-weight: 700; }
.rm-group__count { margin-left: auto; font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums; }
.rm-group__body { padding: 4px 13px 12px; }
.rm-mod { border: 1px solid var(--rm-module-line); border-radius: 10px; padding: 8px 10px 4px; margin: 8px 0; }
.rm-mod__head { display: flex; align-items: center; gap: 8px; padding-bottom: 6px; }
.rm-mod__name { font-size: 12.5px; font-weight: 700; color: var(--ink); }
.rm-row { display: flex; align-items: center; gap: 9px; padding: 8px 0; font-size: 12.5px; }
.rm-row--sub { padding: 6px 0 6px 10px; font-size: 12px; }
.rm-row + .rm-row { border-top: 1px dashed var(--line); }
.rm-row__dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 8px; background: var(--rm-idle); }
.rm-row--done .rm-row__dot { background: var(--rm-done); }
.rm-row--live .rm-row__dot { background: var(--rm-live); }
.rm-row--idle .rm-row__dot { background: var(--accent); }
.rm-row__name { color: var(--ink); text-decoration: none; }
.rm-row__name:hover { color: var(--accent); }
.rm-row__count { margin-left: auto; font-size: 10.5px; color: var(--muted); font-variant-numeric: tabular-nums; }

@media (max-width: 860px) {
  .rm-stage { display: none; }
  .rm-narrow { display: block; }
  .rm-narrow-note { display: block; }
  .rm-head { padding-top: 20px; }
}

@media (max-width: 640px) {
  .rm-upgrade {
    grid-template-columns: auto 1fr;
    gap: 12px 14px;
    padding: 16px;
  }
  .rm-upgrade__icon { width: 40px; height: 40px; flex-basis: 40px; border-radius: 12px; }
  .rm-upgrade__icon svg { width: 21px; height: 21px; }
  .rm-upgrade__list { gap: 6px 16px; }
  .rm-upgrade__cta { grid-column: 1 / -1; width: 100%; }
}

/* 路线图状态色 —— 作用域限定在 .rm-shell,不污染 /learning/ 等页面。
   状态色取「深焦糖橙 / 深橄榄绿」而不是鲜艳的荧光色,原因有三:
     ① 色相融入:橙 H32 / 绿 H100 各自贴着主棕 H29 和米白 H37-40 的暖色家族,
        状态色不跟页面的纸感打架;
     ② 饱和度对齐:页面其他色饱和度只有 21~38(棕 32、灰 23),原来的
        橙 #c07d1c 是 75 —— 全页唯一的高彩度色,孤零零地跳出来;
     ③ 对比度达标:徽标是白字压色块(9.5px 小字,AA 要 4.5:1)。
        旧橙只有 3.39:1、旧绿 3.96:1,都不达标;现在橙 4.58、绿 4.68,
        刚好过线,标题和边框也跟着更实。 */
.rm-shell {
  --rm-done: #468229;
  --rm-done-bg: #e7f0e1;
  --rm-live: #a8661a;
  --rm-live-bg: #f7ecdb;
  --rm-idle: #b6a58f;
  /* 连线/箭头专用色 —— 比药丸的状态色**低一档饱和度**:
     线是 2px 的细笔画,同一个颜色画成线和画成实心色块,视觉热度差很多 ——
     药丸的橙 S73 放到细线上会显得荧光,压到 S58 才和纸感底色融在一起。
     药丸 / 模块外框 / 徽标继续用上面的 --rm-live / --rm-done(白字压色块,
     对比度要过 AA),连线这边按「看得清路径、不抢焦点」的标准另配一档。
     对比度(对卡片底 #f9f2e5,UI 图形阈值 3:1):橙 4.44、绿 4.62。 */
  --rm-edge-live: #996529;
  --rm-edge-done: #4b7934;
  /* 边框/线条色阶 —— 分三层:占位(淡) < 结构(中) < 内容(重):
       占位层:
         画布        rgba(110,79,54,.14)  → #e5dbcc
         未上线药丸  rgba(110,79,54,.22) 虚线 → #dacebe   ← 还没上线,最淡
       结构层:
         模块外框    #c3b2a0
         未点亮连线  #c3b2a0(虚线 + 箭头)                    ← 前景路径,必须看得见
       内容层:
         目标药丸    rgba(112,84,58,.42)  → #bdac9a
         已上线药丸  #70543a                              ← 最重
     模块外框**故意不和药丸同色**:12 个框 + 21 个药丸全是同一根深棕线的话,
     「组」和「项」就分不出来了。 */
  --rm-module-line: #c3b2a0;
  /* 未点亮的连线和箭头用不透明实色,不能直接拿 --line-strong:
     那个是 rgba(110,79,54,.22),半透明色叠在卡片底上还能看,一旦和虚线、
     模块边框互相叠印就会互相透出来(箭头里能看见背后的虚线)。
     取「结构层」#c3b2a0 —— 和模块外框同档:连线是前景结构,淡到跟占位药丸
     一样(之前 #dacebe)整张图的路径几乎看不见,深到跟已上线药丸齐平又会抢焦点。 */
  --rm-idle-line: #c3b2a0;
}
