/* ============================================================================
   NANK ART · 改稿层
   与 Vue 完全隔离：全部挂在 <body>#nk-root 下，position:fixed。
   🔴 绝不能往顶栏（Vue 管辖）里塞节点 —— 重渲染会静默清掉。
   🔴 原按钮上同时挂着 Vue 监听器 —— 用 document 捕获阶段拦截。

   坐标口径：--s = 100vw/1920 → 1 设计 px（Figma 画板 104:522 是 1920×1080）
   ========================================================================= */

/* ---------- 字体 ---------- */
/* MiSans VF：可变字体，wght 150–700（子集：拉丁 + GB2312 + 常用标点，2.46 MB） */
@font-face {
  font-family: 'MiSans VF';
  src: url('./fonts/MiSansVF.woff2') format('woff2-variations'),
       url('./fonts/MiSansVF.woff2') format('woff2');
  font-weight: 150 700;
  font-style: normal;
  font-display: block;
}
/* Stretch Pro：拉长效果来自连字 —— 输入 "NN" 由 liga 换成 NN.liga（一个横贯的宽 N） */
@font-face {
  font-family: 'Stretch Pro';
  src: url('./fonts/StretchPro.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: block;
}

:root {
  --s: calc(100vw / 1920);          /* 1 设计 px */
  --mg: calc(120 * var(--s));       /* 页边距 —— Figma 左右均 120 */
  /* 🔵 2026-10-17 用户要求「三个框横排」→ disc 必须加宽才装得下。
     原站 60rem=960 是单框 newsletter 用的；三框横排按 1080 基准给。 */
  --disc: calc(940 * var(--s));
  --ink: #fff;
  --ink-2: rgba(255, 255, 255, .60);
  --ink-3: rgba(255, 255, 255, .40);
  --paper: #F5F3F0;                 /* 二级页卡面（对齐原站项目详情页） */
  --dark: #17140F;
  --ease: cubic-bezier(.22, .61, .36, 1);
  --ui: 'MiSans VF', 'MiSans', 'ABCDiatype Plus Variable', system-ui, -apple-system, 'Microsoft YaHei', sans-serif;
  --disp: 'Stretch Pro', 'MiSans VF', sans-serif;
  --logo-dy: calc(-3.2 * var(--s));
}

/* ---------- 根容器：加载动画播完前完全不可见 ---------- */
#nk-root {
  position: fixed; inset: 0; z-index: 60;
  pointer-events: none;
  opacity: 0; visibility: hidden;
  transition: opacity .6s var(--ease), visibility 0s linear .6s;
}
#nk-root.nk-ready {
  opacity: 1; visibility: visible;
  transition: opacity .6s var(--ease), visibility 0s;
}
#nk-root > * { pointer-events: none; }
#nk-root button, #nk-root a, #nk-root input, #nk-root textarea { pointer-events: auto; }

.nk-ui { font-family: var(--ui); -webkit-text-fill-color: currentColor; color: var(--ink); }

/* 🔴 顶栏对齐 Figma：原站 s:px-80/s:py-40 → 左右 120 · 上 71 · 下 64
      （不改这条，左上 logo / 底栏 HOME / CONTACT ME 就和筛选行错位）
   ⚠️ 2026-10-07 用户要求：上下边距各缩小 2/5（保留 3/5）
      71 × 0.6 ≈ 43·  64 × 0.6 ≈ 38（向上取整）
      横向 --mg 不变（logo / 筛选行左右基线不能动）
   🔵 三个值都改成读 CSS 变量 → 可在 /admin「内容管理 › 样式」里改，
      后端保存后写 public/nank/site.js，前端自动覆盖（不用改代码）。 */
.nk-bar {
  padding: calc(var(--nk-bar-pt, 43) * var(--s)) var(--mg)
           calc(var(--nk-bar-pb, 38) * var(--s)) !important;
}
.nk-bar .nk-dead { pointer-events: none !important; }
/* CONTACT ME 换成 span 后原站 GL 不再画 → DOM 直接显示（覆盖顶栏容器的
   -webkit-text-fill-color:transparent）。
   🔴 boot 完成前必须隐身（html.nk-booted 由 nank.js afterBoot 加），
   否则和加载动画一起出现 */
.nk-bar .nk-domlabel {
  -webkit-text-fill-color: currentColor;
  color: rgba(255, 255, 255, .72);
  font-family: var(--ui);
  font-size: calc(15 * var(--s));
  letter-spacing: calc(-0.2 * var(--s));
  cursor: pointer;
  display: inline-block;
  /* 🔴 2026-10-22 R11：无条件可见 —— 之前 opacity:0 等 nk-booted，
     boot 一旦卡住/慢，底栏整排「消失」（用户实测）。
     GL 幽灵字问题已由 purgeGlBarTexts 根治，不再需要 boot 门禁。 */
  opacity: 1;
  transition: color .35s var(--ease);
}
/* nav 整体禁止换行（HOME / THANKS 必须同一基线）
   2026-10-07：原「/」分隔符已用 CSS 隐藏（用户反馈「多了一个斜杠」）。
   🔴 绝对不要改 bundle 把它渲染成 null —— Vue 读 vnode.type 会崩，
      整个 app 不挂载（canvas 消失、nk-booted 永远 false）。 */
.nk-bar nav { flex-wrap: nowrap; white-space: nowrap; }
.nk-bar nav > * { flex: 0 0 auto; }
/* 🔴 HOME / THANKS 之间的斜杠 —— 2026-10-17「双斜杠」根治
   根因：这个 span 同时被**原站 GL 烤进 canvas**（DOM 里 text-fill:transparent）。
   10-07 我为解决「顶飞」把 DOM 字色改回来 → GL 那层仍在画、且位置错开
   → 屏幕上叠出两个斜杠（上面一个、下面一个）。

   ✅ 正确解法：**只让 GL 不烤它，DOM 独占显示**
     · JS 已把 textContent 清空 → GL 读不到内容 → 烤不出字
     · DOM 侧改用 ::after 画斜杠 → 位置精确可控，只有一个
   ⚠️ 永远不要改 bundle 把这个节点渲染成 null —— Vue 读 vnode.type 会崩，
      整个 app 不挂载（canvas 消失、白屏）。 */
.nk-bar nav .nk-hidden-slash {
  display: inline-block !important;
  color: transparent;                /* 🔴 真实文字空+ 透明，杜绝任何一层重复显示 */
  -webkit-text-fill-color: transparent !important;
  width: calc(9 * var(--s));
  height: calc(15 * var(--s));
  position: relative;
  vertical-align: middle;
  align-self: center;
  font-size: calc(15 * var(--s));
  user-select: none;
}
.nk-bar nav .nk-hidden-slash::after {
  content: '/';
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  color: rgba(255, 255, 255, .55);
  -webkit-text-fill-color: rgba(255, 255, 255, .55);
  font-family: var(--ui);
  font-size: calc(15 * var(--s));
  line-height: 1;
  /* 🔴 2026-10-22 R10-P1-1：斜杠和 HOME/THANKS 一样必须等 boot 完才出现。
     之前 ::after 无条件可见 → 加载动画没结束左下角就冒出「/」
     （用户：「home和thanks中间的/会在加载动画未完成前出现」）。 */
  opacity: 0;
  transition: opacity .6s var(--ease);
}
html.nk-booted .nk-bar nav .nk-hidden-slash::after { opacity: 1; }
/* 任务㉙②：当前页对应的导航字亮起（HOME 常亮 / THANKS 在 /full 时亮） */
html.nk-booted .nk-bar .nk-domlabel.nk-current { color: #fff; }
/* 🔴 原站项目详情页（nk-detail）打开时藏底栏 DOM 字——GL 时代它们在 canvas(z10)
   被详情页自然盖住，DOM 化后浮到白卡上面了（用户实测） */
html.nk-detail .nk-bar .nk-domlabel {
  opacity: 0 !important;
  visibility: hidden !important;
  transition: opacity .3s var(--ease), visibility 0s linear .3s;
}

/* ---------- 加载进度条结束后的入场动画（用户：内容别闪现） ----------
   logo → 菜单 → 筛选行 → 版权 依次淡入下落。
   fill backwards = 延迟期用 from 态、结束后交还级联（不占住 hover 的 opacity）；
   基础 opacity:0 防 booted 前抢跑；黑洞/详情页 gate 是 !important 优先级更高。
   🔴 本块必须放在 .nk-logo:hover 等规则之前（同权重后者胜，hover 才有效） */
/* 任务㉙⑤：统一为纯淡入 .6s（和底栏 nk-domlabel 的 .6s fade 同语言）。
   🔴🔴 2026-10-22 R12：**拆除全部 boot 隐藏门禁**（用户两次实测「底栏/菜单消失」）。
   之前 opacity:0 等 html.nk-booted —— boot 一旦卡住/慢/旧标签页，
   logo/菜单/筛选/版权整排「消失」。现在一律 opacity:1，
   入场动画保留（animation 淡入），但绝不让内容依赖 boot 才可见。 */
.nk-logo, .nk-menu, .nk-chips, .nk-copy { opacity: 1; }
.nk-logo { animation: nk-fade .6s var(--ease) 0s backwards; }
.nk-menu { animation: nk-fade .6s var(--ease) .06s backwards; }
.nk-chips { animation: nk-fade .6s var(--ease) .12s backwards; }
.nk-copy { animation: nk-fade .6s var(--ease) .18s backwards; }
@keyframes nk-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* ---------- 状态类 ---------- */
/* 黑洞（联系我）打开 → 收起右上小导航 + 筛选行，否则压在黑洞上穿模
   🔴 状态类用 nk-hole-on（html.nk-hole 会被 .nk-hole 元素选择器命中 → 整页白）
   🔴 任务㉙③：visibility 延迟只能放在隐藏方向（gate 规则内）——放 base 规则里
      显示方向也会被延迟 .45s → 元素隐形淡完 .45s 后「全 opacity 弹出」（闪现真凶） */
.nk-menu, .nk-chips { transition: opacity .45s var(--ease), visibility 0s linear 0s; }
/* 🔴🔴 2026-10-18 修正：原来黑洞打开时把 .nk-menu 也隐藏了
   （visibility:hidden + pointer-events:none !important），
   结果用户在黑洞里**没法换页**（用户报「点 ABOUT 没反应、还串页」）。
   实测：内联 pointerEvents='auto' 但 computed='none' —— 就是被这条 !important 覆盖的。
   ✅ 现在：顶栏菜单**保持可见可点**（要能换页），
      只隐藏筛选行和版权（它们在黑洞里是干扰，且不负责导航）。 */
html.nk-hole-on .nk-chips,
html.nk-hole-on .nk-copy { opacity: 0 !important; visibility: hidden !important; pointer-events: none !important;
  transition: opacity .45s var(--ease), visibility 0s linear .45s; }
/* 菜单：提到黑洞之上，保持可点 */
html.nk-hole-on .nk-bar { z-index: 40 !important; }
/* 🔴 2026-10-22 R17：CJK 回退后首页烤字变 DOM 可见，黑洞/详情打开时
   会从透明洞体/白卡边缘穿透出来。按「是否在白卡内」判定：
   白卡外的 GL 文字全藏，白卡内（描述/标签）不受影响。 */
html.nk-hole-on [data-gl="text"],
html.nk-detail [data-gl="text"]:not([data-gl="sheet"] *) {
  opacity: 0 !important; visibility: hidden !important;
}
html.nk-hole-on .nk-menu { opacity: .5 !important; pointer-events: auto !important;
  transition: opacity .35s var(--ease); }
html.nk-hole-on .nk-menu:hover { opacity: 1 !important; }
html.nk-hole-on .nk-logo { opacity: .4 !important; pointer-events: auto !important; }

/* 原站项目详情页（点卡片出来的白卡）打开 → 它才是最高层，我们的家具全部让位
   🔴 .nk-logo / .nk-scrim 也要藏 —— #nk-root z60 > 原站 sheet z40，不藏就浮在白卡上 */
.nk-menu, .nk-chips, .nk-copy { transition: opacity .45s var(--ease), visibility 0s linear 0s; }
.nk-logo, .nk-scrim { transition: opacity .45s var(--ease), visibility 0s linear 0s; }
html.nk-detail .nk-menu,
html.nk-detail .nk-chips,
html.nk-detail .nk-copy,
html.nk-detail .nk-logo,
html.nk-detail .nk-scrim { opacity: 0 !important; visibility: hidden !important; pointer-events: none !important;
  transition: opacity .45s var(--ease), visibility 0s linear .45s; }

/* 我们自己的二级页白卡（ABOUT/JOURNEY/SKILLS）打开 → 同样让位 */
html.nk-sheet-on .nk-menu,
html.nk-sheet-on .nk-chips,
html.nk-sheet-on .nk-copy,
html.nk-sheet-on .nk-logo,
html.nk-sheet-on .nk-scrim { opacity: 0 !important; visibility: hidden !important; pointer-events: none !important;
  transition: opacity .45s var(--ease), visibility 0s linear .45s; }

/* 非首页（/full 等）不显示筛选行 */
html:not(.nk-home) .nk-chips { display: none !important; }

/* ================= 0 · 顶部黑色渐变（往下延伸盖住筛选行） ================= */
.nk-scrim {
  position: fixed; left: 0; right: 0; top: 0;
  height: calc(330 * var(--s));
  z-index: 2;
  background: linear-gradient(to bottom,
    rgba(0, 0, 0, .95) 0%,
    rgba(0, 0, 0, .78) 42%,
    rgba(0, 0, 0, .42) 72%,
    rgba(0, 0, 0, 0) 100%);
}

/* 底部黑色渐变：窄屏卡片直达底缘，托住底栏文字。
   🔴 挂在 body（不在 #nk-root 内），z30：canvas(10) < 渐变 < 原站底栏(40)
   —— 否则会把 HOME/THANKS/CONTACT ME 一起盖暗 */
.nk-scrim-b {
  position: fixed; left: 0; right: 0; bottom: 0;
  height: 150px;
  z-index: 30;
  display: none;
  pointer-events: none;
  background: linear-gradient(to top,
    rgba(0, 0, 0, .92) 0%,
    rgba(0, 0, 0, .55) 45%,
    rgba(0, 0, 0, 0) 100%);
}
@media (max-width: 720px) { .nk-scrim-b { display: block; } }

/* ================= 1 · 左上签名（Stretch Pro，N 靠连字拉长） ================ */
.nk-logo {
  position: fixed;
  left: calc(121 * var(--s));
  top: calc(74 * var(--s) + var(--logo-dy));
  z-index: 3;
  font-family: var(--disp);
  font-size: calc(var(--nk-logo-fs, 22) * var(--s));
  line-height: 1;
  /* 🔵 R7-P3-A：原来是 -0.8*s（@1512 渲染 -0.63px），
     3x 放大能看到 N 与 A 的斜边几乎贴在一起，「NANK」被误读成「NΛNK」。
     收到 -0.15*s，消除粘连。*/
  letter-spacing: calc(-0.15 * var(--s));
  font-weight: 400;
  color: #fff;
  text-decoration: none;
  font-variant-ligatures: common-ligatures discretionary-ligatures;
  font-feature-settings: 'liga' 1, 'dlig' 1;
  white-space: nowrap;
  cursor: pointer;
  transition: opacity .3s var(--ease);
}
.nk-logo:hover { opacity: .72; }

/* ================= 2 · 右上二级页菜单（用户：加大） ================= */
.nk-menu {
  position: fixed;
  top: calc(74 * var(--s) + var(--logo-dy));
  right: var(--mg);
  z-index: 3;
  display: flex; flex-direction: column; align-items: flex-end;
  text-align: right;
  font-family: var(--ui);
  font-size: calc(18 * var(--s));
  line-height: calc(22 * var(--s));
  letter-spacing: calc(-0.80 * var(--s));
  font-weight: 380;
}
.nk-menu button {
  background: none; border: 0; padding: 0; margin: 0;
  font: inherit; letter-spacing: inherit; color: var(--ink-2);
  cursor: pointer;
  transition: color .3s var(--ease);
}
.nk-menu button:hover { color: var(--ink); }
.nk-menu button[aria-current] { color: var(--ink); }
.nk-menu button > .nk-caret { display: none; }
.nk-menu button[aria-current] > .nk-caret { display: inline; }

/* ================= 3 · 筛选行（Spline 液态玻璃） =================
   Figma：@(120,231) 高 38.9 间距 8；21.7px lh28.8 ls −1.30；pad 11
   液态玻璃：backdrop blur + 高光内描边；悬停/选中靠 height/padding 生长
   （transform scale 不影响布局挤不开邻居）+ 弹簧曲线 → 平滑挤压其它标签 */
:root { --spring: cubic-bezier(.34, 1.42, .46, 1); }
.nk-chips {
  position: fixed;
  left: var(--mg);
  right: calc(var(--mg) + 140 * var(--s));
  top: calc(231 * var(--s));
  z-index: 3;
  display: flex; flex-wrap: wrap;
  gap: calc(8 * var(--s)) calc(8 * var(--s));
  font-family: var(--ui);
  font-size: calc(18.5 * var(--s));
  line-height: calc(24 * var(--s));
  letter-spacing: calc(-1.10 * var(--s));
}
.nk-chip {
  position: relative; z-index: 0;   /* 建 stacking context：::before(-1) 垫在文字下 */
  height: calc(34 * var(--s));
  display: inline-flex; align-items: center;
  padding: 0 calc(10 * var(--s));
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, .16);
  /* 🔴 background 不能用 gradient——CSS 过渡不了 gradient→gradient（点亮瞬跳的
     真凶）。底色用可过渡的平色，白渐变挪到 ::before 用 opacity 过渡 */
  background: rgba(255, 255, 255, .10);
  -webkit-backdrop-filter: blur(14px) saturate(1.5);
  backdrop-filter: blur(14px) saturate(1.5);
  color: var(--ink-2);
  font-family: var(--ui);
  font-size: inherit; letter-spacing: inherit; font-weight: 250;
  cursor: pointer;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .22),
              inset 0 -1px 0 rgba(255, 255, 255, .05),
              0 4px 18px rgba(0, 0, 0, .35);
  will-change: height, padding;
  transition: height .5s var(--spring), padding .5s var(--spring),
              background .35s var(--ease), color .3s var(--ease),
              border-color .35s var(--ease), box-shadow .35s var(--ease);
}
.nk-chip:hover {
  color: var(--ink);
  border-color: rgba(255, 255, 255, .34);
  background: rgba(255, 255, 255, .17);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .32),
              inset 0 -1px 0 rgba(255, 255, 255, .08),
              0 4px 18px rgba(0, 0, 0, .35), 0 0 24px rgba(255, 255, 255, .16);
}
.nk-chip:active { transition-duration: .15s; filter: brightness(1.22); }
/* 任务㉙①：选中态高亮改为「滑动拇指」——白胶囊在筛选行底下滑到选中项
   （segmented-control 模式），不再有逐 chip 的 ::before 淡入。
   🔴 font-weight 必须与未选中一致（用户：加粗造成邻居位移） */
.nk-chip[aria-pressed="true"] {
  border-color: transparent;
  color: #0a0a0a;
  /* 选中项玻璃全撤：拇指从底下滑过来时不能隔着磨砂玻璃看（会糊） */
  background: transparent;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  box-shadow: none;
}
.nk-chip[aria-pressed="true"]:hover { color: #000; }
/* 滑动拇指：JS（moveThumb）按选中 chip 的 offsetLeft/Width 定位，
   transform+width 走弹簧曲线 —— 点亮/熄灭/换位都是同一条滑行动画 */
.nk-chip-thumb {
  position: absolute; top: 0; left: 0; z-index: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #ffffff 0%, #e8e6e2 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .9),
              inset 0 -2px 4px rgba(0, 0, 0, .12),
              0 0 28px rgba(255, 255, 255, .22);
  opacity: 0;
  pointer-events: none;
  transition: transform .5s var(--spring), width .5s var(--spring),
              height .5s var(--spring), opacity .3s var(--ease);
  will-change: transform, width, height;
}
/* 窄屏「···」缩略钮（capNarrowChips 注入）：纯指示，不可点 */
.nk-chip-more {
  display: inline-flex; align-items: center;
  height: 24px; padding: 0 6px;
  color: var(--ink-3);
  font-family: var(--ui); font-size: 13px; letter-spacing: 1px;
  pointer-events: none; user-select: none;
}

/* ================= 4 · 底中版权 ================= */
/* 宽屏：HOME 行下方（bottom 24），字号更小、透明度更低（用户指定） */
.nk-copy {
  position: fixed;
  left: 50%; bottom: calc(24 * var(--s));
  transform: translateX(-50%);
  z-index: 3;
  font-family: var(--ui);
  font-size: calc(10.5 * var(--s));
  line-height: calc(15 * var(--s));
  letter-spacing: calc(-0.2 * var(--s));
  font-weight: 250;
  color: rgba(255, 255, 255, var(--nk-copy-op, .30));
  white-space: nowrap;
}
/* 备案号 → 工信部备案查询链接（颜色跟随版权行，hover 微亮） */
.nk-copy .nk-beian { color: inherit; text-decoration: none; }
.nk-copy .nk-beian:hover { color: rgba(255, 255, 255, .55); }

/* ================= 5 · 卡片顶部的「分类 + 年份」标签 =================
   终裁（任务㉘）：走 f.showTitles()（和卡片标题同一管线），随卡形变 100% 跟卡。
   span 挂在 article 内（Ko 栅格化要元素可见），DOM 字用 text-fill transparent 藏。
   无独立 CSS —— 样式全在 nank.js 内联。历史 DOM 方案死因见日记忆 2026-10-07。 */
/* GL 卡片区的 DOM 文字禁选（消除 I-beam 文本光标） */
article[data-gl="card"] { -webkit-user-select: none; user-select: none; }

/* ================= 5b · 卡片轨道垂直偏移 =================
   用户诉求（2026-10-07）：卡片顶部的「分类+年份」角标因3D 透视陷进卡面，
   整排卡片需整体下移一点，且不得压到底栏 HOME/THANKS、CONTACT ME。

   做法：.gl（canvas 所在的 fixed 容器，z10）整体 translateY。
   为什么用它 —— 卡片面是 WebGL 画的，DOM article 只是同步占位、
   改它的 top 不动画面；场景节点（f.core.over / camera）每帧被原站
   tick 重算，注入即被覆盖。canvas 容器是唯一稳定把手。
   安全性：body 背景是纯黑 #000，下移后顶部露出的空白即黑底，无缝。
   换算：位移量 = calc(var(--nk-rail-dy, 0) * var(--s))，--s 为缩放单位，
   1920 基准下 --s = 1px。底部余量见 tools/measure-rail-shift.cjs。 */
:root { --nk-rail-dy: 30; }
.gl { transform: translateY(calc(var(--nk-rail-dy, 0) * var(--s))); }
/* 详情页/黑洞期间轨道已隐藏，不需要偏移 */
html.nk-detail .gl,
html.nk-blackhole .gl { transform: none; }
/* 🔴 2026-10-22 R10-P0-2：矮窗高度自适应（用户：「页面变矮后卡片下方裁切」）。
   GL 整层下移 railDy 在视口变矮时会把卡片底部推出视口（实测 ~510px 高窗
   位移 22px → 卡片标题被裁一半）。高度 ≤700px 时位移归零，贴回设计位置。 */
@media (max-height: 700px) {
  .gl { transform: none !important; }
}

/* ================= 6 · 二级页（右上 ABOUT/JOURNEY/SKILLS） =================
   样式对齐原站「点卡片出来的项目详情页」：白色圆角大卡从底部升起。
   z-index 高于菜单/筛选行/版权 → 盖住所有内容。带退出按钮，点黑边也能退。 */
.nk-sheet {
  position: fixed;
  left: calc(8 * var(--s)); right: calc(8 * var(--s)); bottom: 0;
  top: calc(30 * var(--s));
  z-index: 8;
  background: var(--paper); color: var(--dark);
  border-radius: calc(34 * var(--s)) calc(34 * var(--s)) 0 0;
  transform: translateY(103%);
  transition: transform .72s var(--ease);
  overflow: auto; overscroll-behavior: contain;
  padding: calc(64 * var(--s)) var(--mg) calc(96 * var(--s));
  scrollbar-width: none;
}
.nk-sheet.nk-open { transform: none; }
.nk-sheet::-webkit-scrollbar { width: 0; height: 0; }

.nk-sheet-close {
  position: fixed;
  top: calc(28 * var(--s)); right: calc(28 * var(--s));
  z-index: 9;
  width: calc(40 * var(--s)); height: calc(40 * var(--s));
  border-radius: 999px;
  background: var(--dark); border: 0; padding: 0; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  color: #fff;
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .4s var(--ease), transform .3s var(--ease), visibility 0s linear .4s;
}
.nk-sheet-close svg { width: calc(15 * var(--s)); height: calc(15 * var(--s)); display: block; }
.nk-sheet-close:hover { transform: scale(1.08); }
html.nk-sheet-on .nk-sheet-close {
  opacity: 1; visibility: visible; pointer-events: auto;
  transition: opacity .4s var(--ease), transform .3s var(--ease), visibility 0s;
}

.nk-sheet-head { display: flex; align-items: baseline; gap: calc(24 * var(--s));
  padding-bottom: calc(28 * var(--s));
  border-bottom: 1px solid rgba(23, 20, 15, .14); }
.nk-sheet-kicker { font-size: calc(12 * var(--s)); letter-spacing: calc(0.9 * var(--s));
  text-transform: uppercase; color: rgba(23, 20, 15, .45); white-space: nowrap; }
.nk-sheet-title { font-family: var(--ui); font-size: calc(58 * var(--s)); line-height: 1.02;
  letter-spacing: calc(-2.2 * var(--s)); font-weight: 600; color: var(--dark); margin: 0; }
.nk-sheet-body { padding-top: calc(34 * var(--s)); }
.nk-sheet-lead { font-size: calc(24 * var(--s)); line-height: 1.42;
  letter-spacing: calc(-0.7 * var(--s)); color: var(--dark);
  max-width: calc(760 * var(--s)); margin: 0 0 calc(22 * var(--s)); font-weight: 450; }
.nk-sheet-note { font-size: calc(16 * var(--s)); line-height: 1.7;
  letter-spacing: calc(-0.3 * var(--s)); color: rgba(23, 20, 15, .58);
  max-width: calc(720 * var(--s)); margin: 0 0 calc(30 * var(--s)); }

.nk-ph { height: calc(150 * var(--s)); border-radius: calc(14 * var(--s));
  background: rgba(23, 20, 15, .07); margin-bottom: calc(14 * var(--s)); }
.nk-ph.tall { height: calc(300 * var(--s)); }
.nk-ph-row { display: grid; grid-template-columns: 1fr 1fr; gap: calc(14 * var(--s)); }
.nk-skill { display: flex; flex-wrap: wrap; gap: calc(10 * var(--s));
  margin: 0 0 calc(30 * var(--s)); padding: 0; list-style: none; }
.nk-skill li {
  height: calc(38 * var(--s)); display: inline-flex; align-items: center;
  padding: 0 calc(16 * var(--s));
  border-radius: 999px; border: 1px solid rgba(23, 20, 15, .28);
  font-size: calc(15 * var(--s)); letter-spacing: calc(-0.3 * var(--s));
  color: rgba(23, 20, 15, .78);
}

/* ================= 7 · 联系我（原站黑洞样式，无关闭按钮） ================= */
.nk-hole {
  /* 🔴🔴🔴 2026-10-22 R10-P0-2：高度自适应（用户：「高度自适应没有了」）。
     原站黑洞是 GL 画的、按视口**较小边**缩放；我们的 DOM 圆原来只跟
     --s=100vw/1920 走 → 窗口变矮时圆比视口还高，上下都被切。
     ✅ 黑洞子树内把 --s 换成 min(宽,高) 双约束（文字随圆等比缩小），
        --disc 显式重算（自定义属性在 :root 已求值，继承不会跟着变）。 */
  --s: min(calc(100vw / 1920), calc(100vh / 1080));
  --disc: calc(940 * min(calc(100vw / 1920), calc(100vh / 1080)));
  position: fixed;
  left: 50%; top: 50%;
  width: var(--disc); height: var(--disc);
  transform: translate(-50%, -50%);
  z-index: 8;
  display: flex; align-items: center; justify-content: center;
  opacity: 0;
  /* 🔴🔴🔴 2026-10-18 测试报告 P0-1（实测 r/R 斜向 = 1.413 ≈ √2，数学上证明是纯方形）：
     黑洞遮罩**缺 border-radius** → 整个「黑洞」是 740×740 的方块。
     这是全站最致命的问题：视觉气质从「Awwwards 获奖」掉到「后台模板」。
     ✅ 补这一行即可变正圆（测试 Agent 已注入验证：斜向比 1.416 → 1.002）。*/
  border-radius: 50%;
  /* 🔵🔵 R7-P1-C/D：ABOUT 裁 61px / JOURNEY 裁 133px（@1920）——
     内层是 overflow:hidden（正圆不需要滚动条），内容超出就被切，
     JOURNEY 最后一条时间线被从字形中间切断、完全不可读。
     ✅ 改回 overflow-y:auto：无内容时看不出差别（本来就圆角+隐藏滚动条），
        有溢出时用户能滚到。scrollbar-width:none 已在上方设置。*/
  overflow: hidden;
  /* 🔴🔴🔴 2026-10-22 R9-P0-3：容器背景改透明（用户截图实锤「底部有黑色
     圆垫没融入原生容器」）。
     实测（r9-5 纯 GL 截图）：GL 黑洞环内径 @1920×1125 ≈ 1020px、内部近纯黑；
     DOM 圆 940px 纯黑平面浮在 GL 圆里 → 交界处一条清晰的弧形分层线。
     ✅ 视觉圆完全交给 GL（原站本来就是这么画的），DOM 圆只留布局/裁切/
        交互职责（overflow hidden + 圆形边界）。GL 挂掉的最坏情况 =
        内容直接落在纯黑页面背景上，依然可读。 */
  background: transparent;
  transition: opacity .4s var(--ease);
}
.nk-hole.nk-open { opacity: 1; }

/* 🔴🔴 2026-10-17 用户报「输入框点不进去，点一下就弹出去了」。
   根因：GL canvas 容器 .gl 是 position:fixed; inset:0; z-index:10，
   而 .nk-hole 只有 z-index:8 → **canvas 铺满全屏盖在黑洞之上**，
   真实浏览器里所有点击都被 canvas 吃掉（headless/swiftshader 下 GL 不渲染，
   所以自动化测试反而"通过"了，掩盖了这个 bug）。
   ✅ 根治：黑洞打开期间彻底关掉 canvas 的指针事件 + 沉到最底层。
      二级页（nk-detail）同理，之前能点是因为 sheet 有 z-index 8 + GL 被隐藏。
   ⚠️ 教训：headless 测不出 GL 层遮挡，必须显式关 pointer-events。 */
html.nk-hole-on .gl,
html.nk-blackhole .gl {
  pointer-events: none !important;
  z-index: 0 !important;
}
/* 兜底：任何覆盖全屏的 GL 容器都关掉（防止将来原站再加一层） */
html.nk-hole-on .gl *,
html.nk-hole-on canvas { pointer-events: none !important; }
/* 黑洞自身必须完全可交互（#nk-root 默认是 pointer-events:none，只放开了部分标签） */
html.nk-hole-on .nk-hole,
html.nk-hole-on .nk-hole * { pointer-events: auto; }
html.nk-hole-on .nk-hole .nk-sb-track { pointer-events: auto; }
/* 🔴🔴 2026-10-22 R10-P0-1：关闭态整棵子树强制放行（!important 压住
   页面/graphWrap 上的内联 pointer-events:auto）。
   否则透明的 .nk-hole 圆盘浮在 GL 上，吃掉屏幕中心所有点击 →
   点作品卡片不弹二级页。 */
html:not(.nk-hole-on) .nk-hole,
html:not(.nk-hole-on) .nk-hole * { pointer-events: none !important; }
/* 🔵 排版对齐原站（用户 2026-10-09 截图对比）：
   原站副文案是「三行居中紧排」——靠 max-width 收窄 + 正常 word-wrap，
   不是靠大字距撑开。之前 ls -.36px + 无宽度限制 → 每行都撑满，换行很散。 */
.nk-hole-inner {
  /* 🔴🔴 2026-10-18 修「黑洞里切出一个方框」（用户截图实锤）
   *
   * 病根：`.nk-hole-inner` 是**矩形**（width:720 / height:calc(...)），
   * 它溢出圆形容器的部分（左右两侧的直角区域）被看到 →
   * 视觉上像「圆里嵌了个方框」。
   *
   * ✅ 修法（三条一起）：
   *   ① 内层改成**正圆**（宽高 = 圆直径 × 0.94），跟着黑洞圆走
   *   ② overflow 从 auto 改 hidden（正圆不需要滚动条）
   *   ③ 内容用 padding 内缩到圆的**内切圆**里（视觉上永远在圆内）
   *
   * 注意：position:relative 必须保留 —— 页内 absolute（技能图谱容器 /
   * 详情面板）以它为参照，之前没有它图谱会挤到右下角。 */
  position: relative;
  width: calc(var(--disc) * 0.94);
  height: calc(var(--disc) * 0.94);
  max-width: calc(92vw);
  max-height: calc(92vh);
  border-radius: 50%;
  /* 🔵🔵 R7-P1-C/D：原来是 overflow:hidden，ABOUT 裁 61px / JOURNEY 裁 133px
     （@1920 实测 scrollHeight-clientHeight）。
     后果：JOURNEY 最后一条时间线的正文被**从字形中间切断**（「19%。」只剩上半截），
     完全不可读 —— 内容溢出即永久丢失。
     ✅ 改 auto：正圆 + border-radius:50% 会把滚动条裁掉（视觉上看不出），
        scrollbar-width:none 已在上方设置，内容溢出时用户能滚到。*/
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* 🔴🔴 2026-10-19 用户截图实锤 + R8 实测根因修复
   *
   * 现象：ABOUT 页标题「ABOUT ME」上半被裁（用户箭头指出）。
   *
   * ⚠️ 这不是「文字放在容器外面」—— 实测 @1512：
   *    内容 556px 全部是 .nk-hole-inner 的**直接子元素**，
   *    没有叠加任何 div；但圆的内容区只有 504px（696 − 96.2×2 padding）
   *    → **内容比圆高 52px**，而 justify-content:center 会让超出量
   *    **平均分到两端** → 标题被顶进 padding 区（padding 区不在圆内）
   *    → overflow 把标题切掉一半。
   *
   * ✅ 修法（照搬原站 jesperlandberg 的机制）：
   *    原站的文本不在黑洞里，而在
   *      `fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2`
   *    的 shield 面板中 —— 内容超出时**整体向上溢出**，不裁顶部。
   *    这里等价做法：justify-content: flex-start + padding-top 加大
   *    → 内容从安全区顶部往下排，超出时溢出到底部（可滚），
   *       标题永远在圆内。
   *
   * ③ padding 13% → 10%：圆内容区从 504px 增到 556px（+52px），
   *    正好等于 ABOUT 的超出量 → 标题完整可见。
   */
  justify-content: flex-start;
  text-align: center;
  /* 🔵 内容安全区：10%（原 13%）。放宽到 70.7% 直径是为了容纳内容，
     10% 时 ABOUT/JOURNEY 都能完整放下，且仍在圆内。*/
  padding: 10%;
  font-family: var(--ui);
  color: var(--ink);
  -webkit-text-fill-color: currentColor;
  scrollbar-width: none;
}
.nk-hole-inner::-webkit-scrollbar { width: 0; height: 0; }
/* 🔴 2026-10-17 用户标注：标题上方那行 CONTACT 小标「不要这个」→ 整个移除 */
.nk-hole-kicker { display: none !important; }
.nk-hole-title { margin: 0 0 calc(18 * var(--s));
  font-size: calc(50 * var(--s)); line-height: 1.04;
  letter-spacing: calc(-1.2 * var(--s)); font-weight: 450; color: var(--ink); }
/* 🔵副文案对齐原站 newsletter页（2026-10-11 用户截图指定文案）：
   原站 class="text-14 leading-14 tracking-[-0.02em] max-w-[30rem] s:max-w-[32.5rem]"
   → 字号 14、line-height 14（1.0 倍）、字距 -0.02em、宽度 s:max-w-32.5rem。
   三行居中，不加 text-wrap:balance（原站没有，会改变断行位置）。 */
.nk-hole-lead {
  margin: 0 auto;
  /* 🔴🔴 2026-10-19 R5-P0-1（实测首段「从」字被圆切掉 20.7px）：
     圆在 dy 处的可用宽 = 2√(R²−dy²)，
     段落越靠上/下可用宽越窄；660 是按**矩形**定的宽度。
     ✅ 收到 480（2 行但每行短，落在圆的安全区内）。*/
  max-width: calc(480 * var(--s));
  font-size: calc(20 * var(--s));
  /* 🔴 R5-P1-3：行距比 1.00（=font-size）中文会贴成一片 → 提到 1.4 */
  line-height: calc(28 * var(--s));
  letter-spacing: calc(-0.28 * var(--s));
  font-weight: 400;
  color: rgba(255, 255, 255, .92);
}

/* ================= 联系表单 =================
   🔵 2026-10-17 用户指定：直接照 griflan.com/contact/ 的黑洞表单做，不要自己发挥。
      用户原话：「https://griflan.com/contact/ 那个黑洞里面的样式，你直接拿这边的这个好不好？
      我只需要 name、email、还有最后面的内容，这三个，横排三框，
      最下角放个提交按钮，稳定的，不要动效，悬停变个色就好了」

   ┌── 以下参数全部来自 griflan 实测 getComputedStyle + cssRules 原文 ──
   .input { --height:6.5rem; border-radius:.5rem; display:flex; gap:1.5rem;
            min-height:var(--height); padding:0 2rem; }
   .input::before { border:1px solid #fffddb; border-radius:inherit;
                    opacity:.1; inset:0; z-index:-1 }← 描边画在容器，不在input
   .input__label { opacity:.5; white-space:nowrap }
   .input__field { background:transparent; border:none; outline:none; width:100% }
   .input__text  { min-height:15rem }
   → rem 换算到本站 1920 基准：1rem = 16px → 6.5rem=104 · .5rem=8 · 2rem=32
   form class="flex flex-col gap-y-15"（flex-col = 竖排）
   BUT 用户要求「横排三框」→ 用 flex-wrap 横排，只保留 griflan 的视觉语言
   ================================================================== */

.nk-form {
  width: 100%;
  display: flex; flex-direction: column;
  /* 🔴🔴 2026-10-22 R15：用户「内容水平居中一下」——原来是 flex-start（整体
     贴左，提交按钮挂在左下角显歪）。✅ 整体居中：输入行限宽居中、按钮行居中。 */
  align-items: center;
  gap: calc(12 * var(--s));
  margin-top: calc(30 * var(--s));
}

/* ---------- 一行三个框（横排，用户要求） ---------- */
.nk-frow {
  /* 🔵 2026-10-17 用户要求：「第一排放 your name 跟 email，第二排放一个大一点的框
     就是 what do you need 那一行」→ 上排两列 + 下排整行一个大框。
     用 grid 而不是 flex：两列 1fr1fr / 下排 1fr，间距统一。 */
  width: 100%;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: calc(10 * var(--s));
  align-items: stretch;
}
/* 第三个框（内容）占满整行 */
.nk-fcell {
  /* 🔵 2026-10-17 用户要求三个框横排一行。
     griflan 原站是竖排（flex-col），框内 label 左 / input 右。
     改成三框横排后，每框只有 ~200px，框内再横排必然挤爆
     （实测 label 占 70px + gap，input 只剩 60px，placeholder 全换行）。
     ✅ 折中：保留 griflan 的框体视觉（圆角矩形 / 1px 描边画在容器上），
        框内改成「label 在上、input 在下」竖排 —— 水平空间全给输入。
     窄屏（@max720）三框换行成竖排时会自动回到 griflan 的横排形态。 */
  min-width: 0;
  display: flex; flex-direction: column;
  /* 🔴 2026-10-22 R17 用户：「还原一下表单的左对齐」——R16 把框内文字居中是
     理解错了（用户要的是整体在黑洞里居中，不是框内居中）。恢复左对齐。 */
  align-items: flex-start; justify-content: center;
  gap: calc(8 * var(--s));
  min-height: calc(74 * var(--s));
  padding: calc(14 * var(--s)) calc(16 * var(--s));
  border-radius: calc(8 * var(--s));   /* griflan: .5rem = 8px */
  position: relative;
  text-align: left;
}
/* 🔴 griflan 的描边画在容器 ::before 上（opacity .1 的 1px 线），不在 input 上。
   这样输入框 hover/focus 时容器尺寸不变，不会抖动。 */
.nk-fcell::before {
  content: '';
  position: absolute; inset: 0;
  border: 1px solid rgba(255, 255, 255, .34);   /* griflan 是 #fffddb @ .1，
                                                  但那在纯黑上几乎看不见，
                                                  这里提到 .34 保证可见 */
  border-radius: inherit;
  opacity: 1;
  pointer-events: none;
  z-index: 0;
  transition: border-color .35s ease, background-color .35s ease;
}
/* hover / focus：边框提亮（不做位移、不做动效 —— 用户明确要求） */
.nk-fcell:hover::before { border-color: rgba(255, 255, 255, .62); }
.nk-fcell:focus-within::before { border-color: rgba(255, 255, 255, .95); }

/* label（griflan 的 .input__label：opacity .5、nowrap） */
.nk-flabel {
  flex: none;
  font-size: calc(20 * var(--s));
  line-height: 1;
  letter-spacing: calc(0.4 * var(--s));
  text-transform: uppercase;
  color: var(--ink);
  opacity: .5;
  white-space: nowrap;
  transition: opacity .3s ease;
}
.nk-fcell:focus-within .nk-flabel { opacity: .95; }

/* input / textarea 本身：透明、无边框、撑满剩余空间 */
.nk-finput {
  flex: 1 1 auto; min-width: 0; width: 100%;
  display: block;
  appearance: none;
  background: transparent;
  border: none; outline: 0;
  font-family: var(--ui);
  font-size: calc(20 * var(--s));
  line-height: 1.4;
  letter-spacing: -0.01em;
  color: var(--ink);
  -webkit-text-fill-color: currentColor;
  text-align: left;                   /* R17：恢复左对齐（用户：还原表单左对齐） */
  padding: 0;                     /* 🔴 归零：左右靠 cell 的 padding，上下靠 align-items:center */
  position: relative; z-index: 1;
  resize: none;
}
.nk-finput::placeholder { color: rgba(255, 255, 255, .38); }
.nk-fcell:focus-within .nk-finput::placeholder { color: rgba(255, 255, 255, .22); }
/* 🔵 第三个框（内容）：占满整行，输入区更矮但可换行几行 */
.nk-fcell--area { grid-column: 1 / -1; }
.nk-fcell--area .nk-finput {
  line-height: 1.5;
  height: calc(42 * var(--s));
  overflow-y: auto;
  /* 原生滚动条藏起来（macOS overlay 模式本来也不绘制） */
  scrollbar-width: none;
  scrollbar-color: transparent transparent;
}
.nk-fcell--area .nk-finput::-webkit-scrollbar { width: 0; height: 0; }
/* 自绘滚动条（纯白半透明，无彩虹 —— 用户明确不要彩色） */
.nk-sb-track {
  position: absolute; top: 20%; bottom: 20%;
  right: calc(6 * var(--s));
  width: calc(3 * var(--s));
  border-radius: 999px;
  background: rgba(255, 255, 255, .07);
  opacity: 0;
  transition: opacity .3s ease;
  pointer-events: none;
  z-index: 2;
}
.nk-sb-thumb {
  position: absolute; left: 0; right: 0;
  border-radius: 999px;
  background: rgba(255, 255, 255, .28);
  transition: background .25s ease;
}
.nk-fcell:hover .nk-sb-track,
.nk-fcell:focus-within .nk-sb-track { opacity: 1; }
.nk-sb-track:hover .nk-sb-thumb { background: rgba(255, 255, 255, .5); }
.nk-sb-track.dragging .nk-sb-thumb { background: rgba(255, 255, 255, .62); }

/* ---------- 提交按钮（griflan 红底白字，只变色不做动效） ---------- */
/* 🔴 2026-10-17 用户明确：「不要再尝试那种做动效了，悬停只要变个色就好了」 */
.nk-sendrow { margin-top: calc(6 * var(--s)); }
.nk-send {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  min-width: calc(150 * var(--s));
  height: calc(42 * var(--s));
  padding: 0 calc(22 * var(--s));
  border: 1px solid #fff;
  border-radius: calc(6 * var(--s));
  /* 🔴 2026-10-17 用户明确：「不要用这个红色，我这边是黑白灰三个颜色，
     没有用到这个橙色」→ 整站只用黑 / 白 / 灰。
     griflan 的红底白字换成：白底黑字，hover 反色（黑底白字），只过渡颜色。 */
  background: #fff;
  color: #000;
  font-family: var(--ui);
  font-size: calc(20 * var(--s));
  letter-spacing: 0;
  line-height: 1;
  cursor: pointer;
  /* 🔴 只过渡颜色 —— 无位移、无缩放、无遮罩扫过 */
  transition: background-color .25s ease, color .25s ease, border-color .25s ease;
}
.nk-send:hover  { background: #000; color: #fff; border-color: #fff; }  /* 反色 */
.nk-send:active { background: #e6e6e6; color: #000; }
.nk-send:focus-visible { outline: 2px solid rgba(255,255,255,.55); outline-offset: 3px; }
.nk-send:disabled { opacity: .45; cursor: default; }

/* Chrome 自动填充黄底盖掉 */
.nk-finput::-webkit-autofill,
.nk-finput::-webkit-autofill:hover,
.nk-finput::-webkit-autofill:focus {
  -webkit-text-fill-color: var(--ink) !important;
  -webkit-box-shadow: 0 0 0 1000px #000 inset !important;
  caret-color: var(--ink);
  transition: background-color 9999s ease-out;
}

@media (prefers-reduced-motion: reduce) {
  .nk-fcell::before, .nk-flabel, .nk-send, .nk-sb-track, .nk-sb-thumb { transition: none; }
}

/* 窄屏：两列挤不下 → 单列竖排 */
@media (max-width: 720px) {
  .nk-frow { grid-template-columns: 1fr; }
}


.nk-done { margin: calc(16 * var(--s)) 0 0; font-size: calc(14 * var(--s));
  letter-spacing: calc(-0.3 * var(--s)); color: var(--ink-2); }

/* ================= R13 自适应：卡片按视高定位 =================
   🔴🔴 2026-10-22 用户：「中心卡片按高度定位」——原站 s:h-[43.5svh] 本来就是
   高度驱动，但 s:max-h-[55rem] 是**宽度流体 rem**（html 字号 = vw/150）：
   竖窗（如 768×1024）下 max-h 只有 281px < 43.5svh=445px → 卡片被压成一条。
   ✅ 封顶改高度基（62svh），任何窗口比例下卡片都按视高走。
   ≤650px（Tailwind s: 断点）移动端竖排由原站 bundle 自己处理，不碰。 */
@media (min-width: 650px) {
  article[data-gl="card"] {
    height: 43.5svh !important;
    max-height: 62svh !important;
    width: auto !important;
  }
}

/* ================= ABOUT 白卡富文本（用户后台自己排版） ================= */
.nk-about-html {
  color: #2a2a2e;
  font-family: var(--ui);
  font-size: calc(17 * var(--s));
  line-height: 1.75;
}
.nk-about-html p { margin: 0 0 calc(14 * var(--s)); max-width: none; color: inherit; }
.nk-about-html h2, .nk-about-html h3 {
  margin: calc(22 * var(--s)) 0 calc(10 * var(--s));
  font-size: calc(22 * var(--s));
  font-weight: 600;
  color: #111;
  letter-spacing: calc(-0.3 * var(--s));
}
.nk-about-html ul, .nk-about-html ol { margin: 0 0 calc(14 * var(--s)); padding-left: 1.3em; }
.nk-about-html li { margin: 0 0 calc(6 * var(--s)); }
.nk-about-html a { color: #111; text-underline-offset: 3px; }
.nk-about-html strong { font-weight: 600; color: #111; }
.nk-about-html img { max-width: 100%; border-radius: calc(8 * var(--s)); margin: calc(10 * var(--s)) 0; }
.nk-about-html blockquote {
  margin: calc(12 * var(--s)) 0;
  padding-left: calc(14 * var(--s));
  border-left: 2px solid #ddd;
  color: #555;
}
.nk-about-html table { width: 100%; border-collapse: collapse; margin: 0 0 calc(14 * var(--s)); }
.nk-about-html th, .nk-about-html td { padding: calc(8 * var(--s)) calc(10 * var(--s)); border-bottom: 1px solid #e6e6e6; text-align: left; }

/* ================= 窄屏 ================= */
@media (max-width: 1100px) {
  :root { --s: calc(100vw / 1300); }
  /* 🔴🔴 2026-10-22 R15：黑洞 --s 必须跟着断点走 —— 基础值是 min(100vw/1920,…)，
     在中等窗口下和根 --s(100vw/1300) 脱节，黑洞内容比整页小一圈。 */
  .nk-hole {
    --s: min(calc(100vw / 1300), calc(100vh / 1080));
    --disc: calc(940 * min(calc(100vw / 1300), calc(100vh / 1080)));
  }
  .nk-chips { right: calc(var(--mg) + 150 * var(--s)); }
  .nk-sheet { padding: calc(48 * var(--s)) var(--mg) calc(72 * var(--s)); }
  .nk-sheet-title { font-size: calc(44 * var(--s)); }
}
@media (max-width: 720px) {
  /* 🔴🔴 窄屏把 --s 钉死 1px，全部尺寸走绝对 px。
     之前 --s=100vw/430：在 712px 窗口下放大 1.66 倍 → logo x=200/顶栏 padding 117px/
     chips 三行挤成一团，用户实测全错位。
     🔴🔴 2026-10-22 R15：.nk-hole 的 --s 必须同步钉 1px —— 否则黑洞子树还跑
     min(100vw/1920)=0.32px，整页 1px 体系下黑洞缩成 119px 小点（实测）。 */
  :root { --s: 1px; --mg: 20px; --logo-dy: 0px; }
  .nk-hole { --s: 1px; --disc: 370px; }
  .nk-bar { padding: 16px 20px 20px !important; }
  .nk-scrim { height: 250px; }
  .nk-logo { left: 20px; top: 16px; font-size: 15px; }
  /* 窄屏菜单恢复单列（用户反馈「变2排了」不接受 2×2） */
  .nk-menu { top: 16px; right: 20px; font-size: 15px; line-height: 20px; }
  /* chips：贴左上 logo 下面（用户指定），限宽避开右上小导航，自动换行；
     🔴 用户实测太大 → 窄屏字号 13px / 高 24px */
  .nk-chips { left: 20px; right: auto; top: 46px; max-width: calc(100vw - 195px); gap: 6px 5px; font-size: 13px; line-height: 17px; }
  .nk-chip { height: 24px; padding: 0 8px; }
  .nk-copy { left: var(--mg); bottom: auto; transform: none;
    font-size: 10px; max-width: 320px; white-space: normal; text-align: left; }
  .nk-sheet-close { width: 36px; height: 36px; }
  .nk-sheet-close svg { width: 14px; height: 14px; }
  .nk-sheet { left: 0; right: 0; top: calc(18 * var(--s));
    border-radius: calc(20 * var(--s)) calc(20 * var(--s)) 0 0;
    padding: calc(34 * var(--s)) var(--mg) calc(60 * var(--s)); }
  .nk-sheet-title { font-size: calc(32 * var(--s)); letter-spacing: calc(-1.2 * var(--s)); }
  .nk-sheet-lead { font-size: calc(18 * var(--s)); }
  .nk-hole { width: calc(370 * var(--s)); height: calc(370 * var(--s)); }
  .nk-hole-inner { width: calc(330 * var(--s)); max-height: calc(340 * var(--s)); }
  .nk-hole-title { font-size: calc(26 * var(--s)); }
  .nk-hole-lead { font-size: calc(15 * var(--s)); line-height: calc(22 * var(--s)); }
  .nk-field input { height: calc(44 * var(--s)); }
  .nk-field textarea { min-height: calc(88 * var(--s)); }
  /* 🔴 2026-10-17 用户反馈：「输入过多后出来的下拉框太丑」
   那个是浏览器原生 autofill 下拉 / autofill 高亮块，两样都关掉：
     autocomplete=off 关掉历史下拉（JS 侧已设）
     :-webkit-autofill 的背景要显式透明，否则 Chrome 画一块黄/白底
   自定义滚动条样式，让滚动条也是胶囊风格。 */
.nk-field textarea::-webkit-scrollbar,
.nk-field input::-webkit-scrollbar { width: 0; height: 0; }
.nk-field textarea::-webkit-scrollbar-thumb,
.nk-field input::-webkit-scrollbar-thumb {
  background: rgba(255,255,255,.28); border-radius: 99px;
  width: 6px;
}
.nk-field textarea::-webkit-scrollbar-thumb:hover,
.nk-field input::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,.45); }
.nk-field input::-webkit-autofill,
.nk-field input::-webkit-autofill:hover,
.nk-field input::-webkit-autofill:focus,
.nk-field textarea::-webkit-autofill {
  -webkit-text-fill-color: var(--ink) !important;
  -webkit-box-shadow: 0 0 0 1000px #000 inset !important;  /* 盖掉 autofill 黄底 */
  caret-color: var(--ink);
  transition: background-color 9999s ease-out;
}

.nk-field textarea, .nk-field input {
    padding-left: calc(18 * var(--s)); padding-right: calc(18 * var(--s)); }
  .nk-send { width: calc(44 * var(--s)); height: calc(44 * var(--s)); }
}


/* ================= 黑洞内的 canvas 层级压制 =================
   🔴🔴 2026-10-18：.gl（GL canvas 容器）是 position:fixed inset:0 **z-index:10**，
      .nk-hole 只有 z-index:8 → canvas 铺满全屏盖在黑洞之上，
      **黑洞里的一切点击（输入框 / 图谱节点）都会被它吃掉**
      （今天在联系表单上踩过一次，现在图谱又踩）。
      ✅ 黑洞打开期间：canvas 降层 + 关指针事件 + 压暗。
      ⚠️ 这条对「联系我」和「所有二级页」都生效（共用 .nk-hole）。*/
html.nk-hole-on .gl,
html.nk-hole-on .gl * { pointer-events: none !important; }
/* ⚠️ 不加 opacity！原站 GL 画面就是黑洞背景的一部分，
   压暗会让整个黑洞显灰（用户 10-18 实测反馈）。只降 z + 关指针事件。 */
html.nk-hole-on .gl { z-index: 0 !important; }

/* ================= 黑洞打开时顶栏/筛选行退场 =================
   🔴🔴 2026-10-18 用户报「点了 SKILLS 之后，再点 ABOUT 没反应」
   真实根因（elementsFromPoint 实锤）：黑洞打开后**顶栏没隐藏**，
   原站的 MAIN.fixed inset-0（GL 层）盖在顶栏之上 → 菜单按钮根本收不到点击
   （命中栈：MAIN.fixed → BODY → HTML，.nk-menu 完全不在列表里）。
   ✅ 黑洞打开时把顶栏/筛选行/版权彻底隐藏（不是 opacity，是 visibility+hidden）
      让 MAIN 也被隐藏 → 菜单按钮重新可点。
   ⚠️ 但这样用户就点不到菜单换页了 —— 所以菜单要在黑洞之上（z-index 提升），
      而不是隐藏。两条一起做：
        ① GL/MAIN 降层+压指针 → 菜单可点
        ② 顶栏保持可见（用户要能换页） */
html.nk-hole-on main,
html.nk-hole-on .gl,
html.nk-hole-on .gl * {
  pointer-events: none !important;
  z-index: 0 !important;
}
/* 顶栏提到黑洞之上，用户在黑洞里也能换页 */
html.nk-hole-on .nk-bar { z-index: 40 !important; }
html.nk-hole-on .nk-chips,
html.nk-hole-on .nk-copy { z-index: 40 !important; }
/* 🔴🔴 2026-10-22 R9-P0-3：黑洞打开时必须藏掉两层黑渐变 ——
   容器透明化后 GL 银环直接可见，scrim（顶部 .95 黑 → 0）会盖暗圆环上半截，
   视觉上又是一条「分界线」。原站黑洞期没有这层渐变。 */
.nk-scrim { transition: opacity .45s var(--ease), visibility 0s linear 0s; }
html.nk-hole-on .nk-scrim,
html.nk-hole-on .nk-scrim-b {
  opacity: 0 !important;
  visibility: hidden !important;
  pointer-events: none !important;
  transition: opacity .45s var(--ease), visibility 0s linear .45s;
}


/* ══════════════════════════════════════════════════════════════
   R6-P1-4：导航按钮焦点环
   ──────────────────────────────────────────────────────────────
   之前没定义 :focus-visible，浏览器给系统默认焦点环
   rgb(0, 95, 204)（实测）—— 一套纯黑白灰的极简设计里冒出蓝色。
   表单的 .nk-fcell:focus-within::before 早就做对了（0.34 → 0.95 白），
   导航漏了。*/
.nk-menu button:focus-visible,
.nk-chip:focus-visible {
  outline: calc(1 * var(--s)) solid rgba(255, 255, 255, .55);
  outline-offset: calc(3 * var(--s));
  border-radius: calc(2 * var(--s));
}
/* 鼠标点击不显示焦点环（避免点击后一直有框），键盘 Tab 才显示 */
.nk-menu button:focus:not(:focus-visible),
.nk-chip:focus:not(:focus-visible) { outline: none; }

/* 🔵 R6-P3：.nk-logo 原来 @1280 只有 10px（全站唯一 <12px 的元素）。
   字号由 --nk-logo-fs 变量控制（已从数据源 15 提到 22），
   这里只做兜底下限，避免任何情况下低于 12px。*/
.nk-logo { font-size: max(calc(var(--nk-logo-fs, 22) * var(--s)), 12px); }


/* ══════════════════════════════════════════════════════════════
   R7-P2-E：隐藏层焦点环
   ─────────────────────────────────────────────────────────────
   R7 实测 Tab 前 18 个元素（15 个 sr-only 里的 <a>、logo、社交按钮）
   仍是浏览器默认的 rgb(0,95,204) 蓝色焦点环。用户 Tab 时会先走一遍
   隐藏层，视觉上闪一圈蓝框 —— 在纯黑白灰设计里非常刺眼。
   ✅ 给所有可聚焦元素统一白色焦点环。*/
a:focus-visible,
button:focus-visible,
[tabindex]:focus-visible,
.sr-only a:focus-visible,
.sr-only button:focus-visible {
  outline: calc(1 * var(--s)) solid rgba(255, 255, 255, .55);
  outline-offset: calc(3 * var(--s));
  border-radius: calc(2 * var(--s));
}
/* 鼠标点击不留焦点环 */
a:focus:not(:focus-visible),
button:focus:not(:focus-visible) { outline: none; }
