/* ============================================================================
 * 布局层：容器、页头、页脚、版块节奏、栅格
 * ----------------------------------------------------------------------------
 * 栅格用 CSS Grid 的 auto-fit + minmax，不写媒体查询断点。
 * 卡片在窄屏自动从 3 列降到 2 列再到 1 列，靠内容宽度而非屏幕宽度决定，
 * 因此 375 / 768 / 1440 / 1920 四档都能自然成立。
 * ==========================================================================*/

/* -------------------------------------------------------------- 容器 */

.wrap {
  width: 100%;
  max-width: var(--wrap-max);
  margin-inline: auto;
  padding-inline: var(--wrap-pad);
}

/* -------------------------------------------------------------- 页头 */

.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  height: var(--header-h);
  background: rgba(255, 255, 255, .82);
  /* 毛玻璃：滚动时正文从页头下穿过而仍可辨，保持轻盈 */
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  backdrop-filter: saturate(180%) blur(14px);
  /* 底边初始透明，滚动后由 .is-scrolled 浮出 */
  border-bottom: 1px solid transparent;
  transition: border-color var(--dur-base) var(--ease-out);
}

.site-header.is-scrolled { border-bottom-color: var(--c-rule); }

.header-inner {
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-5);
}

/* 不支持 backdrop-filter 时退回不透明底，避免文字与内容重叠 */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .site-header { background: var(--c-paper); }
}

/* ------------------------------------------------------------ 品牌标识 */

.brand {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex-shrink: 0;
}

.brand-mark {
  font-size: var(--fs-body);
  font-weight: var(--fw-thin);
  letter-spacing: .1em;
  line-height: 1;
  flex-shrink: 0;
  /* 与右侧中文名之间用一道极细竖线分隔 —— 比再加一个图形元素更克制 */
  padding-right: var(--sp-3);
  border-right: 1px solid var(--c-rule);
}

.brand-name {
  font-size: var(--fs-sm);
  letter-spacing: .08em;
  white-space: nowrap;
}

/* -------------------------------------------------------------- 导航 */

.site-nav {
  display: flex;
  align-items: center;
  gap: clamp(1.25rem, 3vw, 2.5rem);
}

.site-nav a {
  position: relative;
  font-size: var(--fs-sm);
  letter-spacing: .06em;
  color: var(--c-muted);
  padding-block: var(--sp-1);
}

/* 悬停时从左侧生长出来的细下划线。
   实线换成点阵：2px 的点、6px 节距 —— 与首屏标识的点同源，
   只是密得多（下划线只有 2px 高，按 --dot-pitch 的 10px 铺点会稀到
   看不出是一条线）。生长机制不变，仍是 scaleX 0 → 1。 */
.site-nav a::after {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  width: 100%;
  height: var(--dot-rule-size);
  background-image: repeating-linear-gradient(
    to right,
    var(--c-ink) 0 var(--dot-rule-size),
    transparent var(--dot-rule-size) var(--dot-rule-pitch)
  );
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-base) var(--ease-out);
}

.site-nav a:hover { color: var(--c-ink); }
.site-nav a:hover::after { transform: scaleX(1); }

/* 当前所在版块，由 js/scrollspy.js 挂上。
   与悬停态刻意不同形 —— 初版是同形方案，需求方看过之后要求区分。 */
/*
   区分不靠「更亮」，靠**用哪一种线**：

     悬停 = 点阵下划线（会生长的）→ 说的是「这里可以点」
     当前 = 1px 实线（常驻不动）  → 说的是「你在这里」

   这条界线正是全站那条原则：点阵 = 交互与生命，实线 = 结构与静态。
   「我正在读哪一版块」是关于文档的一个**事实**，不是一次交互 ——
   因此它落在实线那一侧，与版块分隔线、卡片描边同一族。

   顺带也就解释了为什么它更细（1px 对 2px）：实线没有点与点之间的空隙
   来替它减轻分量，同样宽会比点阵重，细一档才与点阵下划线等重。
   切换版块时它仍走 scaleX 生长，是长出来的，不是跳出来的。 */
.site-nav a.is-current { color: var(--c-ink); }
.site-nav a.is-current::after {
  transform: scaleX(1);
  background-image: none;              /* 撤掉点阵底纹，换成实心 */
  background-color: var(--c-ink);
  height: 1px;
}

/* -------------------------------------------------------------- 版块 */

.section {
  padding-block: var(--section-y);
}

/* 版块之间由实线改为**点阵线**（v1.5）。
   理由与导航下划线同源：全站只有两种线 —— 实线是「结构与静态」，
   点阵是「交互与生命」。版块分隔属于结构，本该用实线；
   但页面上连接两个版块的这道线同时是「继续往下读」的暗示，
   且点阵正是全站唯一的视觉母题 —— 母题必须走出 canvas，
   否则「点阵 = 全站唯一视觉母题」只活在注释里。
   节距复用 --dot-rule-pitch（6px），与导航下划线说同一种语言。
   用伪元素而非 border：border 无法铺 repeating-linear-gradient 的横向点。 */
.section + .section {
  position: relative;
  border-top: 0;
}

.section + .section::before {
  content: "";
  position: absolute;
  inset: 0 auto auto 0;
  width: 100%;
  height: var(--dot-rule-size);
  background-image: repeating-linear-gradient(
    to right,
    var(--c-rule-strong) 0 var(--dot-rule-size),
    transparent var(--dot-rule-size) var(--dot-rule-pitch)
  );
}

/* 版块头部：序号 + 标题 + 说明，三者纵向堆叠 */
.section-head {
  margin-bottom: clamp(2.5rem, 6vh, 4.5rem);
}

/* 折叠屏/窄屏时页头文字可能挤，隐藏品牌名只留标识 */
@media (max-width: 460px) {
  .brand-name { display: none; }
}

/* -------------------------------------------------------------- 页脚 */

.site-footer {
  border-top: 1px solid var(--c-rule);
  padding-block: var(--sp-7) var(--sp-8);
}

.footer-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--sp-5);
}

.footer-meta {
  text-align: right;
  font-size: var(--fs-xs);
  color: var(--c-muted);
  line-height: 1.9;
}

.footer-meta p { margin: 0; }

@media (max-width: 640px) {
  .footer-inner { flex-direction: column; align-items: flex-start; }
  .footer-meta { text-align: left; }
}

/* ------------------------------------------------------------ 点阵涟漪 */
/* 画布由 js/ripple.js 创建，HTML 里没有这个元素 —— 无 JS 时页面上
   不会多出任何东西。初始 display:none 也由这里给出，模块在画完最后一帧
   后会把它设回 none，因此空闲时不残留全屏合成层。
   z-index 高于页头（100）：否则在导航上点击时，涟漪会被页头的毛玻璃
   背景挡掉一半，看起来像是画错了。 */
.ripple-canvas {
  position: fixed;
  inset: 0;
  display: none;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 200;
}
