/* ==========================================================================
   赞助页 · 静态站
   样式表 —— 无外链、无字体依赖、离线可用
   美术沿用 F:\newweb\atori：海蓝青主色 / 玻璃拟态卡片 / 底部双层海浪 /
   亮色「海面白昼」+ 深色「深海夜」双主题。
   ⚠️ 全站低饱和单色系：只允许 --accent 这一个色相及其邻近档，
      别往里加页面里没有的颜色（加一个异色相 = 跳出来的一块）。
   ========================================================================== */

/* ---------- 1. Design tokens ---------- */
:root {
  --bg: #f5fbfd;
  --bg-2: #e9f5fa;
  --bg-3: #dceff6;
  --surface: rgba(255, 255, 255, 0.74);
  --surface-solid: #ffffff;
  /* 卡片的**不透明**底色。照片背景下卡片不能半透明，否则字会糊（见 §5 .card 的说明）。 */
  --card-bg: #f7fcfe;
  /* 照片背景上的蒙版（2026-10-03 换背景图时加，同日按截图调过两次）。
     --scrim-a / --scrim-b 是整幅的上下渐变，负责整体压暗；
     --veil 是中心再压一层的径向渐变端点，让卡片那一块最稳。
     ⚠️ 这几个值是「文字可读性」+「人物不被卡片压脸」的双重底线。
        第一版 0.42/0.30/0.34 太薄 —— 亮色下人物的脸几乎贴着卡片上沿，
        白发白衣的高光把卡片衬得不够稳。第二版 0.56/0.46/0.46 定稿。 */
  --scrim-a: rgba(9, 38, 55, 0.56);
  --scrim-b: rgba(9, 38, 55, 0.46);
  --veil: rgba(9, 38, 55, 0.46);
  --text: #0f2230;
  --text-2: #4a6877;
  --text-3: #7d98a6;
  --line: rgba(15, 34, 48, 0.10);
  --line-2: rgba(15, 34, 48, 0.18);
  --accent: #0e9cb8;
  --accent-ink: #0a7c93;
  --accent-soft: rgba(14, 156, 184, 0.12);
  --accent-2: #6cc9de;
  --shadow-sm: 0 6px 18px -10px rgba(11, 52, 71, 0.35);
  --shadow: 0 22px 55px -26px rgba(11, 52, 71, 0.42);
  --radius: 20px;
  --radius-sm: 12px;
  --wrap: 1160px;
  --nav-h: 68px;
  --nav-bg: rgba(245, 251, 253, 0.72);
  /* 首屏海浪的「远层」颜色：只在贴着底色处露一点色差，比背景略深即可。
     ⚠️ 换照片背景后这两层都改成**半透明**了（--wave-1 / --wave-2）：
        原来近层填的是不透明的 var(--bg)，压在照片上就是一道横贯整页的
        **纯白横条**（照片背景下非常明显）。半透明之后才是「浪掠过照片」的效果。
        别改回不透明色。 */
  --wave-1: rgba(233, 245, 250, 0.42);
  --wave-2: rgba(233, 245, 250, 0.62);
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}

html[data-theme="dark"] {
  --bg: #05131e;
  --bg-2: #071e2c;
  --bg-3: #0a2939;
  --surface: rgba(12, 40, 56, 0.62);
  --surface-solid: #0a2433;
  --card-bg: #0a2433;
  /* ⚠️ 深色主题的蒙版必须比亮色**更重**（0.68 / 0.60 vs 0.42 / 0.30）：
     这张背景图整体是高亮的白花田，深色主题若压得和亮色一样轻，
     整页会亮堂堂的，跟「深海夜」的基调完全打架 —— 深色下文字是浅色，
     更吃对比度。 */
  --scrim-a: rgba(3, 16, 26, 0.70);
  --scrim-b: rgba(3, 16, 26, 0.58);
  --veil: rgba(3, 16, 26, 0.42);
  --text: #e6f4fa;
  --text-2: #9db9c8;
  --text-3: #6f8fa0;
  --line: rgba(150, 205, 228, 0.14);
  --line-2: rgba(150, 205, 228, 0.24);
  --accent: #4ed4e8;
  --accent-ink: #86e6f4;
  --accent-soft: rgba(78, 212, 232, 0.14);
  --accent-2: #2f9fbc;
  --shadow-sm: 0 8px 22px -12px rgba(0, 0, 0, 0.7);
  --shadow: 0 26px 60px -28px rgba(0, 0, 0, 0.8);
  --nav-bg: rgba(5, 19, 30, 0.72);
  --wave-1: rgba(7, 30, 44, 0.46);
  --wave-2: rgba(7, 30, 44, 0.62);
}

/* ---------- 2. Background ---------- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  /* 单页内容可能比视口矮，body 用 min-height 撑出至少一屏，
     这样 .stage 的居中 + .tail 的海浪在矮内容下也贴得到视口底。 */
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI",
    "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans SC", sans-serif;
  font-size: 16px;
  line-height: 1.75;
  letter-spacing: 0.01em;
  overflow-x: hidden;
  transition: background-color 0.4s var(--ease), color 0.4s var(--ease);
}

img, svg { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; border: 0; background: none; cursor: pointer; }
h1, p, figure { margin: 0; }
em { font-style: normal; }

::selection { background: var(--accent); color: #fff; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 6px;
}

.skip {
  position: fixed; top: 10px; left: 50%; transform: translate(-50%, -220%);
  z-index: 200; padding: 10px 18px; border-radius: 999px;
  background: var(--accent); color: #fff; font-size: 14px;
  transition: transform 0.25s var(--ease);
}
.skip:focus { transform: translate(-50%, 0); }

/* 背景层：整页铺一张花田照片（2026-10-03 换）。
   ⚠️ **照片上必须压一层蒙版**，否则卡片上的文字读不出来 —— 原图是高亮的白花田，
      浅色主题下浅字直接糊掉。这里用两层叠加：
        · --scrim  一层整幅的半透明色（亮色/深色各给一档），负责整体压暗；
        · --veil   中心再压一点，把卡片所在的位置压得最狠。
   ⚠️ 深色主题的 --scrim 要比亮色**更重**（0.62 vs 0.34）：照片本身很亮，
      深色主题下若压得不够，整页会亮堂堂的，跟「深海夜」的基调完全打架。
   ⚠️ 别把蒙版压到 0.6 以上（亮色）：会盖掉这张图好看的地方，得不偿失。
   背景图路径写在 CSS 里而不是 <img>：CSS 背景不支持 <picture> 的格式回退，
   所以 jpg / webp 两版由 image-set() 交给浏览器自己挑（挑不出的走 jpg）。
   image-set 是渐进增强：老浏览器忽略这行、只认后面的 url("…bg.jpg") 兜底。

   ⚠️ **路径必须是 ../../images/，不是 ../images/**（2026-10-03 踩过）：
   这份CSS 在 /assets/css/style.css，`../images/` 会解析成 /assets/images/ —— 少一级，
   页面照常渲染、只是背景静默 404（控制台 4 条 network error，视觉上是「图没换上」）。
   改路径时用「相对 style.css 自己」算，别用相对 index.html 算。 */
.atmos {
  position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background-color: var(--bg);
  background-image:
    radial-gradient(58% 42% at 50% 52%, var(--veil), transparent 72%),
    linear-gradient(var(--scrim-a), var(--scrim-b)),
    image-set(url("../../images/bg.webp") type("image/webp") 1x,
              url("../../images/bg.jpg") type("image/jpeg") 1x),
    url("../../images/bg.jpg");
  background-repeat: no-repeat;
  /* 原图 1920×1200（8:5），整幅铺满靠 cover。
     ⚠️ **background-position / -size / -attachment 是逐层的值列表**
        （.atmos 有 4 层：veil、scrim、image-set、jpg 兜底），
        写**单个值会被前面的同名声明按层数规则处理**，很容易出现
        「改了没反应」—— 2026-10-03 就在这栽过：
        上面先写了一句 `background-position: center, center, center, center`（4 层），
        后面又写 `background-position: center 18%`（1 层）——
        浏览器按层索引逐个配对，第 2~4 层仍吃前一条的值，
        于是「取景值改了但截图完全没变」，白排查一轮。
        **所以这里只保留一条 background-position，写单值就用单值，别混着来。** */
  background-size: cover;
  /* 取景值 = 按「别让卡片压住人物的脸」定的，不是随手填 center。
     人物的脸在原图里约 30% 高度处，而卡片是视口正中：
       · 50%（center）：卡片压脸，只剩头发和肩膀
       · 32%：脸挪到卡片上沿，但下颌还贴着卡片顶
       · 18%：脸与上半身完整落在卡片上方（定稿）
     ⚠️ 换背景图必须重看这条 —— 它跟人物在画面里的位置强绑定。
     ⚠️ **看截图定，别算**：cover 的裁切量随视口宽高比变，
        同一个值在 1440×900 和 2560×1440 下的落点完全不同。 */
  background-position: center 18%;
  background-attachment: fixed;
}
/* 竖屏 / 矮屏：cover 的取景窗口很窄，8:5 的图会被裁到只剩中间一条，
   焦点要再抬高一档，人物才不会被挤出画面。 */
@media (max-width: 900px), (max-height: 720px) {
  .atmos { background-position: center 8%; }
}
/* prefers-reduced-motion 时 background-attachment: fixed 在部分浏览器会闪，
   换成 scroll（滚动时背景跟着走，不锁死视口）。 */
@media (prefers-reduced-motion: reduce) {
  .atmos { background-attachment: scroll; }
}

/* ---------- 3. 顶栏 ----------
   单页站：只有品牌名 + 主题按钮，没有导航链接（无处可跳 = 纯装饰，不做）。
   ⚠️ 顶栏是**直接压在照片上的**（照片背景下没有 hero 深色层可借），
      所以两条规则必须留着：品牌名给**白色 + 投影**，主题按钮同理。
   一旦去掉，浅色主题下顶栏字会糊在花丛里 —— 深色主题反而不用管（有深色蒙版）。 */
.nav {
  position: fixed; inset: 0 0 auto; z-index: 100;
  height: var(--nav-h);
  border-bottom: 1px solid transparent;
  transition: background-color 0.3s var(--ease), box-shadow 0.3s var(--ease),
    border-color 0.3s var(--ease), backdrop-filter 0.3s var(--ease);
}
/* 未吸顶（还压在照片上）：文字强制白 + 投影，不吃主题色 */
.nav:not(.is-stuck) .brand__text { color: #fff; text-shadow: 0 2px 12px rgba(6, 26, 38, 0.75); }
.nav:not(.is-stuck) .brand__text em { color: rgba(255, 255, 255, 0.82); }
.nav:not(.is-stuck) .iconbtn { color: #fff; filter: drop-shadow(0 2px 10px rgba(6, 26, 38, 0.8)); }
.nav:not(.is-stuck) .iconbtn:hover { color: #fff; }
/* 吸顶后：换成 --nav-bg 的实底，恢复主题色文字 */
.nav.is-stuck {
  background: var(--nav-bg);
  backdrop-filter: saturate(180%) blur(16px);
  -webkit-backdrop-filter: saturate(180%) blur(16px);
  border-bottom-color: var(--line);
  box-shadow: var(--shadow-sm);
}
.nav__inner {
  max-width: var(--wrap); margin-inline: auto; height: 100%;
  padding-inline: 22px;
  display: flex; align-items: center; gap: 18px;
}

.brand { display: flex; align-items: center; gap: 10px; flex: none; }
.brand__text { font-weight: 700; letter-spacing: 0.16em; font-size: 16px; }
.brand__text em {
  display: inline; margin-left: 0.62em;
  font-size: 13px; letter-spacing: 0.1em; font-weight: 500; color: var(--text-3);
}

.nav__actions { display: flex; align-items: center; gap: 8px; margin-left: auto; }

/* 主题切换：**纯图标**，不画盒子。40×40 的尺寸必须留着 ——
   只刮掉漆，点击/触控目标不能跟着缩。 */
.iconbtn {
  width: 40px; height: 40px; border-radius: 12px;
  display: grid; place-items: center;
  color: var(--text-2);
  transition: transform 0.2s var(--ease), color 0.2s var(--ease);
}
.iconbtn:hover { color: var(--accent-ink); transform: translateY(-2px); }
.iconbtn:active { transform: translateY(0) scale(0.96); }
.iconbtn svg { width: 21px; height: 21px; }
.iconbtn .i-moon { display: none; }
html[data-theme="dark"] .iconbtn .i-sun { display: none; }
html[data-theme="dark"] .iconbtn .i-moon { display: block; }

/* ---------- 4. 主区 ----------
   构图：**水平居中 + 垂直贴底**（2026-10-04 用户三轮要求叠出来的结果：
   ① "把赞助卡片放到网站的正中间" ② "在不遮挡人物脸的基础上，把赞助卡片往下移动"
   ③ "去掉 [卡片标题] 以降低卡片高度，让人物的脸完全露出来" ——
      ③ 就是删掉 h1.title（见下面 §4 的 .card__head 一节），换来 51px 高度）。
   ④ 同日（晚）又点名加回两段文字（kicker 下的 .note + 码下的 .qr__pay）——
      ④ 把 ③ 让出来的高度又花掉了约 66px，下颌让位**主动放弃**（见几何账）。

   ⚠️ 垂直方向为什么是**贴底（flex-end）而不是居中** —— 别改回 center：
      背景 1920×1200 在 1440×900 上 cover 恰好铺满（×0.75 = 1440×900，溢出量 0），
      所以 background-position 横向**没有任何位移空间**，人物的脸永远固定在
      画面横向中央（测出来 x≈52%，头宽约占画面 16%）。既然水平躲不开，
      就只能**垂直让**：把卡片往下压，让画面上半部腾给头部。
      「贴底」是单屏不滚动的前提下能拿到的**最大下移量** ——
      padding-bottom 再小卡片就要压到海浪上了。

   📏 人物位置（2026-10-04 用 tools/locate-subject.py 实测，不是估的）。
      判据是「中央带 vs 两侧带的边缘强度比值」，源图纵向的强细节带：
        12%~20%   头顶 / 发饰（峰值最高的一段）
        21%~29%   平涂的脸 —— 比值反而落回 1.0，插画的脸就是一块干净的颜色
        30%~41%   下颌 / 脖子
        46%~50%   肩（肩比卡片宽，会从卡片两侧露出来）
      换算到 1440×900（cover 溢出量 0，源图百分比 = 视口百分比）：
        脸 ≈ 189~261px｜下颌/脖子 ≈ 270~378px
      **脸下沿 261px 是现在的底线**（e2e 钉的是这条）；下颌下沿 378px 已主动放弃
      （2026-10-04 晚用户点名加回 .note + .qr__pay 两段字，卡片装不下它们）。
      实测演变：删标题后 397px → 加回两段字后 331px（删标题前 346px、居中期 312px）。
   ⚠️ 这条也**推翻了 2026-10-03 的「靠左」**（那时的办法是横向躲）。
      用户两次点名的都是「居中」，别把他改回靠左。
      （旧注释里那句「居中只剩头发和肩膀」也能对上：那时卡片上沿 178px，
       只露出 12%~20% 那一截头发。）

   ⚠️ 几何底线（改之前算一遍，别靠试）：
      卡片上沿 = 视口高 − 92px(海浪) − padding-bottom(10px) − 卡片高
      卡片高实测 ≈ 467px（加回 .note + .qr__pay 后；删标题后曾 401px，删标题前 452px），
      故 1440×900 下上沿 ≈ 331px。
      **下颌下沿 378px 已主动放弃** —— 要压过它需要 卡片高 ≤ 420px，
      现在的卡片装不下那两段字。底线退回「脸完整露出」（下沿 261px）：
      视口高 − 92 − 10 − 467 ≥ 261 → **视口 ≳ 830px 高**。
      更矮的窗口（如 1366×768 = 768px）物理上做不到，那时只能接受轻微遮挡，
      或允许页面比一屏高（海浪会被推到折线以下）——别指望 padding-bottom 能变出空间。
      想再往下只有两条路，各有代价：
        · 再收 .card 的竖向内边距（每收 1px 换 1px，二维码尺寸不受影响）
        · 允许页面比一屏高 —— 那海浪就会被推到折线以下 */
.stage {
  flex: 1 0 auto;
  display: flex;
  align-items: flex-end;          /* 往下贴 —— 见上面那段，别改回 center */
  justify-content: center;        /* 水平居中 —— 用户点名要的 */
  padding: calc(var(--nav-h) + 44px) 22px 10px;
}

/* 收款卡 = atori 那族玻璃卡的**近亲**，但**底色不透明**（2026-10-03 换照片背景时改的）。
   原设计是 `--surface` 半透明 + backdrop-filter 玻璃，压在纯色渐变上很好看；
   压到照片上就不行了 —— 花丛的高光会透上来，卡片上的标题和 kicker 直接糊掉，
   实测浅色主题下最明显。所以改成不透明底 + 保留细描边与圆角，
   「玻璃感」靠背景蒙版（.atmos 的 --scrim / --veil）去营造，不靠卡片自己透明。
   ⚠️ 想省事把 background 换回 var(--surface) 会立刻退化，别这么干。 */
.card {
  width: 100%; max-width: 380px;
  /* 竖向内边距比常规略紧：这是拿去给「人物头部」让位的（见 §4）。
     ⚠️ 只动竖向 —— 横向 32px 不能动，一动二维码的可用宽度就跟着变，
        二维码是「宽度驱动」的（width:100% + height:auto），
        横向一改它整张就大了/小了，那是不能碰的。
        竖向改了之后二维码**尺寸完全不变**，只有文字与边缘的空变窄一点。 */
  padding: 26px 32px 24px;   /* 加了 .note / .qr__pay 后从 28/26 又收一档，抵掉部分增高 */
  border-radius: var(--radius);
  background: var(--card-bg);
  border: 1px solid var(--line-2);
  box-shadow: var(--shadow);
  transition: border-color 0.3s var(--ease), box-shadow 0.3s var(--ease);
}
.card:hover { border-color: var(--accent); }

/* 区头：kicker（小字 + 两侧短横线）+ 一段说明。
   2026-10-04 用户先删掉了主标题「赞助一下」（压高度 + 去重复表达），
   同日晚又点名在 kicker 下面加回一段说明（.note，见下）。
   kicker 的短横线是纯装饰，但它是 atori 区头的统一识别件，留着。 */
.card__head { text-align: center; }
.kicker {
  display: flex; align-items: center; justify-content: center; gap: 12px;
  font-size: 11.5px; letter-spacing: 0.36em; text-transform: uppercase;
  color: var(--accent-ink); font-weight: 700;
}
.kicker::before {
  content: ""; width: 26px; height: 2px; border-radius: 2px; background: var(--accent);
}
.kicker::after {
  content: ""; width: 26px; height: 2px; border-radius: 2px; background: var(--accent);
}
/* kicker 下的一段说明（2026-10-04 用户点名加的）：
   「收到的每一份心意都会用在后续的开发上。它不构成任何购买：…」。
   小字 + 弱色（--text-2），不跟 kicker 抢层级；两行 ≈ 47px，
   这 47px 就是从「下颌完整露出」里让出去的（见 §4 的几何账）。 */
.note {
  margin-top: 10px;
  font-size: 11.5px; line-height: 1.6;
  color: var(--text-2);
}
/* 原先这里有一条 `.title`（主标题「赞助一下」），
   2026-10-04 按用户要求随那个 <h1> 一起删除（红框圈的就是它）。别加回来 ——
   卡片已经有了 kicker + note，再放一行大字既是重复表达、又把卡片顶回 452px 高。 */

/* 原先这里有 `.sub`（「微信扫码，或长按识别下方二维码」），
   2026-10-03 按用户要求随那行字一起删除。别加回来 ——
   二维码本身已经说明了扫什么，说明文字属于重复表达。 */

/* ---------- 5. 收款码 ----------
   ⚠️ .qr__plate 的底色**写死 #fff，两套主题都不变**（不吃 --surface）。
      收款码靠黑白反差识别，深色主题下若跟着卡片变深，识别率会直接掉。
      这是全站唯一不许「统一进主题」的地方，改动前先想清楚。
   ⚠️ plate 上不许加 backdrop-filter / 半透明 / 投影落在码面上：
      任何压在码上的东西都会干扰识别。装饰只在 plate 之外（阴影挂在 .qr 上）。 */
/* 24px → 18px → 12px：给头部让位一路收下来的。note 已经在 head 和码之间
   提供了空隙，这里不需要再留 18px。 */
.qr { margin-top: 12px; }
.qr__plate {
  padding: 14px;
  border-radius: var(--radius-sm);
  background: #fff;
  box-shadow: 0 10px 30px -16px rgba(11, 52, 71, 0.45);
}
html[data-theme="dark"] .qr__plate { box-shadow: 0 12px 34px -14px rgba(0, 0, 0, 0.8); }

/* 原图 559×546（近正方但略宽）。保持原比例，不裁不拉：
   width:100% + height:auto 让它随卡片宽度缩放，
   容器最大 356px 宽（420 − 32×2 padding），显示约 108 DPI，扫码够用。 */
.qr__plate img {
  width: 100%; height: auto;
  border-radius: 6px;
  /* 不加 image-rendering: pixelated —— 那是给像素画用的，
     二维码边缘的抗锯齿灰阶反而有助于相机对焦，别动。 */
}

/* 原先这里有 `.qr__hint`（「长按图片可保存 · 微信支付」），
   2026-10-03 按用户要求随那行字一起删除。
   2026-10-04（晚）用户点名在支付方式旁边加「推荐使用微信支付」→ 新增 .qr__pay
   （figcaption，跟着码走）。同样小字 + 弱色，不压过码面（码上不许有任何东西）。 */
.qr__pay {
  margin-top: 10px;
  text-align: center;
  font-size: 11px; letter-spacing: 0.06em;
  color: var(--text-3);
}

/* ---------- 6. 海浪 ----------
   .tail 是 flex: 0 0 auto，内容多高它就多高，海浪贴它的底边。
   两层浪的路径参数与三条约束沿用 atori（改之前先读那段）：
     · viewBox 宽 2880，半波 HALF=360 → 2880÷360=8（偶数），
       translateX(-50%) 的无缝漂移才没有折角；
     · 两层都从负 x 起步并向右多画两段，避免动画中左右露直角；
     · 横向不许有 CSS 位移以外的裁剪（preserveAspectRatio="none" 已按视口裁）。
   高度比 atori 首屏矮（92px vs 168px）：这一页底部没有视频压着，
   浪只是收边，不该抢戏。 */
.tail { position: relative; flex: 0 0 auto; height: 92px; }
/* ⚠️ overflow:hidden 是**必需**的，不是可选的清理：
   两层浪的 svg 是 `width: 200%`（要给 translateX(-50%) 留位移空间），
   它们会把 .tail 乃至整个文档横向撑宽 —— 实测文档宽到 2680px、
   390px 手机上横向溢出 311px。波浪本身只在 .waves 这 92px 高的盒子里可见，
   多出来的那一半永远在盒外，所以直接裁掉即可。
   atori 那边是靠 `.hero { overflow: hidden }` 挡的（那里有 hero 视频，同理）；
   这一页没有 hero，就**必须由 .waves 自己扛**，别指望父级。 */
.waves {
  position: absolute; left: 0; right: 0; bottom: -1px; z-index: 0;
  height: 92px; overflow: hidden; pointer-events: none;
}
.waves svg {
  position: absolute; left: 0; bottom: 0; width: 200%; height: 100%;
  /* 必须解除全局 `img, svg { max-width: 100% }`：
     它会把这里的 200% 悄悄夹成 100%，svg 只有一屏宽，
     位移动画一跑右边缘就露出一条没被波浪盖住的底色。 */
  max-width: none;
}
.wave--far { fill: var(--wave-1); animation: waveSlide 19s linear infinite; }
.wave--near { fill: var(--wave-2); animation: waveSlide 28s linear infinite reverse; }
@keyframes waveSlide { from { transform: translateX(0); } to { transform: translateX(-50%); } }

/* 原先这里有 `.foot`（「本页仅用于个人收款，与任何第三方无关。」），
   2026-10-03 按用户要求随那行字一起删除。删掉后 .tail 自身就是那 92px 高度
   （原先是靠 .foot 的文字撑起来的），别再往里加内容。 */

/* ---------- 7. 署名 ----------
   2026-10-04 用户要求：「在页面右下角小字标注，by 白織」。
   固定贴**视口**右下角（这一页是单屏的，所以视口右下角 = 页面右下角；
   用 fixed 而不是跟着 .tail 走，是为了矮窗口里滚动时它也不会跑掉）。

   📏 右缘位置（2026-10-04 第二轮改动，用户发截图圈旧位置 + 画箭头指向更靠右的角落）：
      改前是 `max(22px, (100% - 1160)/2 + 22px)` —— 即「跟顶栏主题按钮同一列」，
      1440 下 = 162px、1536 下 = 210px。用户要的是右下角，于是改成
      **`clamp(22px, 原式, 72px)`**：窄屏（≤1160px）结果与改前**逐像素相同**
      —— 这正是用户「手机版不要动」的要求；只有桌面被夹到 72px。
      ⚠️ 72px 是**量出来的**，不是估的：用户截图为 1920×714 设备像素、缩放 1.25
         （用二维码纯白底板的 394 设备 px ÷ CSS 的 316px 反推，再用
         「旧文字右缘落在 1650 设备 px」交叉验证过），
         红箭头尖端在 x=1814 设备 px → 距视口右边 ≈ 72 CSS px。
      ⚠️ 若哪天要「贴死角落」，把夹取值 72px 改成 22px 即可（只此一处）。

   ⚠️ 墨色必须是 **var(--text)**（跟着主题走），别改成「一律白字」更别写死深色/浅色：
      这一块底下是照片 + 半透明海浪，而**右下角那一片的明暗是跟主题反过来的** ——
      亮色主题下 --scrim 只压 0.56、浪又是浅色 → 实测背景亮度 166（明亮），
      深墨 #0f2230 是 7.9:1、白字只有 2.4:1（会糊）；
      深色主题下 --scrim 压 0.70 → 实测亮度 51（暗），白字 12.7:1、深墨 1.5:1。
      这套「跟着主题翻转」正好等于 var(--text)，所以直接用变量最省事。
      ⚠️ 顶栏那套「一律白字」不适用（见 §3）：那是页面**顶部**，照片顶部本来就暗。
      ⚠️ 换背景图后必须用 tools/probe-contrast.py 重测这两块 —— DOM 断言看不出糊字。 */
.credit {
  position: fixed;
  /* 窄屏 = 22px（与改前逐像素相同）；桌面被夹到 72px（用户截图里箭头所指的落点）。 */
  right: clamp(22px, calc((100% - var(--wrap)) / 2 + 22px), 72px);
  bottom: 15px;
  z-index: 90;                /* 在海浪之上（.waves 是 z-index: 0），在顶栏之下（100） */
  font-size: 11.5px;
  letter-spacing: 0.1em;
  line-height: 1;
  color: var(--text);
  /* 光晕也反着给：亮色用浅光晕托住深墨，深色用暗投影托住浅字。 */
  text-shadow: 0 1px 8px rgba(255, 255, 255, 0.8);
  pointer-events: none;       /* 纯署名，不要挡住底下的东西 */
}
html[data-theme="dark"] .credit {
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.75);
}

/* ---------- 8. Reveal on scroll ---------- */
.js-ready .reveal { opacity: 0; transform: translateY(26px); }
.js-ready .reveal.is-in {
  opacity: 1; transform: none;
  transition: opacity 0.7s var(--ease), transform 0.7s var(--ease);
}

/* ---------- 9. Responsive ---------- */
/* 窄屏（≤ 1000px）：卡片在桌面端就已经居中了（见 §4），所以这里只剩背景焦点要调 ——
   竖屏上 cover 只剩中间一条，焦点抬高一点，人物的头才不会被挤出画面。
   （原先这里还负责把「靠左」退回「居中」，2026-10-04 全站改居中后那两行已删。） */
@media (max-width: 1000px) {
  .atmos { background-position: center 6%; }
}

@media (max-width: 560px) {
  body { font-size: 15.5px; }
  .brand__text { font-size: 14px; letter-spacing: 0.12em; }
  .brand__text em { font-size: 11px; letter-spacing: 0.04em; margin-left: 0.5em; }
  .stage { padding: calc(var(--nav-h) + 28px) 18px 10px; }
  .card { padding: 26px 20px 24px; }
  .waves { height: 68px; }
  .tail { height: 68px; }
  /* 右缘仍对齐 22px（= 顶栏主题按钮那一列），只把字号/离底收一点，别挤到浪里。 */
  .credit { bottom: 12px; font-size: 11px; }
}

/* 极矮视口（横放的手机）：内容比视口高时正常滚动即可，
   这里只把主区的上下留白收一点，别让首屏只看到标题。
   ⚠️ padding-bottom 必须跟着收小：卡片是**贴底**的（见 §4），
      这里若留 56px 的空白，卡片就又被抬回画面中间去了。 */
@media (max-height: 560px) {
  .stage { padding-top: calc(var(--nav-h) + 20px); padding-bottom: 16px; }
}

/* ---------- 10. Motion & print ---------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .js-ready .reveal { opacity: 1; transform: none; }
}

@media print {
  .nav, .waves, .atmos { display: none !important; }
  body { background: #fff; color: #000; }
  .card { border: 1px solid #ccc; box-shadow: none; }
  .stage { padding: 0; }
}