/* ══════════════════════════════════════════════════════════════
   新拟态（neumorphism）的全部秘密就一条：
   控件底色 = 页面底色，靠一对方向相反的外阴影顶出立体。
   左上放亮色 = 光从左上来；右下放暗色 = 那边是背光面。
   两道都 inset，就从凸起变成凹陷。
   ══════════════════════════════════════════════════════════════ */
:root{
  --surf:#efe3cd;                    /* 面料。所有控件都用它，不许各自填色 */
  --lite:#fffaf0;                    /* 左上高光 */
  --dark:#c9b58f;                    /* 右下暗影 */
  --off:9px; --blur:18px;            /* 位移 / 模糊，成对调 */
  --navy:#2e456f; --navy-d:#1e3153;
  --orange:#ef7a1e; --orange-d:#c25c0c;
  --ink:#4a4036;
  /* 下面这层是「角色」不是「颜色」。加皮肤时只改这一层，页面里不许再写死色值。 */
  --muted:#6a5c4b;                   /* 说明文字 */
  --warn:#9d3f0d;                    /* 警示 / 易错处 */
  --hot-a:#f9922f; --hot-b:#dd731a;  /* 强调块渐变。收窄过：两端跨度太大，深字在暗端会挂 */
  --on-hot:#3a1e06;                  /* 强调块上的字 */
  --on-deep:#ffffff;                 /* 深色块上的字 */
  --deep-a:#4b6497; --deep-b:#25395f;/* 深色块渐变 */
  --line:var(--dark);                /* 框图连线。暗色皮肤下要比底色亮 */
  --kw:#8f4108;                      /* 代码里的关键字。必须单列一个角色 —— 借用 --orange-d
                                        曾经漏检：它是「强调块的暗端」，不是「面料上的前景色」 */
  --hi:rgba(255,255,255,.85);        /* SVG 浮雕的上沿亮边 */
  --lo:rgba(120,96,58,.45);          /* SVG 浮雕的下投暗影 */
}
*{box-sizing:border-box;margin:0;padding:0}
body{background:var(--surf);color:var(--ink);font-family:"Noto Sans SC",system-ui,sans-serif;
     padding:44px 40px 80px;font-size:16px}
.relief-wrap{max-width:1180px;margin:0 auto}

/* ── 三条基础配方 ── */
.relief-raised{background:var(--surf);
  box-shadow:calc(var(--off)*-1) calc(var(--off)*-1) var(--blur) var(--lite),
             var(--off) var(--off) var(--blur) var(--dark)}
.relief-sunken{background:var(--surf);
  box-shadow:inset calc(var(--off)*-1) calc(var(--off)*-1) var(--blur) var(--lite),
             inset var(--off) var(--off) var(--blur) var(--dark)}
/* 薄件（按钮/药丸/小方块）位移要跟着缩，否则阴影糊成一坨 */
.relief-thin{--off:5px;--blur:10px}
.relief-thick{--off:13px;--blur:26px}
/* 浮雕 + 厚度。纯 neumorphism 是「面料鼓起来」，没有厚度；
   参考图那种是捏出来的实体块，所以要再加一道外落影把它抬离底面。 */
.relief-solid{background:var(--surf);
  box-shadow:calc(var(--off)*1.1) calc(var(--off)*1.5) calc(var(--blur)*1.4) rgba(122,92,48,.30),
             inset calc(var(--off)*-.9) calc(var(--off)*-.9) calc(var(--blur)*.9) var(--lite),
             inset calc(var(--off)*.7) calc(var(--off)*.7) calc(var(--blur)*.8) var(--dark)}

h2{font-size:23px;font-weight:900;color:var(--navy-d);margin:56px 0 8px;letter-spacing:.01em}
h2:first-child{margin-top:0}
.relief-note{font-size:14.5px;line-height:1.75;color:var(--muted);margin-bottom:22px;max-width:760px}
.relief-note b{color:var(--navy-d)}
code{font-family:var(--relief-mono);font-size:.92em;padding:1px 6px;border-radius:5px;
  /* 底色必须是中性的：草稿里写死的暖色 rgba 在暗皮肤上把前景压到 2.99:1。
     前景用 --navy-d，它在每个皮肤都对着面料验过 8:1 以上，16% 灰不会吃掉余量。 */
  color:var(--navy-d);background:rgba(128,128,128,.16)}

/* ── 给 SVG 描边用的浮雕。SVG 吃不到 box-shadow，只能靠成对 drop-shadow：
      第一道贴一条白边在上沿，第二道往下投一道暗影。 ── */
.relief-emboss{filter:drop-shadow(0 -1.2px 0 var(--hi)) drop-shadow(0 2px 1.6px var(--lo))}

/* ── 框图通用件 ── */
.relief-board{padding:34px 32px;border-radius:30px;margin-bottom:26px}
/* 从图集页点进来时，要能一眼认出落到的是哪一张 —— 一页十张图，
   光滚过去不够。滚动留一段余量，再让边沿亮一下就退回常态。
   注意这里不给 html 加 scroll-behavior:smooth：截图脚本是 scrollTo 分步
   滚完立刻截，平滑滚动会让它截在没停稳的位置上。 */
.relief-board{scroll-margin-top:28px}
.relief-board:target{animation:relief-land 2.6s ease-out 1}
@keyframes relief-land{
  0%,55%{box-shadow:0 0 0 3px var(--hot-b),
    calc(var(--off)*-1) calc(var(--off)*-1) var(--blur) var(--lite),
    var(--off) var(--off) var(--blur) var(--dark)}
  100%{box-shadow:0 0 0 3px transparent,
    calc(var(--off)*-1) calc(var(--off)*-1) var(--blur) var(--lite),
    var(--off) var(--off) var(--blur) var(--dark)}
}
/* 关掉动效的人看不到那道闪，给他留一条不动的标记 */
@media (prefers-reduced-motion:reduce){
  .relief-board:target{animation:none;
    box-shadow:0 0 0 3px var(--hot-b),
      calc(var(--off)*-1) calc(var(--off)*-1) var(--blur) var(--lite),
      var(--off) var(--off) var(--blur) var(--dark)}
}
.relief-bt{font-size:14px;font-weight:700;color:var(--muted);letter-spacing:.06em;margin-bottom:22px}
.relief-bt em{font-style:normal;font-weight:500;color:var(--muted);margin-left:10px;letter-spacing:0}

/* ══════════════════════════════════════════════════════════════
   中性灰皮肤。新拟态原本就长在中性灰上（neumorphism.relief-io 的默认底色
   是 #e0e0e0），因为灰色两头都留得出余量：往白走有高光的空间，
   往黑走有暗影的空间。暖米白的亮度已经到 78%，高光只剩 4% 可涨，
   所以凸起会比灰底弱一截 —— 这不是配色好看不好看的问题，是物理上限。
   ══════════════════════════════════════════════════════════════ */
[data-theme="gray"]{
  --surf:#e3e6ea; --lite:#ffffff; --dark:#b6bcc7; --ink:#333a45;
  --navy:#2c4470; --navy-d:#1b2c4e; --orange:#e8721a; --orange-d:#bd5509;
  --muted:#59616e; --warn:#a8480e;
  --hot-a:#f2842a; --hot-b:#de7620; --on-hot:#3a1e06; --deep-a:#44608f; --deep-b:#1f3356;
  --hi:rgba(255,255,255,.95); --lo:rgba(74,84,102,.40);
  --kw:#8a3f07;
}

/* 皮肤切换条 */
.relief-skins{position:fixed;top:16px;right:20px;z-index:9;display:flex;gap:5px;padding:6px;border-radius:15px;
  --off:5px;--blur:10px}
.relief-skins b{padding:7px 13px;border-radius:11px;font:700 12.5px "Noto Sans SC";color:var(--muted);cursor:pointer;white-space:nowrap}
.relief-skins b.on{color:var(--navy-d);background:var(--surf);
  box-shadow:3px 3px 7px var(--dark),-3px -3px 7px var(--lite)}
/* 窄屏：七个皮肤一行比 390px 的屏还宽，右对齐之后左端被屏幕切掉，而且整条压在
   左上角的语言按钮上面 —— 手机上语言切换点不到。让皮肤条只占语言按钮右边的那段，
   放不下就在条里横着滑。 */
@media (max-width:640px){
  .lang-toggle{left:10px;top:12px}
  .relief-skins{top:12px;right:10px;max-width:calc(100vw - 122px);overflow-x:auto;scrollbar-width:none}
  .relief-skins::-webkit-scrollbar{display:none}
}

/* ══════════════════════════════════════════════════════════════
   皮肤。每个皮肤只覆盖上面那层「角色」变量，一行样式都不用重写。
   暗色那个要单独说：高光不能用白 —— 白边在暗底上会变成一圈灯管，
   不像鼓起来像发光。暗色的高光是「比底色亮一点的同色」，
   暗影是「比底色暗一点的同色」，两边都往自己那头挪一小步。
   代价是明暗差更小，所以位移和模糊要加大才看得出凹凸。
   ══════════════════════════════════════════════════════════════ */
[data-theme="ink"]{
  --surf:#2e333b; --lite:#3d444e; --dark:#1e2228; --ink:#c7cedb;
  --navy:#8fb2e8; --navy-d:#bcd0f0; --orange:#f0954a; --orange-d:#c8701f;
  --muted:#9aa5b6; --warn:#f0946a; --line:#4d5663;
  --hot-a:#e89340; --hot-b:#c56c1c; --on-hot:#2a1503; --deep-a:#4e6285; --deep-b:#2f3d57;
  --hi:rgba(255,255,255,.10); --lo:rgba(0,0,0,.60);
  --off:11px; --blur:22px;
  --kw:#f0a45c;
}
[data-theme="mist"]{            /* 低饱和青灰 */
  --surf:#dce4e3; --lite:#f4fbfa; --dark:#aeb9b7; --ink:#2d3938;
  --navy:#2f5a55; --navy-d:#1d403b; --orange:#a86a4e; --orange-d:#844e35;
  --muted:#556360; --warn:#8a4526; --line:var(--dark);
  --hot-a:#35766f; --hot-b:#275b56; --on-hot:#ffffff; --deep-a:#476b66; --deep-b:#2a4844;
  --hi:rgba(255,255,255,.90); --lo:rgba(56,74,72,.42);
  --kw:#7d3f22;
}
[data-theme="clay"]{            /* 低饱和陶土 */
  --surf:#e6ddd7; --lite:#faf4f0; --dark:#bfb2aa; --ink:#3c332e;
  --navy:#4a5769; --navy-d:#3d4a55; --orange:#a9694f; --orange-d:#854c35;
  --muted:#6b5d55; --warn:#8c4128; --line:var(--dark);
  --hot-a:#ae5f45; --hot-b:#96492f; --on-hot:#ffffff; --deep-a:#5f6e83; --deep-b:#3e4a5b;
  --hi:rgba(255,255,255,.88); --lo:rgba(96,80,68,.42);
  --kw:#7e3a1e;
}
[data-theme="sage"]{            /* 低饱和鼠尾草 */
  --surf:#e2e5db; --lite:#f7faf0; --dark:#b4bbab; --ink:#353a2e;
  --navy:#47573d; --navy-d:#2f3c28; --orange:#9c7a3c; --orange-d:#775b26;
  --muted:#5c6353; --warn:#8d5a2c; --line:var(--dark);
  --hot-a:#98682f; --hot-b:#7d5424; --on-hot:#ffffff; --deep-a:#55664a; --deep-b:#354330;
  --hi:rgba(255,255,255,.88); --lo:rgba(74,82,64,.42);
  --kw:#6f4a18;
}

/* 磨砂黑。比 ink 再深一档，接近纯黑。
   深到这个程度，高光/暗影和底色的明暗差被压得更扁，所以位移要再加大。
   颗粒层一半为质感，一半是[推断，未实测]：8 位色深下大面积近黑的平缓渐变
   容易出色带，颗粒能打散它。真要确认得在目标屏上看，不是在这里下结论。 */
[data-theme="matte"]{
  --surf:#1b1e23; --lite:#282d34; --dark:#0d0f12; --ink:#d3d9e2;
  --navy:#7ea6e6; --navy-d:#a8c3ee; --orange:#e08a3c; --orange-d:#b05f14;
  --muted:#8590a0; --warn:#ef9a70; --line:#3b424c;
  --hot-a:#e08b30; --hot-b:#cc7524; --on-hot:#241202; --deep-a:#42557a; --deep-b:#212c40;
  --hi:rgba(255,255,255,.07); --lo:rgba(0,0,0,.72);
  --off:12px; --blur:24px;
  --kw:#f2a862;
}
[data-theme="matte"] body::after{content:"";position:fixed;inset:0;pointer-events:none;z-index:99;
  opacity:.30;mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3'/><feColorMatrix type='saturate' values='0'/></filter><rect width='140' height='140' filter='url(%23n)'/></svg>")}

/* ─────────── 基础框图部件 ─────────── */
/* ══════ 3 框图 ══════ */

/* 流程链 */
/* safe center：放得下时居中，放不下时从左边排起。只写 center 的话，比图板宽的一行
   会往两边溢出，而左边溢出的那段在横向滚动容器里拖不到（滚动只能往右）——
   390px 下流水线图的前 308px 就是这样看不见的。桌面放得下，渲染不变。 */
.relief-flow{display:flex;align-items:center;justify-content:safe center;gap:0}
.relief-node{padding:18px 26px;border-radius:19px;font-size:17px;font-weight:700;color:var(--navy-d);
  white-space:nowrap}
.relief-node.relief-hot{color:var(--on-hot);background:linear-gradient(145deg,var(--hot-a),var(--hot-b));
  box-shadow:6px 6px 13px var(--dark),-6px -6px 13px var(--lite)}
/* 连线：凹槽 + 浮起的箭头。凹槽让线看起来是刻进面料里的 */
.relief-wire{width:76px;height:10px;border-radius:999px;position:relative;flex:none;
  box-shadow:inset 3px 3px 6px var(--dark),inset -2px -2px 5px var(--lite)}
.relief-wire::after{content:"";position:absolute;right:-7px;top:50%;transform:translateY(-50%);
  width:0;height:0;border:11px solid transparent;border-left:16px solid var(--navy);
  filter:drop-shadow(0 -1px 0 var(--hi)) drop-shadow(1px 2px 1.5px var(--lo))}

/* 树状 */
.relief-tree{display:flex;flex-direction:column;align-items:center;gap:0}
.relief-tier{display:flex;justify-content:center;gap:34px}
/* 树的连线（.relief-rung 里固定宽度的 svg）要和每一层节点共用同一根中线。窄屏下
   各层居中往两边溢出、连线从左边起排，两者对不上，最左的节点还拖不到。给整棵树
   一个不小于最宽那层连线（620）的宽度，几何和桌面一样，由图板横向拖。 */
@media (max-width:1023px){.relief-tree{min-width:640px}}
.relief-tnode{padding:13px 24px;border-radius:15px;font:700 16px "JetBrains Mono","Noto Sans SC";
  color:var(--navy-d)}
.relief-tnode.relief-root{color:var(--on-hot);background:linear-gradient(145deg,var(--hot-a),var(--hot-b));
  box-shadow:6px 6px 13px var(--dark),-6px -6px 13px var(--lite)}
.relief-rung{height:38px;width:100%;display:grid;place-items:center}
.relief-rung svg{overflow:visible}
.relief-rung path{fill:none;stroke:var(--line);stroke-width:7;stroke-linecap:round;stroke-linejoin:round;
  filter:drop-shadow(0 -1.5px 0 rgba(255,250,240,.95))}
.relief-leafrow{display:flex;justify-content:center;gap:18px;margin-top:6px}
.relief-prop{padding:6px 14px;border-radius:999px;font:500 13px "JetBrains Mono";color:var(--muted);
  box-shadow:inset 3px 3px 6px var(--dark),inset -2px -2px 5px var(--lite)}

/* 左右对比 */
.relief-split{display:grid;grid-template-columns:1fr 72px 1fr;align-items:stretch;gap:0}
.relief-panel{padding:26px 24px;border-radius:24px;text-align:center;display:flex;flex-direction:column}
.relief-panel .relief-cap{font-size:15px;font-weight:700;color:var(--navy-d);margin-bottom:14px}
.relief-panel .relief-body{flex:1;display:grid;place-items:center;padding:22px 16px;border-radius:17px;font-size:15px;line-height:1.7;color:var(--muted);
  box-shadow:inset 5px 5px 10px var(--dark),inset -5px -5px 10px var(--lite)}
.relief-bigarrow{display:grid;place-items:center}
.relief-bigarrow svg{filter:drop-shadow(0 -1.5px 0 rgba(255,250,240,.9)) drop-shadow(2px 3px 2px var(--lo))}

/* 分层 */
.relief-layers{display:flex;flex-direction:column;gap:14px;max-width:560px;margin:0 auto}
.relief-layer{display:flex;align-items:center;gap:16px;padding:17px 24px;border-radius:19px}
.relief-layer .relief-idx{width:34px;height:34px;border-radius:50%;flex:none;display:grid;place-items:center;
  font:900 15px "JetBrains Mono";color:var(--on-deep);background:linear-gradient(145deg,var(--deep-a),var(--deep-b));
  box-shadow:3px 3px 7px var(--dark),-3px -3px 7px var(--lite)}
.relief-layer .relief-nm{font-size:17px;font-weight:700;color:var(--navy-d)}
.relief-layer .relief-hint{margin-left:auto;font:500 13.5px "JetBrains Mono";color:var(--muted)}
.relief-drop{height:20px;display:grid;place-items:center}
.relief-drop svg{filter:drop-shadow(0 -1px 0 rgba(255,250,240,.9)) drop-shadow(0 2px 1.5px var(--lo))}

/* 结构体字段 */
.relief-grid4{display:grid;grid-template-columns:repeat(4,1fr);gap:15px}
.relief-slot{padding:15px 12px;border-radius:15px;text-align:center;font:500 15px "JetBrains Mono";color:var(--muted)}
.relief-slot.relief-set{color:var(--navy-d);font-weight:700}
.relief-slot.relief-set::after{content:"●";display:block;margin-top:6px;font-size:10px;color:var(--orange)}

/* ─────────── 控件 ─────────── */
/* ══════ 2 控件 ══════ */
.relief-kit{display:flex;flex-wrap:wrap;gap:20px;align-items:center}
/* background 必须显式写：<button> 有浏览器默认底色，浅皮肤下它碰巧接近面料
   看不出来，暗皮肤下就是一块浅灰。凸起态靠 .relief-raised 补底，按下态没有。 */
.relief-btn{padding:15px 30px;border-radius:17px;border:0;background:var(--surf);font:700 16px "Noto Sans SC";
  color:var(--navy-d);cursor:pointer;transition:box-shadow .16s}
.relief-btn:active,.relief-btn.on{box-shadow:inset 5px 5px 10px var(--dark),inset -5px -5px 10px var(--lite)}
.relief-btn-pri{color:var(--on-hot);background:linear-gradient(145deg,var(--hot-a),var(--hot-b));
  box-shadow:5px 5px 10px var(--dark),-5px -5px 10px var(--lite)}
.relief-pill{padding:9px 20px;border-radius:999px;font-size:14.5px;font-weight:700;color:var(--navy)}

.relief-switch{width:82px;height:42px;border-radius:999px;position:relative;cursor:pointer}
.relief-switch i{position:absolute;top:6px;left:6px;width:30px;height:30px;border-radius:50%;
  background:var(--surf);box-shadow:3px 3px 7px var(--dark),-3px -3px 7px var(--lite);
  transition:left .22s cubic-bezier(.4,0,.2,1)}
.relief-switch.on i{left:46px;background:linear-gradient(145deg,var(--hot-a),var(--hot-b))}

.relief-slider{width:250px;height:16px;border-radius:999px;position:relative}
.relief-slider .relief-fill{position:absolute;inset:3px auto 3px 3px;width:58%;border-radius:999px;
  background:linear-gradient(90deg,#f0a35a,#e0700f)}
.relief-slider .relief-knob{position:absolute;left:56%;top:50%;transform:translateY(-50%);
  width:32px;height:32px;border-radius:50%;background:var(--surf);
  box-shadow:4px 4px 9px var(--dark),-4px -4px 9px var(--lite)}

.relief-field{width:280px;padding:15px 20px;border-radius:15px;border:0;background:var(--surf);
  font:500 15px "Noto Sans SC";color:var(--ink);outline:0;
  box-shadow:inset 5px 5px 10px var(--dark),inset -5px -5px 10px var(--lite)}
.relief-seg{display:inline-flex;padding:6px;border-radius:16px;gap:4px}
.relief-seg span{padding:9px 20px;border-radius:12px;font-size:14.5px;font-weight:700;color:var(--muted);cursor:pointer}
.relief-seg span.on{color:var(--navy-d);background:var(--surf);
  box-shadow:3px 3px 7px var(--dark),-3px -3px 7px var(--lite)}
.relief-disc{width:78px;height:78px;border-radius:50%;display:grid;place-items:center}


/* ─────────── 硬件框图部件 ─────────── */
/* ══ 通用：浮雕描边。SVG 描边吃不到 box-shadow，只能成对 drop-shadow ══ */
.relief-wire-stroke{fill:none;stroke:var(--dark);stroke-width:5;stroke-linecap:round;stroke-linejoin:round;
  filter:drop-shadow(0 -1.4px 0 var(--lite))}
.relief-arrowhead{fill:var(--navy);filter:drop-shadow(0 -1px 0 var(--hi)) drop-shadow(1px 2px 1.5px var(--lo))}

/* ══════ A 状态机 ══════ */
.relief-fsm{position:relative;width:960px;height:430px;margin:0 auto}
/* SVG 跟着容器走，不写死尺寸 —— 写死 960x430 会把 viewBox 不同的图纵向拉伸，
   状态框还在原位，箭头却整体偏掉，看起来像坐标算错了。 */
.relief-fsm svg{position:absolute;inset:0;width:100%;height:100%;overflow:visible}
.relief-st{position:absolute;display:grid;place-items:center;border-radius:20px;
  font:700 17px var(--relief-sans);color:var(--navy-d);text-align:center;line-height:1.3}
.relief-st small{display:block;font:500 12px var(--relief-mono);color:var(--muted);margin-top:3px}
.relief-st.relief-entry{color:var(--on-hot);background:linear-gradient(145deg,var(--hot-a),var(--hot-b));
  box-shadow:6px 6px 13px var(--dark),-6px -6px 13px var(--lite)}
.relief-st.relief-entry small{color:var(--on-hot);opacity:.75}
.relief-lbl{position:absolute;padding:6px 13px;border-radius:999px;white-space:nowrap;
  font:500 12.5px var(--relief-sans);color:var(--muted);
  box-shadow:inset 3px 3px 6px var(--dark),inset -2px -2px 5px var(--lite)}
.relief-lbl.relief-bad{color:var(--warn)}

/* ══════ B 时序图 ══════ */
.relief-scope{padding:22px 18px;border-radius:24px}
.relief-scope svg{display:block;width:100%;height:auto}
/* 波形图窄屏下不跟着缩（known-bugs §1.71）：390px 下标注只剩 2–3px。
   面板本身撑到 --pan-w（量出来的：最小字 9px 时图要多宽，visual-audit 的
   diagram-tiny-text 提示里给数），由外面的图板横向拖 —— 撑的是面板不是 svg，
   不然凹槽还是窄的，波形伸到槽外面去。没写 --pan-w 时 calc 无效，这条不生效。 */
@media (max-width:1023px){.relief-scope{min-width:calc(var(--pan-w) + 36px)}}
.relief-wave{fill:none;stroke:var(--navy);stroke-width:4.5;stroke-linecap:round;stroke-linejoin:round;
  filter:drop-shadow(0 -1.3px 0 var(--lite)) drop-shadow(0 2px 1.6px var(--lo))}
.relief-wave.relief-busline{stroke:var(--warn)}
.relief-guide{stroke:var(--dark);stroke-width:1.6;stroke-dasharray:4 5;opacity:.85}
.relief-siglbl{font:700 14px var(--relief-sans);fill:var(--navy-d)}
.relief-signote{font:500 11px var(--relief-mono);fill:var(--muted)}
.relief-tspan{stroke:var(--navy);stroke-width:2.2;fill:none}
.relief-tcap{font:500 11.5px var(--relief-sans);fill:var(--muted);text-anchor:middle}
.relief-tcap b{font-family:var(--relief-mono);fill:var(--warn)}

/* ══════ C 寄存器位域 ══════ */
.relief-regbar{display:grid;grid-template-columns:repeat(32,1fr);gap:3px}
/* 一格一位，位宽就是意思：窄屏下不跟着缩（390px 下每位只剩 7px，字段名叠在一起），
   保持 720px，由图板横向拖 */
@media (max-width:1023px){.relief-regbar{min-width:720px}}
.relief-bitno{font:500 10.5px var(--relief-mono);color:var(--muted);text-align:center;padding-bottom:6px}
.relief-fld{border-radius:11px;height:88px;display:grid;place-items:center;text-align:center;
  font:700 13px var(--relief-mono);color:var(--navy-d);padding:4px;--off:5px;--blur:10px}
.relief-fld.relief-rsvd{color:var(--muted);font-weight:400}
.relief-fld.relief-narrow{writing-mode:vertical-rl;transform:rotate(180deg);font-size:11.5px;letter-spacing:.04em}
.relief-fld .relief-rst{display:block;font-weight:400;font-size:10.5px;color:var(--muted);margin-top:4px}
.relief-fld.relief-wo{color:var(--warn)}
.relief-regfoot{display:flex;gap:26px;margin-top:16px;font:500 13px var(--relief-mono);color:var(--muted);flex-wrap:wrap}
.relief-regtab{width:100%;border-collapse:separate;border-spacing:0 7px;margin-top:20px;font-size:14px}
.relief-regtab th{text-align:left;font:700 12px var(--relief-sans);color:var(--muted);letter-spacing:.05em;padding:0 14px 4px}
.relief-regtab td{padding:11px 14px;background:var(--surf);color:var(--ink)}
.relief-regtab tr td:first-child{border-radius:12px 0 0 12px}
.relief-regtab tr td:last-child{border-radius:0 12px 12px 0}
.relief-regtab tbody tr{box-shadow:4px 4px 9px var(--dark),-4px -4px 9px var(--lite)}
.relief-regtab .relief-nm{font:700 13.5px var(--relief-mono);color:var(--navy-d)}
/* 描边标签，不给底色。半透明底会把面料压暗十几级，而前景色是照纯面料
   验的对比度，余量不到 0.5，一压就破 —— 标签要的是「这是个标记」，
   描边同样做得到，还不动底。 */
.relief-acc{display:inline-block;padding:3px 10px;border-radius:999px;font:700 11.5px var(--relief-mono);
  background:transparent;box-shadow:inset 0 0 0 1.4px currentColor}
.relief-acc.relief-rw{color:var(--navy-d)} .relief-acc.relief-ro{color:var(--muted)} .relief-acc.relief-wo{color:var(--warn)}


/* ══════ E 内存布局 ══════ */
.relief-memmap{display:grid;grid-template-columns:132px 1fr 96px;gap:0 14px;align-items:stretch}
.relief-addr{font:500 12.5px var(--relief-mono);color:var(--muted);text-align:right;white-space:nowrap;
  align-self:end;padding-bottom:9px}   /* 贴住区块底边：地址往上增长，起始地址在下边界 */
.relief-region{border-radius:13px;padding:13px 18px;margin-bottom:7px;--off:5px;--blur:10px;
  display:flex;align-items:center;gap:12px;min-height:50px}
.relief-region .relief-rn{font:700 14.5px var(--relief-sans);color:var(--navy-d)}
.relief-region .relief-rd{font:400 12px var(--relief-sans);color:var(--muted);margin-left:auto;text-align:right}
.relief-region.relief-dead .relief-rn{color:var(--muted);font-weight:500}
.relief-region.relief-hot{background:linear-gradient(145deg,var(--hot-a),var(--hot-b));
  box-shadow:5px 5px 11px var(--dark),-5px -5px 11px var(--lite)}
.relief-region.relief-hot .relief-rn,.relief-region.relief-hot .relief-rd{color:var(--on-hot)}
.relief-region.relief-hot .relief-rd{opacity:.8}
.relief-size{font:500 12px var(--relief-mono);color:var(--muted);align-self:center;padding-bottom:7px}

/* ══════ F 数据通路 ══════ */
.relief-path{display:flex;align-items:stretch;gap:0;overflow-x:auto;padding:4px 0}
.relief-stagebox{min-width:104px;flex:1;display:flex;flex-direction:column;align-items:center}
.relief-stage{width:100%;border-radius:15px;padding:13px 7px;text-align:center;--off:5px;--blur:10px;min-height:76px;
  display:flex;flex-direction:column;justify-content:center}
.relief-stage .relief-sn{font:700 13px var(--relief-sans);color:var(--navy-d)}
.relief-stage .relief-ss{font:400 11px var(--relief-mono);color:var(--muted);margin-top:4px}
.relief-stage.relief-store{background:linear-gradient(145deg,var(--deep-a),var(--deep-b));
  box-shadow:5px 5px 11px var(--dark),-5px -5px 11px var(--lite)}
.relief-stage.relief-store .relief-sn{color:var(--on-deep)} .relief-stage.relief-store .relief-ss{color:var(--on-deep);opacity:.74}
.relief-rate{margin-top:8px;font:500 10.5px var(--relief-mono);color:var(--muted);text-align:center;line-height:1.5}
.relief-gap{width:34px;flex:none;display:flex;flex-direction:column;align-items:center;justify-content:flex-start;padding-top:32px}
.relief-gap svg{filter:drop-shadow(0 -1.2px 0 var(--hi)) drop-shadow(1px 2px 1.5px var(--lo))}
.relief-bwbar{margin-top:22px;height:15px;border-radius:999px;position:relative;overflow:hidden}
.relief-bwbar span{position:absolute;top:3px;bottom:3px;left:3px;border-radius:999px;
  background:linear-gradient(90deg,var(--hot-a),var(--hot-b))}
.relief-bwcap{display:flex;justify-content:space-between;margin-top:8px;font:500 11.5px var(--relief-mono);color:var(--muted)}

/* ══════ G 时钟树 ══════ */
.relief-clk{display:grid;grid-template-columns:auto 1fr;gap:18px 0;align-items:center}
.relief-clkrow{display:flex;align-items:center;gap:0;flex-wrap:wrap}
.relief-cnode{border-radius:13px;padding:11px 16px;--off:4px;--blur:9px;text-align:center;white-space:nowrap}
.relief-cnode .relief-cn{font:700 13.5px var(--relief-mono);color:var(--navy-d)}
.relief-cnode .relief-cf{font:500 11px var(--relief-mono);color:var(--muted);margin-top:3px}
.relief-cnode.relief-src{background:linear-gradient(145deg,var(--deep-a),var(--deep-b));
  box-shadow:4px 4px 9px var(--dark),-4px -4px 9px var(--lite)}
.relief-cnode.relief-src .relief-cn{color:var(--on-deep)} .relief-cnode.relief-src .relief-cf{color:var(--on-deep);opacity:.74}
.relief-cnode.relief-leaf{background:linear-gradient(145deg,var(--hot-a),var(--hot-b));
  box-shadow:4px 4px 9px var(--dark),-4px -4px 9px var(--lite)}
.relief-cnode.relief-leaf .relief-cn{color:var(--on-hot)} .relief-cnode.relief-leaf .relief-cf{color:var(--on-hot);opacity:.78}
.relief-crun{width:34px;height:8px;border-radius:999px;flex:none;margin:0 7px;
  /* 只用在真的串联的两级之间。并联支路一律不连线，连了就是画错 */
  box-shadow:inset 3px 3px 6px var(--dark),inset -2px -2px 5px var(--lite)}
/* 选择器和门控本来就是控件 —— 直接用控件的样子画，不另造图形 */
.relief-mux{display:inline-flex;padding:4px;border-radius:13px;gap:3px;--off:4px;--blur:9px;justify-self:start}   /* grid 里默认 stretch，会把它拉满整列 */
.relief-mux i{font:700 11.5px var(--relief-mono);font-style:normal;padding:6px 11px;border-radius:9px;color:var(--muted)}
.relief-mux i.on{color:var(--navy-d);background:var(--surf);box-shadow:3px 3px 6px var(--dark),-3px -3px 6px var(--lite)}
.relief-gate{width:56px;height:30px;border-radius:999px;position:relative;flex:none;margin:0 9px;--off:4px;--blur:9px}
.relief-gate b{position:absolute;top:4px;left:4px;width:22px;height:22px;border-radius:50%;background:var(--surf);
  box-shadow:2px 2px 5px var(--dark),-2px -2px 5px var(--lite)}
.relief-gate.on b{left:30px;background:linear-gradient(145deg,var(--hot-a),var(--hot-b))}
.relief-clklbl{font:700 12.5px var(--relief-sans);color:var(--muted);padding-right:20px;text-align:right;white-space:nowrap}

/* ══════ D IP 内部框图 ══════ */
.relief-soc{display:flex;flex-direction:column;align-items:center;gap:0}
.relief-socrow{display:grid;gap:20px;width:100%}
.relief-well{padding:18px 18px 20px;border-radius:22px}
.relief-wname{font:700 12.5px var(--relief-sans);color:var(--muted);letter-spacing:.05em;margin-bottom:13px;
  display:flex;align-items:center;gap:8px}
.relief-wname span{font:500 11px var(--relief-mono);color:var(--muted);letter-spacing:0}
.relief-blocks{display:flex;flex-wrap:wrap;gap:9px}
.relief-blk{padding:11px 14px;border-radius:13px;font:700 13.5px var(--relief-mono);color:var(--navy-d);
  --off:4px;--blur:9px}
.relief-blk i{display:block;font:400 10.5px var(--relief-sans);color:var(--muted);font-style:normal;margin-top:3px}
.relief-blk.relief-big{background:linear-gradient(145deg,var(--deep-a),var(--deep-b));color:var(--on-deep);
  box-shadow:4px 4px 9px var(--dark),-4px -4px 9px var(--lite)}
.relief-blk.relief-big i{color:var(--on-deep);opacity:.74}
.relief-blk.relief-hot{background:linear-gradient(145deg,var(--hot-a),var(--hot-b));color:var(--on-hot);
  box-shadow:4px 4px 9px var(--dark),-4px -4px 9px var(--lite)}
.relief-blk.relief-hot i{color:var(--on-hot);opacity:.72}
/* 总线：一条凹槽轨。主设备接在上面，从设备接在下面 —— 这是读图的约定 */
.relief-bus{width:100%;height:46px;border-radius:14px;margin:0;display:grid;place-items:center;
  font:700 13.5px var(--relief-mono);color:var(--navy-d);letter-spacing:.06em;position:relative}
.relief-bus em{font-style:normal;font-weight:500;font-size:11.5px;color:var(--muted);margin-left:12px;letter-spacing:0}
.relief-stubs{display:grid;width:100%;height:26px}
.relief-stub{justify-self:center;width:9px;height:26px;border-radius:999px;
  box-shadow:inset 3px 3px 6px var(--dark),inset -2px -2px 5px var(--lite)}
.relief-legend{display:flex;gap:22px;flex-wrap:wrap;margin-top:18px;font-size:13px;color:var(--muted)}
.relief-legend i{display:inline-block;width:26px;height:13px;border-radius:5px;vertical-align:-2px;margin-right:7px}
.relief-legend i.relief-m{background:linear-gradient(145deg,var(--deep-a),var(--deep-b))}
.relief-legend i.relief-s{background:var(--surf);box-shadow:2px 2px 3px var(--dark),-2px -2px 3px var(--lite),inset 0 0 0 1px var(--dark)}
.relief-legend i.relief-h{background:linear-gradient(145deg,var(--hot-a),var(--hot-b))}

/* ═══════════════ 双语切换（cross-skill-rules §G）═══════════════ */
html[data-lang="en"] .lang-zh{display:none!important}
html[data-lang="zh"] .lang-en{display:none!important}
.lang-toggle{position:fixed;top:16px;left:20px;z-index:9;padding:9px 16px;border:0;cursor:pointer;
  border-radius:13px;background:var(--surf);color:var(--navy-d);font:700 13px var(--relief-sans);
  box-shadow:5px 5px 10px var(--dark),-5px -5px 10px var(--lite)}
.lang-toggle:active{box-shadow:inset 4px 4px 8px var(--dark),inset -4px -4px 8px var(--lite)}

/* ═══════════════ 页头（§K 品牌色必须出现在顶部 1440×500）═══════════════ */
.relief-hero{padding:74px 0 8px}
.relief-badge{display:inline-flex;align-items:center;gap:9px;padding:9px 20px;border-radius:999px;
  font:700 13px var(--relief-mono);letter-spacing:.06em;color:var(--on-hot);
  background:linear-gradient(145deg,var(--hot-a),var(--hot-b));
  box-shadow:5px 5px 11px var(--dark),-5px -5px 11px var(--lite)}
.relief-h1{margin:26px 0 14px;font:900 46px/1.16 var(--relief-sans);color:var(--navy-d);letter-spacing:-.01em}
.relief-lede{max-width:760px;font-size:17px;line-height:1.8;color:var(--muted)}
.relief-lede b{color:var(--navy-d)}
.relief-rail{margin:30px 0 0;height:15px;border-radius:999px;position:relative;overflow:hidden;
  box-shadow:inset 5px 5px 10px var(--dark),inset -4px -4px 9px var(--lite)}
.relief-rail span{position:absolute;top:3px;bottom:3px;left:3px;width:38%;border-radius:999px;
  background:linear-gradient(90deg,var(--hot-a),var(--hot-b))}
.relief-mono{font-family:var(--relief-mono)}
.relief-wrap--narrow{max-width:900px}
.relief-wrap--wide{max-width:1360px}
.relief-container{max-width:1180px;margin:0 auto}
.relief-container--narrow{max-width:900px;margin:0 auto}
.relief-container--wide{max-width:1360px;margin:0 auto}

/* ═══════════════ 术语表（known-bugs 1.63：中文正文里的术语要有定义）═══════════════ */
.relief-glossary{margin-top:14px;display:grid;grid-template-columns:repeat(auto-fit,minmax(252px,1fr));gap:12px}
.relief-glossary div{padding:15px 18px;border-radius:15px;--off:5px;--blur:10px}
.relief-glossary dt{font:700 14px var(--relief-mono);color:var(--navy-d);margin-bottom:5px}
.relief-glossary dd{margin:0;font-size:13.5px;line-height:1.7;color:var(--muted)}

/* 键盘焦点必须看得见。新拟态没有边框，焦点若只靠颜色变化就等于没有 */
:focus-visible{outline:3px solid var(--orange);outline-offset:3px;border-radius:9px}

/* 固定像素宽的图（状态机的节点是按坐标摆的，缩不了）放进可横向拖的容器，
   否则窄屏下整页跟着横向滚动 —— 那会把每一段正文都拖歪。 */
.relief-pan{overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch}
.relief-pan::-webkit-scrollbar{height:9px}
.relief-pan::-webkit-scrollbar-thumb{border-radius:999px;background:var(--dark)}

/* 窄屏下图板自己就是 .relief-pan。
   上面那条规矩（固定宽的部件包一层 .relief-pan）写在 dos-and-donts §9 里，
   但一直没有检查逼它：2026-09-23 在 390px 下量，9 个 relief 页整页横滚，
   冲出去的是二十多种图 —— 栈回溯、时序图、调用链、内存图、寄存器表。
   这些图的几何就是意思（地址往下长、生命线并排、缩进=调用深度），
   窄屏下不能重排，只能在自己的图板里左右拖。所以不再指望每张图都记得包，
   而是让图板在窄屏下自己承担：一条规则，以后新画的图也自动在内。
   两条边上的暗槽只在「那边还有内容」时出现（background-attachment:
   local 那两层遮住、scroll 那两层露出来），读者靠它知道这块能拖；拖到头就消失。
   内边距收到 16px：子部件的凸起阴影约 5px 偏移 + 10px 模糊，
   16px 刚好还在滚动容器的内边距里，不会被裁成一刀齐。
   分界宽度是 1023px，不是 640px：第一版只在 ≤640px 生效，768 / 900 下照样整页横滚。
   上限也不能去掉，有两个原因，都是改的时候量出来的：
   · 暗槽是渐变底，axe 在渐变底上算不出对比度，只报「无法判定」。桌面宽度（axe 跑的
     就是 1440）也画的话，relief 每张图里的文字会悄悄退出 axe 的对比度检查；
   · overflow 让图板成为独立的裁剪层，桌面端 17/18 张整页截图出现 11–1109 个像素、
     最大 6/255 的抗锯齿差。桌面上放得下，拖动用不上，这点差不值得付。
   现在桌面端与改动前逐像素相同（9 页 × 中英，改动时比过）。 */
@media (max-width:1023px){
  .relief-board{overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;overscroll-behavior-x:contain;
    background:
    linear-gradient(to right,var(--surf) 45%,transparent) left center/28px 100% no-repeat local,
    linear-gradient(to left,var(--surf) 45%,transparent) right center/28px 100% no-repeat local,
    radial-gradient(farthest-side at 0 50%,var(--dark),transparent) left center/12px 100% no-repeat scroll,
    radial-gradient(farthest-side at 100% 50%,var(--dark),transparent) right center/12px 100% no-repeat scroll,
    var(--surf)}
}
@media (max-width:640px){
  .relief-board{padding:22px 16px;border-radius:22px}
}

/* ═══════════════ 质感对照（教学部件）═══════════════ */
.relief-vs{display:grid;grid-template-columns:repeat(4,1fr);gap:20px}
.relief-cell{padding:26px 22px;border-radius:26px;text-align:center}
.relief-swatch{height:112px;border-radius:24px;margin-bottom:16px;display:grid;place-items:center;
  font:900 34px var(--relief-sans);color:var(--navy)}
.relief-cell h3{font-size:16px;font-weight:700;color:var(--navy-d);margin-bottom:5px}
.relief-cell p{font-size:13.5px;line-height:1.6;color:var(--muted)}
/* 四张样例是并列的卡片，不是按坐标摆的图：窄屏下两列排，不做横向拖 */
@media (max-width:640px){
  .relief-vs{grid-template-columns:repeat(2,minmax(0,1fr));gap:14px}
  .relief-cell{padding:18px 12px}
  .relief-swatch{height:84px}
}
/* 反面样本：渐变填充 + 单向落影。这是 claymorphism 的做法，
   没有左上那道亮色，所以看着是「贴上去」的，不是从面料上顶起来的。 */
.relief-wrong{background:linear-gradient(158deg,var(--lite),var(--surf) 48%,var(--dark));
  box-shadow:0 20px 30px -14px rgba(96,62,28,.30),
             inset 0 8px 12px -5px rgba(255,255,255,.55),
             inset 0 -11px 16px -7px rgba(70,42,16,.26)}

/* ═══════════════ 平台级框图部件 ═══════════════ */
/* 启动链：阶段按「跑在哪块内存里」分带。带是凹槽，阶段是凸块 ——
   深度在这里直接回答「这一级的代码在哪执行」，不用再画一列注解。 */
.relief-boot{display:flex;flex-direction:column;gap:0}
.relief-bootband{padding:17px 18px 19px;border-radius:22px}
.relief-bandname{font:700 12.5px var(--relief-sans);color:var(--muted);letter-spacing:.05em;
  margin-bottom:13px;display:flex;align-items:center;gap:9px;flex-wrap:wrap}
.relief-bandname em{font-style:normal;font-weight:500;font-size:11.5px;font-family:var(--relief-mono)}
.relief-stagerow{display:flex;align-items:stretch;flex-wrap:wrap;gap:0}
.relief-bstage{padding:12px 15px;border-radius:14px;--off:4px;--blur:9px;min-width:126px}
.relief-bstage b{display:block;font:700 14px var(--relief-mono);color:var(--navy-d)}
.relief-bstage i{display:block;font-style:normal;font:400 11.5px var(--relief-sans);color:var(--muted);margin-top:4px;line-height:1.5}
.relief-bstage.relief-sealed{box-shadow:5px 5px 11px var(--dark),-5px -5px 11px var(--lite),inset 0 0 0 2px var(--orange)}
.relief-barrow{width:30px;flex:none;display:grid;place-items:center}
.relief-barrow svg{filter:drop-shadow(0 -1.2px 0 var(--hi)) drop-shadow(1px 2px 1.5px var(--lo))}
.relief-banddrop{height:22px;display:grid;place-items:center}
.relief-banddrop svg{filter:drop-shadow(0 -1.2px 0 var(--hi)) drop-shadow(0 2px 1.5px var(--lo))}

/* 编号翻译：同一个东西在两侧叫不同的名字 */
.relief-xlate{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:18px;
  padding:18px 20px;border-radius:19px}
.relief-xside{text-align:center}
.relief-xside b{display:block;font:700 19px var(--relief-mono);color:var(--navy-d)}
.relief-xside i{display:block;font-style:normal;font:500 12px var(--relief-sans);color:var(--muted);margin-top:5px}
.relief-xmid{font:700 12px var(--relief-mono);color:var(--warn);text-align:center;white-space:nowrap}

/* 焊盘复用：一个焊盘 N 个功能，只有一路接得通 */
.relief-pad{display:grid;grid-template-columns:150px 1fr;gap:16px;align-items:center;
  padding:15px 18px;border-radius:18px;margin-bottom:11px}
.relief-padname{font:700 14.5px var(--relief-mono);color:var(--navy-d)}
.relief-padname span{display:block;font:400 11px var(--relief-sans);color:var(--muted);margin-top:4px}
.relief-padclash{box-shadow:inset 5px 5px 10px var(--dark),inset -5px -5px 10px var(--lite),inset 0 0 0 2px var(--warn)}

/* ═══════════════ 软件框图部件 ═══════════════ */

/* 函数堆栈。栈往低地址长，所以「视觉上在上面」和「地址上在下面」是反的 ——
   左边那列地址就是用来把这件事说清楚的，不然读者只能靠记。 */
.relief-stack{display:grid;grid-template-columns:128px 1fr 118px;gap:0 14px;align-items:stretch}
.relief-frame{border-radius:13px;padding:12px 17px;margin-bottom:7px;--off:5px;--blur:10px;
  display:flex;align-items:center;gap:12px;min-height:48px}
.relief-frame b{font:700 14px var(--relief-mono);color:var(--navy-d)}
.relief-frame i{font-style:normal;font:400 12px var(--relief-sans);color:var(--muted);margin-left:auto;text-align:right}
.relief-frame.relief-crash{background:linear-gradient(145deg,var(--hot-a),var(--hot-b));
  box-shadow:5px 5px 11px var(--dark),-5px -5px 11px var(--lite)}
.relief-frame.relief-crash b{color:var(--on-hot)}
.relief-frame.relief-crash i{color:var(--on-hot);opacity:.82}
.relief-sp{font:500 12px var(--relief-mono);color:var(--muted);text-align:right;align-self:center;
  padding-bottom:7px;white-space:nowrap}
.relief-fnote{font:400 11.5px var(--relief-sans);color:var(--muted);align-self:center;padding-bottom:7px}

/* 调用关系。被关注的函数在中间，调它的在上、它调的在下 —— 这是读调用图的约定，
   反过来摆，读者得先花时间弄清哪边是哪边。 */
.relief-cg{display:flex;flex-direction:column;align-items:center;gap:0}
.relief-cgrow{display:flex;justify-content:center;gap:13px;flex-wrap:wrap}
.relief-fn{padding:11px 16px;border-radius:13px;--off:4px;--blur:9px;text-align:center;white-space:nowrap}
.relief-fn b{display:block;font:700 13.5px var(--relief-mono);color:var(--navy-d)}
.relief-fn i{display:block;font-style:normal;font:400 11px var(--relief-sans);color:var(--muted);margin-top:3px}
.relief-fn.relief-focus{background:linear-gradient(145deg,var(--hot-a),var(--hot-b));
  box-shadow:6px 6px 13px var(--dark),-6px -6px 13px var(--lite);padding:14px 24px}
.relief-fn.relief-focus b{color:var(--on-hot);font-size:15.5px}
.relief-fn.relief-focus i{color:var(--on-hot);opacity:.8}
/* 中断上下文里会走到的路径描警示色：这一支下面不能睡眠 */
.relief-fn.relief-atomic{box-shadow:4px 4px 9px var(--dark),-4px -4px 9px var(--lite),inset 0 0 0 2px var(--warn)}
.relief-cgedge{height:34px;width:100%;display:grid;place-items:center}
.relief-cgedge svg{overflow:visible}
.relief-cgedge path{fill:none;stroke:var(--line);stroke-width:6;stroke-linecap:round;stroke-linejoin:round;
  filter:drop-shadow(0 -1.5px 0 var(--hi))}
.relief-cgedge path.relief-cond{stroke-dasharray:8 7}

/* 缩进式调用树。内核里看调用关系从来不是并排的 —— ftrace function_graph、
   dmesg 的 Call trace、gdb bt，全是缩进的一棵树，缩进深度就是调用深度。
   照着这个形状画，读者不用先学图例，而且能和手上那份 ftrace 输出逐行对上。

   每一级画一道凹槽：深度在这里是「一条通道」，和别的图里凹的意思一致。
   槽不用逐行接 —— 前序遍历里「深度大于 k 的行」正好是那一级的全部子孙，
   而且一定连续，所以每行各画各的那几道，竖线自然就连成一条。 */
.relief-ct{display:flex;flex-direction:column;gap:6px;--step:30px}
.relief-ctrow{position:relative;display:grid;grid-template-columns:1fr auto;
  align-items:center;gap:14px;padding-left:calc(var(--d,0) * var(--step))}
.relief-ctrow::before{content:"";position:absolute;left:0;top:-3px;bottom:-3px;
  width:calc(var(--d,0) * var(--step));pointer-events:none;
  /* 暗线紧跟一道亮线 = 一道刻进面料的细槽 */
  background:repeating-linear-gradient(to right,
    transparent 0 11px,var(--dark) 11px 12.3px,var(--lite) 12.3px 13.6px,
    transparent 13.6px var(--step))}
.relief-ctfn{justify-self:start;max-width:100%;padding:9px 15px;border-radius:12px;
  --off:4px;--blur:9px;display:flex;align-items:baseline;gap:11px;white-space:nowrap}
.relief-ctfn b{font:700 13.5px var(--relief-mono);color:var(--navy-d)}
.relief-ctfn i{font-style:normal;font:400 11.5px var(--relief-sans);color:var(--muted)}
/* 这一趟里最该看的那一帧 */
.relief-ctfn.relief-hot{background:linear-gradient(145deg,var(--hot-a),var(--hot-b));
  box-shadow:5px 5px 11px var(--dark),-5px -5px 11px var(--lite)}
.relief-ctfn.relief-hot b,.relief-ctfn.relief-hot i{color:var(--on-hot)}
.relief-ctfn.relief-hot i{opacity:.82}
/* 这一支跑在原子上下文里：往下都不能睡 */
.relief-ctfn.relief-atomic{box-shadow:4px 4px 9px var(--dark),-4px -4px 9px var(--lite),
  inset 0 0 0 2px var(--warn)}
/* 没进去的分支画成凹的 —— 「这条路这次没走」 */
.relief-ctfn.relief-skip{box-shadow:inset 3px 3px 7px var(--dark),inset -3px -3px 6px var(--lite)}
.relief-ctfn.relief-skip b{color:var(--muted);font-weight:500}
.relief-ctus{font:500 12px var(--relief-mono);color:var(--muted);white-space:nowrap;text-align:right}
.relief-ctus.relief-slow{color:var(--warn);font-weight:700}
/* 树底下那句「所以呢」 */
.relief-ctnote{margin-top:14px;padding:11px 16px;border-radius:13px;--off:4px;--blur:9px;
  font:400 13px var(--relief-sans);color:var(--ink);line-height:1.7}
.relief-ctnote b{color:var(--navy-d)}

/* ═══════════════ 调用链定位图 ═══════════════
   形状和上面那棵调用树像，回答的问题不是一个：
   调用树答「这一次走了哪条路、时间花在哪一层」，
   这张答 ——「为什么这件事卡在这一行」。
   所以每一层右边必须挂 file:line，关键那一层底下必须贴代码原文。

   凹凸的分工（读者不用看图例就能读对）：
     凸起药丸   = 一个函数，一个存在的东西
     竖凹槽     = 缩进，一级一道。和调用树同一套画法，深度就是一条通道
     凹陷出处条 = file:line。它是一个指向图外的坐标，不是一个东西
     凹得更深   = 这一层真的拿不到行号（运行时决定 / 宏展开后才有），
                  条子上写原因。「凹 = 够不到」在这里是字面成立的
     凹陷代码条 = 原文。它不是我画的东西，是刻在那个文件里的事实
     凸起橙卡   = 「为什么这一行是关键」。这句是人的判断，所以它凸起 ——
                  一眼分得出哪句话是代码说的、哪句是写图的人说的

   出处为什么不靠空格对齐：纯文本版这张图最难的正是这一步，file:line 要凑
   空格才能成列，而中文注释一进来宽度就乱（全角 2 格、ASCII 1 格）。
   grid 的右列天生就是一列，两种字混排也不歪，缩进也不靠空格 —— 改一个字不会错位。 */
.relief-site{display:flex;flex-direction:column;gap:7px;--step:26px;max-width:960px}
/* 一张图里两条互不相干的链，各自戴一个凹陷小牌。
   「这两条链彼此不调用」是这类图的全部要点 —— 不分段的话，
   读者会把第二条链读成第一条的下一步，而那正好是反过来的结论。 */
.relief-sitehead{font:700 11px var(--relief-sans);color:var(--muted);
  padding:6px 12px;border-radius:8px;margin:0 0 6px;width:fit-content;
  box-shadow:inset 2px 2px 5px var(--dark),inset -2px -2px 4px var(--lite)}
.relief-sitehead+.relief-site{margin-bottom:18px}

/* 一层一行：函数在左，出处靠右。行宽固定，auto 列被推到最右，于是
   各行长短不同的 file:line 右缘自己成一列。 */
.relief-siterow{position:relative;display:grid;grid-template-columns:1fr auto;
  align-items:center;gap:14px;padding-left:calc(var(--d,0) * var(--step))}
/* 缩进槽：暗线紧跟一道亮线 = 一道刻进面料的细槽（同 .relief-ct） */
.relief-siterow::before,.relief-sitesrc::before,.relief-siteret::before{content:"";position:absolute;left:0;
  top:-3px;bottom:-3px;width:calc(var(--d,0) * var(--step));pointer-events:none;
  background:repeating-linear-gradient(to right,
    transparent 0 9px,var(--dark) 9px 10.3px,var(--lite) 10.3px 11.6px,
    transparent 11.6px var(--step))}
/* 药丸和出处之间那道引导点线，就是目录页页码前面那串点。
   一行里函数名在左、出处在右，中间隔着一段空白 —— 空白越宽，眼睛越容易
   串到上下行去，而这张图读错一行就是读错一个结论。
   画法：点线铺在整行的背景上，药丸和出处各自用面料色把自己那段盖掉，
   于是点线只在空隙里露出来，不用去算每行的距离。
   **代价写在这儿**：凡是压在这条线上的东西都必须有不透明底色 ——
   少一个，点线就从字里穿过去。所以 .relief-skip 也显式给了面料底。 */
.relief-siterow::after{content:"";position:absolute;top:50%;height:1px;z-index:0;
  left:calc(var(--d,0) * var(--step) + 6px);right:2px;opacity:.55;
  background:repeating-linear-gradient(to right,var(--dark) 0 1.6px,transparent 1.6px 7px)}
.relief-sitefn{position:relative;z-index:1;justify-self:start;max-width:100%;
  padding:8px 14px;border-radius:12px;background:var(--surf);
  --off:4px;--blur:9px;display:flex;align-items:baseline;gap:10px;white-space:nowrap}
.relief-sitefn b{font:700 13.5px var(--relief-mono);color:var(--navy-d)}
.relief-sitefn i{font-style:normal;font:400 11.5px var(--relief-sans);color:var(--muted)}
/* 出事的那一层 */
.relief-sitefn.relief-hot{background:linear-gradient(145deg,var(--hot-a),var(--hot-b));
  box-shadow:5px 5px 11px var(--dark),-5px -5px 11px var(--lite)}
.relief-sitefn.relief-hot b,.relief-sitefn.relief-hot i{color:var(--on-hot)}
.relief-sitefn.relief-hot i{opacity:.82}
/* 这次没进去的分支画成凹的 —— 「这条路没走」，和别的图里凹的意思一致 */
.relief-sitefn.relief-skip{box-shadow:inset 3px 3px 7px var(--dark),inset -3px -3px 6px var(--lite)}
.relief-sitefn.relief-skip b{color:var(--muted);font-weight:500}
/* 被删掉的那一步。**和 .relief-skip 不是一回事**：那个是「代码还在，这次没走到」，
   这个是「代码没了」。第一版两者共用一个样式 —— 同一种深度表达了两件事，
   图例自相矛盾，而这张图要回答的恰恰是「删掉它会怎样」。
   所以删掉的这一层凹得一样深，名字划掉，再挂一个警示色的小字说清。
   它下面的孩子因为它没了才不跑，那些画成 .relief-skip（没走到）。 */
.relief-sitefn.relief-removed{box-shadow:inset 3px 3px 7px var(--dark),inset -3px -3px 6px var(--lite)}
.relief-sitefn.relief-removed b{color:var(--muted);font-weight:500;
  text-decoration:line-through;text-decoration-color:var(--warn);text-decoration-thickness:2px}
.relief-sitecut{font:700 10.5px var(--relief-sans);color:var(--warn);letter-spacing:.04em;white-space:nowrap}

/* 出处。等宽、凹陷、贴着右边缘 —— 读者拿它直接跳过去核。 */
.relief-siteat{position:relative;z-index:1;background:var(--surf);
  font:500 11.5px var(--relief-mono);color:var(--navy-d);white-space:nowrap;
  padding:5px 10px;border-radius:8px;--off:2px;--blur:5px;
  box-shadow:inset 2px 2px 5px var(--dark),inset -2px -2px 4px var(--lite)}
/* 这一层拿不到行号。凹得更深，字换成说明体 —— 条子上写的是「为什么拿不到」，
   不是一个坐标。没有行号又不说原因的那一层，读者没法核，跟一段文字没区别。 */
.relief-siteat.relief-noline{font:400 11px var(--relief-sans);color:var(--muted);
  white-space:normal;max-width:min(330px,46vw);line-height:1.5;text-align:right;
  box-shadow:inset 4px 4px 8px var(--dark),inset -3px -3px 6px var(--lite)}

/* 关键那一层底下贴的原文行。自成一行，缩进比它上面那层再深半级。 */
.relief-sitesrc{position:relative;display:grid;
  grid-template-columns:minmax(0,auto) minmax(0,1fr);
  align-items:center;gap:13px;margin:2px 0 4px;
  padding-left:calc(var(--d,0) * var(--step) + 13px)}
/* 原文也要带出处。上一层挂的是「这一层在哪被调用」，而原文常常在另一个文件里
   （调用在 tp_pm.c，被引用的判断在 tp_fw.c）—— 不单独标，读者会以为原文就在上一行
   说的那个位置。所以原文上方再压一条同样的凹刻小条。 */
.relief-sitequote{display:flex;flex-direction:column;align-items:flex-start;gap:6px;min-width:0;max-width:100%}
/* 原文：凹陷、等宽、保留空白。**转述会丢掉 return 1 和 return 3 的区别，
   而那个区别常常就是结论** —— 所以这一条只许贴原文，不许写「大意是」。 */
.relief-sitecode{padding:10px 15px;border-radius:10px;font:500 12px var(--relief-mono);
  color:var(--navy-d);line-height:1.9;white-space:pre;overflow-x:auto;
  background:var(--surf);
  box-shadow:inset 3px 3px 6px var(--dark),inset -2px -2px 5px var(--lite)}
/* 决定结论的那几个字，像用马克笔划出来 */
.relief-sitecode em{font-style:normal;padding:1px 5px;border-radius:5px;font-weight:700;
  background:linear-gradient(145deg,var(--hot-a),var(--hot-b));color:var(--on-hot)}
/* 两条链共用的那个东西，在原文里圈出来 —— 用的是和耦合扣子同一种圈，
   读者不用看图例就知道扣子说的是原文里这几个字。 */
.relief-sitecode u{text-decoration:none;color:var(--warn);font-weight:700;padding:0 4px;border-radius:5px;
  box-shadow:inset 0 0 0 1.5px var(--warn)}
.relief-sitecode b{color:var(--kw);font-weight:700}
.relief-sitecode i{font-style:normal;color:var(--muted);font-weight:400}
/* 「为什么这一行是关键」。凸起 = 这是人的判断，和凹陷的原文分得开。 */
.relief-sitewhy{justify-self:start;max-width:min(360px,100%);padding:8px 13px;border-radius:11px;
  --off:4px;--blur:9px;font:500 11.5px var(--relief-sans);line-height:1.55;
  background:linear-gradient(145deg,var(--hot-a),var(--hot-b));color:var(--on-hot);
  box-shadow:4px 4px 9px var(--dark),-4px -4px 9px var(--lite)}
/* 耦合扣子。同一个名字的扣子出现在两处 = 那两处是同一个东西 ——
   「A 的私有步骤产出了 B 依赖的东西」这类耦合，靠的就是认出这枚扣子。
   为什么不画连线：两端常常隔着十几行，线一长就得跨屏，扣子不会。 */
.relief-sitepin{font:700 10.5px var(--relief-mono);color:var(--warn);white-space:nowrap;
  padding:4px 9px;border-radius:999px;background:var(--surf);
  box-shadow:inset 0 0 0 1.5px var(--warn),2px 2px 5px var(--dark),-2px -2px 4px var(--lite)}
.relief-sitefn.relief-hot .relief-sitepin{color:var(--on-hot);background:transparent;
  box-shadow:inset 0 0 0 1.5px var(--on-hot)}
/* 失败往回传到哪。调用往下走画了，但「这一行的返回值决定了后面全挂」里
   「后面全挂」那一半，第一版只写在文字里。
   画法照 anthropic §18 的约定：**这一行放在它真正落回的那一层的缩进上**，
   横着的那道槽从出事那层的缩进一直伸回落点，箭头朝左 —— 槽的长度就是
   这个返回值往上穿过了几层。槽是凹的：它是一条通道，和缩进槽一个意思。 */
.relief-siteret{position:relative;display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  margin:2px 0 4px;padding-left:calc(var(--d,0) * var(--step))}
.relief-siteretbar{position:relative;flex:none;height:7px;border-radius:4px;
  width:calc(var(--span,1) * var(--step));background:var(--surf);
  box-shadow:inset 2px 2px 4px var(--dark),inset -2px -2px 3px var(--lite)}
.relief-siteretbar::before{content:"";position:absolute;left:-3px;top:50%;transform:translateY(-50%);
  border:6px solid transparent;border-left:0;border-right:8px solid var(--warn)}
.relief-siteret b{font:700 12px var(--relief-mono);color:var(--warn)}
.relief-siteret i{font-style:normal;font:400 12px var(--relief-sans);color:var(--ink)}

/* 窄屏。第一版在 390px 宽下有 9 个部件冲出图板：药丸和出处条都是 nowrap，
   两列 grid 挤不下就往右溢。runner 的第二视口默认 1024，所以没被报出来。
   窄屏下出处换到函数下面一行，引导点线不画（上下排了就没有要连的空白），
   缩进也收窄 —— 七层每层 26px 在一块 250px 的图板里就占掉了大半。 */
@media (max-width:640px){
  .relief-site{--step:14px}
  .relief-siterow{grid-template-columns:minmax(0,1fr);gap:4px}
  .relief-siterow::after{display:none}
  .relief-sitefn{white-space:normal;flex-wrap:wrap;row-gap:2px}
  .relief-siteat,.relief-siteat.relief-noline{justify-self:start;white-space:normal;overflow-wrap:anywhere;text-align:left}
  .relief-sitesrc{grid-template-columns:minmax(0,1fr);padding-left:calc(var(--d,0) * var(--step) + 6px)}
  .relief-sitecode{max-width:100%}
  .relief-sitewhy{justify-self:start;max-width:100%}
}

/* 函数时序图。生命线是一道竖凹槽 —— 参与者在时间里的那条通道；
   激活块是压在槽上的凸块 —— 这段时间它在栈上。 */
.relief-seq{display:grid;position:relative;row-gap:0;column-gap:0;padding-bottom:8px}
.relief-seqhead{grid-row:1;align-self:end;padding:11px 10px;border-radius:13px;text-align:center;
  --off:4px;--blur:9px;margin:0 7px 14px}
.relief-seqhead b{display:block;font:700 12.5px var(--relief-mono);color:var(--navy-d)}
.relief-seqhead i{display:block;font-style:normal;font:400 10.5px var(--relief-sans);color:var(--muted);margin-top:3px}
.relief-life{justify-self:center;width:9px;border-radius:999px;
  box-shadow:inset 3px 3px 6px var(--dark),inset -2px -2px 5px var(--lite)}
.relief-act{justify-self:center;width:24px;border-radius:8px;z-index:1;
  box-shadow:4px 4px 8px var(--dark),-4px -4px 8px var(--lite);background:var(--surf)}
.relief-act.relief-hot{background:linear-gradient(145deg,var(--hot-a),var(--hot-b))}
/* 消息：标签居中在线的上方，不压住任何激活块。
   箭头画在线的终点那一端 —— 第一版把两个箭头形状写反了，
   所有正向消息的箭头都指着起点，图整个读反。 */
.relief-seqmsg{z-index:2;align-self:center;display:flex;flex-direction:column;
  align-items:center;gap:5px;width:100%}   /* 左右内缩由每条消息按跨度算，写在行内 */
.relief-seqmsg .relief-lbl2{font:500 11.5px var(--relief-mono);color:var(--muted);white-space:nowrap;
  padding:4px 11px;border-radius:999px;background:var(--surf);
  box-shadow:inset 3px 3px 6px var(--dark),inset -2px -2px 5px var(--lite)}
.relief-seqline{display:flex;align-items:center;width:100%;gap:0}
.relief-seqline svg{flex:none;filter:drop-shadow(0 -1.1px 0 var(--hi)) drop-shadow(0 2px 1.4px var(--lo))}
.relief-seqline .relief-ln{flex:1;height:7px;border-radius:999px;
  box-shadow:inset 2px 2px 5px var(--dark),inset -2px -2px 4px var(--lite)}

/* DMA 描述符链。每块描述符是凸的，next 指针是凹槽 ——
   最后一块的 next 是空的，所以那一格画成凹陷的死区，
   「链在这里结束」和「这里有个东西」用形状就分开了。 */
.relief-dchain{display:flex;align-items:stretch;gap:0;overflow-x:auto;padding:4px 0}
.relief-desc{min-width:186px;flex:none;border-radius:16px;padding:14px 16px;--off:5px;--blur:10px}
.relief-desc h4{margin:0 0 10px;font:700 12px var(--relief-mono);color:var(--muted);letter-spacing:.05em}
.relief-desc dl{margin:0;display:grid;grid-template-columns:auto 1fr;gap:5px 10px;align-items:baseline}
.relief-desc dt{font:500 11px var(--relief-sans);color:var(--muted)}
.relief-desc dd{margin:0;font:700 12.5px var(--relief-mono);color:var(--navy-d);text-align:right}
.relief-desc dd.relief-null{color:var(--muted);font-weight:500}
.relief-desc.relief-live{box-shadow:5px 5px 11px var(--dark),-5px -5px 11px var(--lite),inset 0 0 0 2px var(--orange)}
.relief-dlink{width:44px;flex:none;display:grid;place-items:center}
.relief-dlink svg{filter:drop-shadow(0 -1.2px 0 var(--hi)) drop-shadow(1px 2px 1.5px var(--lo))}
.relief-dend{width:44px;flex:none;display:grid;place-items:center}
.relief-dend i{width:26px;height:9px;border-radius:999px;
  box-shadow:inset 3px 3px 6px var(--dark),inset -2px -2px 5px var(--lite)}

/* 电源域：域套域套设备。深度就是包含关系，不用画线。 */
.relief-pd{display:grid;gap:13px}
.relief-pdom{padding:16px 17px 18px;border-radius:21px}
.relief-pdname{font:700 12.5px var(--relief-sans);color:var(--muted);letter-spacing:.05em;
  margin-bottom:12px;display:flex;align-items:center;gap:9px;flex-wrap:wrap}
.relief-pdname em{font-style:normal;font-weight:500;font-size:11px;font-family:var(--relief-mono)}
.relief-pdname .relief-alwayson{padding:3px 10px;border-radius:999px;font:700 10.5px var(--relief-mono);
  color:var(--on-hot);background:linear-gradient(145deg,var(--hot-a),var(--hot-b))}

/* ═══════════════ 排查用部件 ═══════════════ */

/* 锁：拿在手里的是凸的，空闲的是凹的空槽。
   形状直接说明「有没有被占」，不用读文字也不用图例。 */
.relief-locks{display:grid;grid-template-columns:1fr auto 1fr;gap:16px;align-items:start}
.relief-lane{padding:15px 16px 17px;border-radius:20px}
.relief-lanename{font:700 13px var(--relief-mono);color:var(--navy-d);margin-bottom:11px}
.relief-lock{padding:11px 15px;border-radius:13px;margin-bottom:9px;--off:4px;--blur:9px;
  display:flex;align-items:center;gap:10px}
.relief-lock b{font:700 13px var(--relief-mono);color:var(--navy-d)}
.relief-lock i{font-style:normal;font:400 11.5px var(--relief-sans);color:var(--muted);margin-left:auto}
.relief-lock.relief-free b{color:var(--muted);font-weight:500}
.relief-lock.relief-blocked{box-shadow:inset 5px 5px 10px var(--dark),inset -5px -5px 10px var(--lite),
  inset 0 0 0 2px var(--warn)}
.relief-cycle{align-self:center;text-align:center;padding:13px 16px;border-radius:16px;
  font:700 12px var(--relief-mono);color:var(--on-hot);white-space:nowrap;
  background:linear-gradient(145deg,var(--hot-a),var(--hot-b));
  box-shadow:5px 5px 11px var(--dark),-5px -5px 11px var(--lite)}
.relief-cycle span{display:block;font-weight:500;font-size:10.5px;opacity:.85;margin-top:4px;
  font-family:var(--relief-sans)}

/* 引用计数：对象活着是凸的，释放之后整块塌成凹陷。
   在凹的那一段还有人调 put/get，就是 use-after-free —— 图上是「往塌掉的地方伸手」。 */
.relief-ref{display:grid;grid-template-columns:132px 1fr;gap:9px 14px;align-items:center}
.relief-refop{font:600 12px var(--relief-mono);color:var(--navy-d);text-align:right}
.relief-refbar{display:flex;align-items:center;gap:10px;padding:9px 14px;border-radius:13px;
  --off:4px;--blur:9px;min-height:44px}
.relief-refbar b{font:700 13px var(--relief-mono);color:var(--navy-d);min-width:74px}
.relief-refbar i{font-style:normal;font:400 11.5px var(--relief-sans);color:var(--muted)}
.relief-refbar.relief-dead b{color:var(--muted)}
.relief-refbar.relief-uaf{box-shadow:inset 5px 5px 10px var(--dark),inset -5px -5px 10px var(--lite),
  inset 0 0 0 2px var(--warn)}
.relief-refbar.relief-uaf b{color:var(--warn)}
.relief-pip{width:13px;height:13px;border-radius:50%;flex:none;
  background:linear-gradient(145deg,var(--hot-a),var(--hot-b));
  box-shadow:2px 2px 4px var(--dark),-2px -2px 4px var(--lite)}

/* 竞态：两条泳道共用一条时间轴，竞态窗口是一条横跨两道的凹带。
   出事只发生在凹进去的那一段 —— 这正是图要说的唯一一件事。 */
.relief-race{position:relative;display:grid;row-gap:11px}
.relief-rlane{display:grid;align-items:center;column-gap:8px}
.relief-rname{font:700 12px var(--relief-mono);color:var(--navy-d);padding-right:10px;text-align:right}
.relief-rop{padding:9px 11px;border-radius:12px;--off:4px;--blur:8px;text-align:center;
  font:600 11.5px var(--relief-mono);color:var(--navy-d);white-space:nowrap}
.relief-rop.relief-boom{background:linear-gradient(145deg,var(--hot-a),var(--hot-b));color:var(--on-hot);
  box-shadow:4px 4px 9px var(--dark),-4px -4px 9px var(--lite)}
.relief-window{border-radius:16px;padding:11px 14px;margin:2px 0;
  font:600 11.5px var(--relief-sans);color:var(--warn);text-align:center;
  box-shadow:inset 5px 5px 10px var(--dark),inset -4px -4px 9px var(--lite),inset 0 0 0 2px var(--warn)}

/* 关卡链：每一道都可能挡住，挡住的现象各不相同 —— 右边那列才是这图的正文 */
.relief-gates{display:grid;grid-template-columns:44px 1fr 1fr;gap:0 14px;align-items:stretch}
.relief-gnum{font:700 13px var(--relief-mono);color:var(--muted);align-self:center;
  text-align:right;padding-bottom:9px}
.relief-gate2{border-radius:14px;padding:12px 16px;margin-bottom:9px;--off:5px;--blur:10px}
.relief-gate2 b{display:block;font:700 13.5px var(--relief-mono);color:var(--navy-d)}
.relief-gate2 i{display:block;font-style:normal;font:400 11.5px var(--relief-sans);color:var(--muted);margin-top:4px}
.relief-gate2.relief-stuck{background:linear-gradient(145deg,var(--hot-a),var(--hot-b));
  box-shadow:5px 5px 11px var(--dark),-5px -5px 11px var(--lite)}
.relief-gate2.relief-stuck b{color:var(--on-hot)}
.relief-gate2.relief-stuck i{color:var(--on-hot);opacity:.82}
.relief-symptom{border-radius:14px;padding:12px 16px;margin-bottom:9px;
  font:400 12px var(--relief-sans);color:var(--muted);line-height:1.6;
  box-shadow:inset 4px 4px 9px var(--dark),inset -3px -3px 8px var(--lite)}
.relief-symptom b{color:var(--navy-d);font-weight:700}

/* oops：原始 dump 放凹陷面板（它本来就是一块屏），右边逐行翻译 */
.relief-oops{display:grid;grid-template-columns:1fr 1fr;gap:18px;align-items:start}
.relief-dump{padding:16px 18px;border-radius:18px;font:500 12px var(--relief-mono);
  color:var(--navy-d);line-height:2;white-space:pre-wrap;overflow-x:auto}
.relief-dump em{font-style:normal;color:var(--warn);font-weight:700}
.relief-reads{display:grid;gap:9px}
.relief-read{padding:12px 15px;border-radius:14px;--off:4px;--blur:9px}
.relief-read b{display:block;font:700 12px var(--relief-mono);color:var(--navy-d);margin-bottom:4px}
.relief-read i{font-style:normal;font:400 12px var(--relief-sans);color:var(--muted);line-height:1.65}

/* 两个栈并排对比：调试时真正在做的事不是读一个栈，是拿好的那次跟崩的那次比。
   两边一样的帧压平成凹陷，只有不一样的那几帧凸起 —— 差异自己跳出来。 */
.relief-vs2{display:grid;grid-template-columns:1fr 1fr;gap:20px;align-items:start}
.relief-vs2 .relief-lanename{margin-bottom:11px}
.relief-vframe{border-radius:12px;padding:10px 14px;margin-bottom:7px;--off:4px;--blur:9px;
  font:600 12.5px var(--relief-mono);color:var(--navy-d);display:flex;align-items:center;gap:10px}
.relief-vframe.relief-same{box-shadow:inset 3px 3px 7px var(--dark),inset -3px -3px 7px var(--lite);
  color:var(--muted);font-weight:400}
.relief-vframe.relief-diff{box-shadow:4px 4px 9px var(--dark),-4px -4px 9px var(--lite),
  inset 0 0 0 2px var(--orange)}
.relief-vframe em{font-style:normal;font:400 11px var(--relief-sans);color:var(--muted);margin-left:auto}

/* 栈溢出：栈往低地址长，撞到警戒页就完。用一条纵向的量尺说明还剩多少。 */
.relief-ovf{display:grid;grid-template-columns:118px 1fr 104px;gap:0 14px}
.relief-ovfcell{border-radius:12px;padding:11px 15px;margin-bottom:6px;--off:4px;--blur:9px;
  font:600 12.5px var(--relief-mono);color:var(--navy-d);display:flex;align-items:center;gap:10px;min-height:44px}
.relief-ovfcell i{font-style:normal;font:400 11.5px var(--relief-sans);color:var(--muted);margin-left:auto}
.relief-ovfcell.relief-guard{box-shadow:inset 5px 5px 10px var(--dark),inset -4px -4px 9px var(--lite),
  inset 0 0 0 2px var(--warn)}
.relief-ovfcell.relief-guard i{color:var(--warn)}

/* ═══════════════ git 图部件 ═══════════════ */
/* 提交图：分支是一条横向的凹轨，提交是轨上的凸点。
   合并点给强调色 —— 读提交图的人找的就是「这两支在哪汇的」。 */
.relief-git{display:grid;gap:0;position:relative}
.relief-branch{display:grid;align-items:center;column-gap:0;padding:9px 0;
  grid-template-rows:auto}   /* 轨道和提交点同一行，靠 z-index 分层 */
.relief-bname{font:700 12.5px var(--relief-mono);color:var(--navy-d);padding-right:16px;text-align:right;white-space:nowrap}
.relief-bname span{display:block;font:400 10.5px var(--relief-sans);color:var(--muted);margin-top:3px}
.relief-track{position:relative;height:11px;border-radius:999px;
  box-shadow:inset 3px 3px 6px var(--dark),inset -2px -2px 5px var(--lite)}
.relief-commit{justify-self:center;width:34px;height:34px;border-radius:50%;z-index:1;
  display:grid;place-items:center;font:700 10px var(--relief-mono);color:var(--navy-d);
  background:var(--surf);box-shadow:4px 4px 9px var(--dark),-4px -4px 9px var(--lite)}
.relief-commit.relief-merge{background:linear-gradient(145deg,var(--hot-a),var(--hot-b));color:var(--on-hot)}
.relief-commit.relief-ghost{box-shadow:inset 3px 3px 7px var(--dark),inset -3px -3px 7px var(--lite);
  color:var(--muted);font-weight:500}
.relief-fork{justify-self:center;align-self:stretch;width:9px;border-radius:999px;
  box-shadow:inset 3px 3px 6px var(--dark),inset -2px -2px 5px var(--lite)}

/* 仓库拓扑：每个仓一块，能推的凸起、只读的凹陷 —— 形状就是权限 */
.relief-repos{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:15px}
.relief-repo{padding:16px 18px 18px;border-radius:20px}
.relief-repo h4{margin:0 0 9px;font:700 14px var(--relief-mono);color:var(--navy-d)}
.relief-repo p{margin:0 0 11px;font:400 12.5px var(--relief-sans);color:var(--muted);line-height:1.65}
.relief-repo.relief-readonly h4{color:var(--muted)}
.relief-caps{display:flex;flex-wrap:wrap;gap:7px}
.relief-cap{padding:4px 11px;border-radius:999px;font:700 11px var(--relief-mono);color:var(--navy-d);
  box-shadow:3px 3px 7px var(--dark),-3px -3px 7px var(--lite)}
.relief-cap.relief-no{color:var(--muted);font-weight:500;
  box-shadow:inset 3px 3px 6px var(--dark),inset -2px -2px 5px var(--lite)}

/* ═══════════════ 代码与图并排 ═══════════════
   图是为了让代码更直观。所以数据结构这类图，旁边必须贴着它对应的那段代码 ——
   读者不用在脑子里做映射，指着看就行。代码放凹陷面板(它是「原文」)，
   图放凸起(它是「对原文的解释」)。 */
.relief-codefig{display:grid;grid-template-columns:minmax(260px,0.85fr) 1.15fr;gap:20px;align-items:start}
.relief-code{padding:16px 18px;border-radius:18px;font:500 12.5px var(--relief-mono);
  color:var(--navy-d);line-height:1.95;white-space:pre;overflow-x:auto}
.relief-code em{font-style:normal;color:var(--warn);font-weight:700}
.relief-code b{color:var(--kw);font-weight:700}
.relief-code i{font-style:normal;color:var(--muted);font-weight:400}
.relief-figcap{margin-top:11px;font:400 12px var(--relief-sans);color:var(--muted);line-height:1.65}

/* 结构体内存布局：字段凸起，填充空洞凹陷（那里真的什么都没有），
   cache line 边界用一条横线标出来。 */
.relief-layout{display:grid;grid-template-columns:70px 1fr 78px;gap:0 12px}
.relief-off{font:500 11.5px var(--relief-mono);color:var(--muted);text-align:right;
  align-self:center;padding-bottom:6px}
.relief-fieldrow{border-radius:11px;padding:10px 14px;margin-bottom:6px;--off:4px;--blur:9px;
  display:flex;align-items:center;gap:11px;min-height:40px}
.relief-fieldrow b{font:700 12.5px var(--relief-mono);color:var(--navy-d)}
.relief-fieldrow i{font-style:normal;font:400 11.5px var(--relief-sans);color:var(--muted);margin-left:auto}
.relief-fieldrow.relief-hole{box-shadow:inset 4px 4px 9px var(--dark),inset -3px -3px 8px var(--lite)}
.relief-fieldrow.relief-hole b{color:var(--muted);font-weight:500}
/* 位域里落在坏地方的那个字段：描一圈警示色，不动底色。 */
.relief-fieldrow.relief-risk{box-shadow:4px 4px 9px var(--dark),-4px -4px 9px var(--lite),
  inset 0 0 0 2px var(--warn)}
.relief-fieldrow.relief-risk i{color:var(--warn)}

/* 联合体：所有成员从同一个字节起算，谁也不在谁后面。
   线性偏移表画不出这件事 —— 那种图的前提就是「一个接一个」。
   每个成员一行，都从第 2 列开始，横向占几格就是它几个字节。 */
.relief-ovl{display:grid;gap:8px 4px;align-items:center}
.relief-ovlname{font:700 12.5px var(--relief-mono);color:var(--navy-d);
  text-align:right;padding-right:14px;white-space:nowrap}
.relief-ovlno{font:500 10.5px var(--relief-mono);color:var(--muted);text-align:center;padding-bottom:4px}
.relief-ovlbar{border-radius:11px;--off:4px;--blur:9px;padding:9px 13px;min-height:42px;
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  font:700 12.5px var(--relief-mono);color:var(--navy-d)}
.relief-ovlbar i{font-style:normal;font:400 11px var(--relief-sans);color:var(--muted);text-align:right}
.relief-ovlbar.relief-hot{background:linear-gradient(145deg,var(--hot-a),var(--hot-b));
  box-shadow:4px 4px 9px var(--dark),-4px -4px 9px var(--lite)}
.relief-ovlbar.relief-hot b,.relief-ovlbar.relief-hot i{color:var(--on-hot)}
.relief-ovlbar.relief-hot i{opacity:.85}
/* 联合体尾巴上没被最短成员盖到的那几个字节 */
.relief-ovltail{border-radius:11px;min-height:42px;display:grid;place-items:center;
  font:500 11px var(--relief-sans);color:var(--muted)}

.relief-cl{grid-column:1/-1;height:0;border-top:2px dashed var(--warn);margin:3px 0 9px;position:relative}
.relief-cl span{position:absolute;right:0;top:-9px;font:700 10.5px var(--relief-mono);color:var(--warn);
  background:var(--surf);padding:0 8px}
.relief-sz{font:500 11.5px var(--relief-mono);color:var(--muted);align-self:center;padding-bottom:6px}

/* 三种关系：嵌入是套在凹槽里，指针是连到外面，链表是链上的挂钩 */
.relief-rel{display:grid;grid-template-columns:repeat(auto-fit,minmax(272px,1fr));gap:16px}
.relief-relcard{padding:16px 17px 18px;border-radius:20px}
.relief-relcard h4{margin:0 0 4px;font:700 13.5px var(--relief-mono);color:var(--navy-d)}
.relief-relcard .relief-sub{font:400 11.5px var(--relief-sans);color:var(--muted);margin-bottom:13px;line-height:1.6}
.relief-outer{padding:12px 13px 13px;border-radius:15px;
  box-shadow:inset 5px 5px 10px var(--dark),inset -4px -4px 9px var(--lite)}
.relief-outer .relief-tag{font:700 11.5px var(--relief-mono);color:var(--muted);margin-bottom:9px;display:block}
.relief-inner{padding:10px 13px;border-radius:11px;font:700 12px var(--relief-mono);color:var(--navy-d);
  box-shadow:4px 4px 9px var(--dark),-4px -4px 9px var(--lite);background:var(--surf);margin-bottom:7px}
.relief-inner:last-child{margin-bottom:0}
.relief-inner.relief-ptrfield{color:var(--kw)}
.relief-relnote{margin-top:11px;font:400 11.5px var(--relief-sans);color:var(--muted);line-height:1.65}
.relief-relnote b{color:var(--navy-d)}
.relief-hop{display:grid;place-items:center;height:26px}
.relief-hop svg{filter:drop-shadow(0 -1.1px 0 var(--hi)) drop-shadow(0 2px 1.4px var(--lo))}

/* slab 对象越界：对象凸起，红区凹陷并描警示色，下一个对象再凸起。
   越界落在红区 = 检测得到；越过红区落进下一个对象 = 静悄悄把别人的数据改了。 */
.relief-slab{display:flex;align-items:stretch;gap:0;overflow-x:auto;padding:4px 0}
.relief-slot{border-radius:14px;padding:13px 15px;--off:5px;--blur:10px;min-width:150px;flex:none;text-align:center}
.relief-slot b{display:block;font:700 12.5px var(--relief-mono);color:var(--navy-d)}
.relief-slot i{display:block;font-style:normal;font:400 11px var(--relief-sans);color:var(--muted);margin-top:5px;line-height:1.5}
.relief-slot.relief-redzone{box-shadow:inset 5px 5px 10px var(--dark),inset -4px -4px 9px var(--lite),
  inset 0 0 0 2px var(--warn);min-width:96px}
.relief-slot.relief-redzone b{color:var(--warn)}
.relief-slot.relief-victim{box-shadow:5px 5px 11px var(--dark),-5px -5px 11px var(--lite),
  inset 0 0 0 2px var(--orange)}
.relief-gapx{width:7px;flex:none}

/* dmesg 时间线：打印是凸点，中间那段没有输出的空档是凹带 —— 空档才是线索 */
.relief-tl{display:grid;grid-template-columns:106px 1fr;gap:8px 14px;align-items:center}
.relief-ts{font:500 12px var(--relief-mono);color:var(--muted);text-align:right}
.relief-ev{padding:10px 15px;border-radius:12px;--off:4px;--blur:9px;
  font:500 12.5px var(--relief-mono);color:var(--navy-d);min-height:40px;display:flex;align-items:center;gap:10px}
.relief-ev i{font-style:normal;font:400 11.5px var(--relief-sans);color:var(--muted);margin-left:auto}
.relief-gapband{grid-column:2;border-radius:15px;padding:13px 16px;margin:3px 0;
  font:600 12px var(--relief-sans);color:var(--warn);text-align:center;
  box-shadow:inset 5px 5px 10px var(--dark),inset -4px -4px 9px var(--lite),inset 0 0 0 2px var(--warn)}

/* 图集页：一页看完所有框图，每条直接跳到它所在的那一页 */
.relief-gitems{display:grid;grid-template-columns:repeat(auto-fill,minmax(176px,1fr));gap:10px}
.relief-gitem{padding:12px 15px;border-radius:13px;text-decoration:none;
  font:600 13px var(--relief-sans);color:var(--navy-d);line-height:1.5;display:block}
.relief-gitem:hover{box-shadow:inset 4px 4px 9px var(--dark),inset -3px -3px 8px var(--lite)}
