/* ==========================================================================
   ttread.cn — 蜻蜓伴读 · 个人作品站
   --------------------------------------------------------------------------
   两组变量决定观感，没有别的开关：
     data-theme   light | dark      跟随系统，可手动覆盖
     data-accent  cinnabar | moss | amber | indigo
   2 × 4 = 8 种组合，全靠 CSS 变量，切换零重排。

   三条不能破的规矩（都和 SEO / 可用性有关）：
   1. 内容默认可见。动效由 html.motion 门控 —— JS 没跑、被禁用、
      或用户要求减少动效时，样式根本不生效，页面照常可读。
   2. 背景只用渐变与几何，不放图片。首屏 LCP 不许被装饰拖慢。
   3. 视差只在桌面端，移动端整段关闭。
   ========================================================================== */

/* ── 1. 主题令牌 ──────────────────────────────────────────────────────── */
:root{
  /* 基础层：不随主题变 */
  --wrap:1120px;
  --pad:clamp(18px,5vw,44px);
  --r:14px;
  --r-lg:22px;
  --ease:cubic-bezier(.22,.61,.36,1);

  /* 字体全走系统栈，零网络请求；display 只是别名，
     8 组合共用一套字形，靠字重和字距拉开层级 */
  --font-sans:"PingFang SC","HarmonyOS Sans SC","Source Han Sans SC",
              "Noto Sans SC","Microsoft YaHei",system-ui,-apple-system,
              "Segoe UI",Roboto,sans-serif;
  --font-display:var(--font-sans);
  --font-mono:"SF Mono",ui-monospace,"Cascadia Mono",Menlo,Consolas,
              "Liberation Mono",monospace;

  /* 浅色中性层。底色 #f7f5f0 就是 head 里的 theme-color，
     改这里必须同步改 build.py 的 THEMECOLOR，浏览器地址栏会不同步 */
  --bg:#f7f5f0;
  --bg-2:#fffdf8;
  --panel:rgba(255,253,248,.72);
  --panel-solid:#ffffff;
  --line:rgba(24,26,32,.12);
  --line-2:rgba(24,26,32,.18);
  --ink:#16181e;
  --ink-2:#4a5060;
  --faint:#646a79;
  --grid:rgba(24,26,32,.06);
  --shadow:0 1px 2px rgba(24,26,32,.05),0 10px 26px -18px rgba(24,26,32,.24);
  --shadow-lift:0 2px 6px rgba(24,26,32,.06),0 22px 44px -24px rgba(24,26,32,.32);

  /* 强调色默认朱砂。--on-acc 是「压在强调色上的字」，
     铁律：浅色底的强调色够深 → 配白字；深色底提亮 → 配近黑字 */
  --acc:#b33420;
  --acc-2:#d4573c;
  --on-acc:#ffffff;
  --violet:#7a3ff2;
  /* 第三支装饰色相：logo 本身就是青色 */
  --teal:#0d9488;

  /* 背景渐变用的 R,G,B 三元组。刻意不用 color-mix() —— 它要 2023 年的
     浏览器，且 background 是多层简写、任一层作废则整条丢弃；
     rgba(var(--acc-rgb),.34) 这类写法是纯文本替换，2016 年起全支持。 */
  --acc-rgb:179,52,32; --acc2-rgb:212,87,60;
  --violet-rgb:122,63,242; --teal-rgb:13,148,136;
  --bg-rgb:247,245,240; --bg2-rgb:255,253,248; --ink-rgb:22,24,30;
  --acc-shade:#842618; --acc-tint:#c7695a;

  /* 运行时值：--mx/--my 鼠标随行、--sp 滚动进度，都由 app.js 写。
     没有 JS 时必须留 0，否则 calc 里的偏移会把装饰层甩出可视区 */
  --mx:0; --my:0; --sp:0;
}

/* 深色整组覆盖。强调色同时提亮，--on-acc 随之翻转成近黑 ——
   这两件事必须同帧，见下面 html.themeswap 的注释 */
[data-theme=dark]{
  --bg:#0d1017;
  --bg-2:#141926;
  --panel:rgba(233,237,245,.055);
  --panel-solid:#171d2b;
  --line:rgba(233,237,245,.11);
  --line-2:rgba(233,237,245,.18);
  --ink:#e9edf5;
  --ink-2:#a5adc0;
  --faint:#838ba0;
  --grid:rgba(233,237,245,.06);
  --shadow:0 1px 2px rgba(0,0,0,.45),0 10px 26px -18px rgba(0,0,0,.7);
  --shadow-lift:0 2px 6px rgba(0,0,0,.5),0 22px 44px -24px rgba(0,0,0,.8);

  --acc:#ff7a63;
  --acc-2:#ffb08a;
  --on-acc:#0b0e14;
  --violet:#a78bfa;
  --teal:#4fd1c5;
  --acc-rgb:255,122,99; --acc2-rgb:255,176,138;
  --violet-rgb:167,139,250; --teal-rgb:79,209,197;
  --bg-rgb:13,16,23; --bg2-rgb:20,25,38; --ink-rgb:233,237,245;
  --acc-shade:#bd5a49; --acc-tint:#ff9d8c;
}

/* 其余 3 个强调色 × 2 深浅。深浅同名色必须成对出现，
   否则 [data-accent=x] 会以同级优先级盖掉 [data-theme=dark] 的提亮 */
[data-accent=moss]{  --acc:#276641; --acc-2:#4aa3c7;
  --acc-rgb:39,102,65; --acc2-rgb:74,163,199; 
  --acc-shade:#1d4b30; --acc-tint:#5f8e72; }
[data-accent=amber]{ --acc:#8f5304; --acc-2:#d98324;
  --acc-rgb:143,83,4; --acc2-rgb:217,131,36; 
  --acc-shade:#6a3d03; --acc-tint:#ac8045; }
[data-accent=indigo]{--acc:#3a54c4; --acc-2:#7c5cd6;
  --acc-rgb:58,84,196; --acc2-rgb:124,92,214; 
  --acc-shade:#2b3e91; --acc-tint:#6d80d3; }

[data-theme=dark][data-accent=moss]{  --acc:#5fd39a; --acc-2:#7fd8e8;
  --acc-rgb:95,211,154; --acc2-rgb:127,216,232; 
  --acc-shade:#469c72; --acc-tint:#89deb4; }
[data-theme=dark][data-accent=amber]{ --acc:#f5b53c; --acc-2:#ffd07a;
  --acc-rgb:245,181,60; --acc2-rgb:255,208,122; 
  --acc-shade:#b5862c; --acc-tint:#f8c86f; }
[data-theme=dark][data-accent=indigo]{--acc:#8fa4ff; --acc-2:#b9a5ff;
  --acc-rgb:143,164,255; --acc2-rgb:185,165,255; 
  --acc-shade:#6a79bd; --acc-tint:#acbcff; }

/* 主题切换的那几帧里关掉全站 transition。
   这是「切到浅色后字看不见」的根因：带 transition 的块（.ft/.card/.btn/.slide…）
   底色用 0.3s 慢慢变，而 .lede 这类没写 transition 的文字是瞬间换新前景色，
   两者对不上 —— 深色字压在还没变完的深色底上，整块字消失约 0.3s。
   文字色和底色必须同帧切换，所以切主题时一律不许过渡。
   assets/app.js 的 setTheme/setAccent 会加 .themeswap 再在两帧后摘掉。 */
html.themeswap *,html.themeswap *::before,html.themeswap *::after{
  transition:none !important;
}

/* ── 2. 基础 ─────────────────────────────────────────────────────────── */
*,*::before,*::after{ box-sizing:border-box; }
/* 底色必须挂在 html 上：CSS 绘制顺序里 html 背景是第1步，
    z-index:-1 的 .bgfx 是第2步，body 背景是第3步 ——
    挂在 body 上会把 .bgfx 整个盖住（光斑从来没露出来过）。 */
html{ -webkit-text-size-adjust:100%; scroll-behavior:smooth; background:var(--bg); }
@media (prefers-reduced-motion:reduce){ html{ scroll-behavior:auto; } }

body{
  margin:0;
  font-family:var(--font-sans);
  font-size:16px;
  line-height:1.75;
  color:var(--ink);
  /* 这里绝不能再写 background:var(--bg) —— 见上面 html 的注释，
     body 的背景会在第3步盖住 z-index:-1 的 .bgfx。兜底底色归 html。 */
  background:transparent;
  overflow-x:hidden;
  -webkit-font-smoothing:antialiased;
  /* 这里刻意不写 transition。曾经有 background/color 各 0.35s 的淡入，
     结果切主题时 body 的底色还在过渡、而 .lede/.h1-sub 这些子元素没有
     transition 就瞬间换成了新前景 —— 深色字压在还没变过来的深色底上，
     整块文字消失约 0.35s。文字色和底色必须同帧切换，主题切换改成瞬时。 */
}
img{ max-width:100%; display:block; }
a{ color:inherit; text-decoration:none; }
b,strong{ font-weight:700; }

h1,h2,h3,h4{ line-height:1.22; margin:0; font-weight:800; letter-spacing:-.02em; }

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

.skip{
  position:absolute; left:-9999px; top:0; z-index:200;
  background:var(--ink); color:var(--bg); padding:10px 18px; border-radius:0 0 10px 0;
}
.skip:focus{ left:0; }

/* 只给读屏和标题层级用的小标题，视觉上不占位置也不产生横向滚动 */
.sr-only{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip-path:inset(50%); white-space:nowrap; border:0;
}

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

/* ── 3. 动态背景（纯 CSS，不取资源，不挡首屏）───────────────────────── */
.bgfx{
  position:fixed; inset:0; z-index:-1; pointer-events:none;
  /* 三支光斑，三个不同色相：朱砂(左上) 青(右下) 紫(左下)，右上留空。
     中心随鼠标偏移（--mx/--my 由 app.js 在桌面端设，默认 0 无偏移）。
     移动端不设 --mx/--my，无随行。刻意不放 acc-2 —— 它是 acc 同色相浅版，
     不构成独立变化，摆上去只会让画面四面合围。 */
  background:
    radial-gradient(48% 42% at calc(10% + var(--mx,0)*14%) calc(6% + var(--my,0)*14%),
      rgba(var(--acc-rgb),.34),transparent 60%),
    radial-gradient(42% 46% at calc(82% + var(--mx,0)*11%) calc(76% - var(--my,0)*11%),
      rgba(var(--teal-rgb),.32),transparent 60%),
    radial-gradient(46% 36% at calc(16% - var(--mx,0)*11%) calc(86% + var(--my,0)*11%),
      rgba(var(--violet-rgb),.30),transparent 62%),
    var(--bg);
}
.bgfx::before{
  content:""; position:absolute; inset:-20%;
  background:
    repeating-linear-gradient(0deg,var(--grid) 0 1px,transparent 1px 64px),
    repeating-linear-gradient(90deg,var(--grid) 0 1px,transparent 1px 64px);
  mask-image:radial-gradient(75% 65% at 50% 30%,#000,transparent 85%);
  -webkit-mask-image:radial-gradient(75% 65% at 50% 30%,#000,transparent 85%);
  /* 原 46s：挪 64px 要 46 秒，肉眼判定为静止（用户报「没有动态效果」） */
  animation:drift 14s linear infinite;
}
.bgfx::after{
  content:""; position:absolute; left:50%; top:-30%;
  width:min(120vw,1400px); aspect-ratio:1; translate:-50% 0;
  background:conic-gradient(from 0deg,
    rgba(var(--acc-rgb),.28),transparent 33%,
    rgba(var(--violet-rgb),.25),transparent 66%,
    rgba(var(--teal-rgb),.23),transparent 92%);
  filter:blur(90px); opacity:.5;
  /* 原 90s：转一圈要 90 秒，等于不动 */
  animation:spin 24s linear infinite;
}
@keyframes drift{ to{ transform:translate3d(64px,64px,0); } }
@keyframes breathe{ 0%,100%{ opacity:.55; } 50%{ opacity:.95; } }
@keyframes glowpulse{ 0%,100%{ opacity:.72; } 50%{ opacity:1; } }
@keyframes spin{ to{ transform:rotate(360deg); } }

/* ── 4. 顶栏 ─────────────────────────────────────────────────────────── */
.topbar{
  position:sticky; top:0; z-index:60;
  background:rgba(var(--bg-rgb),.82);
  backdrop-filter:saturate(180%) blur(14px);
  -webkit-backdrop-filter:saturate(180%) blur(14px);
}
.topbar .wrap{
  display:flex; align-items:center; gap:20px;
  height:64px;
}
.topbar-line{
  display:block; height:1px;
  background:linear-gradient(90deg,transparent,var(--line),transparent);
}
.brand{ display:flex; align-items:center; gap:13px; margin-right:auto; }
/* 页头 logo 用的是蜻蜓伴读自带的品牌图（青色 + 透明底），所以这里不再套强调色
   瓦片：青色压在红色强调上会打架，而且图自带颜色，深浅两个主题都不用改色。 */
/* 46px：64px 顶栏内能放下的上限附近，再大会和导航抢高度；
   top:88px（64+24）是 side-card 吸顶的锚点，顶栏高度不能改 */
.brand-mark{
  width:46px; height:46px; display:grid; place-items:center;
  transition:transform .3s var(--ease);
}
.brand-mark img{ width:46px; height:46px; display:block; }
.brand:hover .brand-mark{ transform:rotate(-8deg) scale(1.06); }
/* 品牌名一行到底（明确要求：原来上下两行不好看）。
   .brand 已经 margin-right:auto 把剩余宽度推给它，这里 nowrap + 省略号兜住极窄屏 */
.brand-txt{
  min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  font-size:clamp(17px,2vw,22px); font-weight:800; letter-spacing:-.01em;
  color:var(--ink);
}

.nav{ display:flex; gap:4px; }
.nav a{
  padding:7px 14px; border-radius:99px; font-size:14.5px; font-weight:600;
  color:var(--ink-2); transition:.22s var(--ease);
}
.nav a:hover{ color:var(--ink); background:var(--line-2); }
.nav a.on{ color:var(--acc); background:rgba(var(--acc-rgb),.12); }
/* 按压反馈统一放一处：hover 只说明「可点」，按下去才算点上了 */
.nav a:active,.chip:active,.ibtn:active{ scale:.955; transition-duration:.06s; }
.nav a.on:active{ scale:.98; }

.tools{ display:flex; gap:6px; }
.ibtn{
  width:36px; height:36px; display:grid; place-items:center;
  border:1px solid var(--line); border-radius:10px;
  background:var(--panel); color:var(--ink-2); cursor:pointer;
  transition:.22s var(--ease);
}
.ibtn:hover{ color:var(--acc); border-color:rgba(var(--acc-rgb),.45); translate:0 -1px; }
.burger{ display:none; flex-direction:column; gap:4px; }
.burger span{ width:16px; height:1.7px; background:currentColor; border-radius:2px; transition:.25s var(--ease); }

/* ── 5. Hero ─────────────────────────────────────────────────────────── */
.hero{ position:relative; padding:clamp(48px,9vw,104px) 0 clamp(34px,5vw,56px); overflow:hidden; }
.hero-bg{ position:absolute; inset:0; pointer-events:none; }
.hero-bg .layer{
  position:absolute; border-radius:50%; filter:blur(46px); opacity:.72;
  /* 只动 opacity，绝不碰 transform —— l1/l2/l3 的 transform 已被滚动视差
     （.motion .hero-bg .l1{ transform:... }）占用，动画一碰就互相覆盖。
     三块给不同 delay 错开相位，避免同步闪烁显得机械。 */
  animation:breathe 8s ease-in-out infinite;
}
.hero-bg .l2{ animation-delay:-2.7s; }
.hero-bg .l3{ animation-delay:-5.3s; }
.hero-bg .l1{ width:min(46vw,430px); aspect-ratio:1; left:-6%; top:2%;
  background:rgba(var(--acc-rgb),.5); }
.hero-bg .l2{ width:min(34vw,320px); aspect-ratio:1; right:4%; top:-8%;
  background:rgba(var(--violet-rgb),.44); }
.hero-bg .l3{ width:min(30vw,260px); aspect-ratio:1; right:22%; bottom:-14%;
  background:rgba(var(--teal-rgb),.42); }
.hero-bg .grid{
  position:absolute; inset:0;
  background:
    repeating-linear-gradient(0deg,var(--grid) 0 1px,transparent 1px 72px),
    repeating-linear-gradient(90deg,var(--grid) 0 1px,transparent 1px 72px);
  mask-image:linear-gradient(#000 20%,transparent 92%);
  -webkit-mask-image:linear-gradient(#000 20%,transparent 92%);
}
.hero-bg .glow{
  animation:glowpulse 11s ease-in-out infinite;
  position:absolute; left:50%; top:12%; width:min(90vw,900px); aspect-ratio:2.4;
  translate:-50% 0; border-radius:50%;
  background:radial-gradient(closest-side,
              rgba(var(--acc-rgb),.28) 0%,
              rgba(var(--violet-rgb),.28) 46%,
              rgba(var(--teal-rgb),.24) 74%,
              transparent 100%);
  filter:blur(40px);
}

/* 视差：JS 写 --sp（0→1 的滚动进度），层各自平移。移动端整段停用 */
.hero-in,.hero-foot{ position:relative; z-index:1; }
.hero-in{ display:grid; grid-template-columns:1.15fr .85fr; gap:clamp(24px,5vw,60px); align-items:center; }
.motion .hero-bg .l1{ transform:translate3d(0,calc(var(--sp,0) * -46px),0); }
.motion .hero-bg .l2{ transform:translate3d(0,calc(var(--sp,0) * 34px),0); }
.motion .hero-bg .l3{ transform:translate3d(0,calc(var(--sp,0) * -64px),0); }
.motion .hero-side{ transform:translate3d(0,calc(var(--sp,0) * -26px),0); }

.eyebrow{
  font-family:var(--font-mono); font-size:12.5px; letter-spacing:.14em;
  text-transform:uppercase; color:var(--acc); margin:0 0 16px; font-weight:600;
}
.hero h1{
  font-size:clamp(44px,8.4vw,88px);
  letter-spacing:-.045em; margin-bottom:6px;
}
.h1-sub{
  display:block; font-size:clamp(19px,2.9vw,30px); font-weight:600;
  letter-spacing:-.02em; color:var(--ink-2); margin-top:12px; line-height:1.4;
}
.lede{
  font-size:clamp(15.5px,1.7vw,18.5px); color:var(--ink-2);
  max-width:56ch; margin:22px 0 0;
}
.lede strong{ color:var(--ink); }

.hero-cta{ display:flex; flex-wrap:wrap; gap:12px; margin-top:32px; }

/* ── 首屏轮播：默认竖排列表且全部可见，JS 加 .js-on 后才叠成轮播 ──────
   为什么默认可见：这站的入场动画曾经是 JS 驱动，JS 一断整屏白屏。
   现在一律「先保证看得见，再谈动画」，轮播只是装饰性增强。 */
.hero-side{ display:flex; flex-direction:column; gap:14px; align-self:center; }
.hero-carousel{ display:grid; gap:14px; }

.slide{
  display:grid; grid-template-columns:88px 1fr; gap:16px; align-items:center;
  padding:16px 18px; border-radius:var(--r-lg);
  background:var(--panel-solid); border:1px solid var(--line);
  box-shadow:var(--shadow); transition:.3s var(--ease);
}
.slide:hover{ border-color:rgba(var(--acc-rgb),.4); }
.slide-shot{
  /* 宽高跟着列宽走，不写死 px：原来列给了 104px 却把图锁在 74px，
     既显小又空出 30px。100% + aspect-ratio 让两档断点自动对齐列宽。 */
  width:100%; height:auto; aspect-ratio:1; border-radius:15px; overflow:hidden;
  display:grid; place-items:center;
  /* 必须是强调色实底，不能用淡渐变：原来是 acc 6%~30% 的渐变，
     浅色下两端几乎纯白，白字直接消失（实测 1.6:1）。
     换成「强调色 → 加深/提亮 26%」，浅色配白字、深色配深字都压得住。 */
  /* 74% 强调色 + 26% 黑，预计算成 --acc-shade（color-mix 老内核不支持） */
  background:linear-gradient(140deg, var(--acc), var(--acc-shade));
}
[data-theme=dark] .slide-shot{
  background:linear-gradient(140deg, var(--acc), var(--acc-tint));
}
.slide-shot img{ width:100%; height:100%; object-fit:cover; display:block; }
.slide-glyph{
  font-size:32px; font-weight:800; color:var(--on-acc); letter-spacing:0;
  text-shadow:0 2px 10px rgba(0,0,0,.26);   /* 浅底白字要自带一层暗晕，否则压不住渐变 */
}
[data-theme=dark] .slide-glyph{ text-shadow:none; }  /* 深底深字不需要暗晕 */
.slide-tag{
  font-family:var(--font-mono); font-size:11px; letter-spacing:.08em;
  color:var(--acc); font-weight:700;
}
.slide-body h3{ font-size:19px; margin:5px 0 6px; letter-spacing:-.02em; }
.slide-body p{
  margin:0; font-size:14px; color:var(--ink-2); line-height:1.62;
  /* 3 行而不是 2 行：摘要现在写实了，压成 2 行会把信息砍掉，
     也让卡片下沿留出一截空白 */
  display:-webkit-box; -webkit-line-clamp:3; -webkit-box-orient:vertical; overflow:hidden;
}
.slide-go{ display:inline-block; margin-top:8px; font-size:13.5px; font-weight:650; color:var(--acc); }

/* JS 接管：叠成一张，只露 .on，其余仍然留在 DOM 里（可被搜索引擎读到） */
/* 叠放改用 grid 同格，不再 absolute + min-height。
   实测最满的一张内容只有 172px，而拍死的 min-height 是 240 —— 凭空多出
   68px 空档，第一屏看着就「散」。同格叠放让容器高度由内容自己决定，
   既消掉空档，也不怕某张换行更多后溢出到圆点上。 */
.hero-side.js-on .hero-carousel{ display:grid; }
.hero-side.js-on .slide{
  grid-area:1/1; opacity:0; visibility:hidden;
  grid-template-columns:124px 1fr;
  transition:opacity .5s var(--ease), visibility .5s;
}
.hero-side.js-on .slide.on{ opacity:1; visibility:visible; }

/* 控制条只在 JS 接管后出现；JS 没跑就没有摆着不管用的按钮 */
.carousel-nav{ display:none; align-items:center; gap:14px; justify-content:flex-end; }
.hero-side.js-on .carousel-nav{ display:flex; }
.dots{ display:flex; gap:0; align-items:center; }
/* 圆点视觉只有 11px，但点击区必须 24×24（WCAG 2.5.8 / axe target-size）。
   所以按钮本体撑到 24、真正的圆点用 ::before 画在正中，视觉不变、够点。 */
.dot{
  position:relative; width:24px; height:24px; padding:0; cursor:pointer;
  border:0; background:transparent;
}
.dot::before{
  content:""; position:absolute; left:50%; top:50%; translate:-50% -50%;
  width:11px; height:11px; border-radius:99px;
  border:1px solid rgba(var(--acc-rgb),.55);
  background:transparent; transition:.24s var(--ease);
}
.dot.on::before{ background:var(--acc); border-color:var(--acc); width:20px; }
.c-pause{ width:30px; height:30px; }
.c-pause[aria-pressed="true"]{ background:rgba(var(--acc-rgb),.16); }
.c-pause .i-play{ display:none; }
.c-pause[aria-pressed="true"] .i-pause{ display:none; }
.c-pause[aria-pressed="true"] .i-play{ display:block; }

/* ── 功能介绍 ─────────────────────────────────────────────────────── */
.feats{ display:grid; grid-template-columns:repeat(auto-fit,minmax(270px,1fr)); gap:16px; }
.ft{
  padding:22px 22px 24px; border-radius:var(--r-lg);
  background:var(--panel-solid); border:1px solid var(--line);
  transition:.3s var(--ease);
}
.ft:hover{
  translate:0 -4px; box-shadow:var(--shadow-lift);
  border-color:rgba(var(--acc-rgb),.34);
}
.ftn{ font-family:var(--font-display); font-size:12.5px; letter-spacing:.16em;
  color:var(--acc); font-weight:700; }
.ft h3{ font-size:17.5px; margin:9px 0 8px; letter-spacing:-.02em; }
.ft p{ margin:0; font-size:14.5px; color:var(--ink-2); line-height:1.72; }

/* ── 界面截图 ─────────────────────────────────────────────────────── */
.shots-wrap{ margin-top:clamp(34px,4.5vw,54px); }
.shots{ display:grid; grid-template-columns:repeat(auto-fit,minmax(300px,1fr)); gap:16px; }
/* 桌面截图 + 两张竖版成稿：首图通栏，后两张并排，避免 3 列把界面压成缩略图 */
.shots.editorial{ grid-template-columns:repeat(2,1fr); }
.shots.editorial figure:first-child{ grid-column:1/-1; }
@media (max-width:700px){ .shots.editorial{ grid-template-columns:1fr; } .shots.editorial figure:first-child{ grid-column:auto; } }
.shots figure{
  margin:0; border-radius:var(--r-lg); overflow:hidden;
  border:1px solid var(--line); box-shadow:var(--shadow); background:var(--bg-2);
}
.shots img{ width:100%; height:auto; display:block; }
.shots figcaption{
  padding:11px 15px; font-size:13.5px; font-weight:600; letter-spacing:.01em;
  color:var(--ink-2); background:var(--panel); border-top:1px solid var(--line);
}

/* 联系二维码：只放关于页一处，贴两个产品页就重复了（二维码必须留白底才扫得出来） */
.qr-row{ display:grid; grid-template-columns:repeat(auto-fit,minmax(168px,1fr));
         gap:16px; max-width:660px; }
.qr{
  margin:0; border:1px solid var(--line); border-radius:var(--r-lg);
  overflow:hidden; background:var(--panel);
}
.qr img{ width:100%; height:auto; display:block; background:#fff; }
.qr figcaption{
  display:flex; flex-direction:column; gap:2px;
  padding:12px 15px; border-top:1px solid var(--line);
}
.qr figcaption b{ font-size:14.5px; color:var(--ink); }
.qr figcaption span{ font-size:12.5px; color:var(--faint); }

.hero-foot{ margin-top:clamp(34px,5vw,56px); }
.stats{ display:grid; grid-template-columns:repeat(4,1fr); gap:14px; margin:0;
  padding-top:26px; border-top:1px solid var(--line); }
.stats div{ display:flex; flex-direction:column; }
.stats dt{
  font-family:var(--font-display); font-size:clamp(30px,4.4vw,46px);
  font-weight:700; letter-spacing:-.03em; color:var(--acc); line-height:1;
}
.stats dd{ margin:7px 0 0; font-size:13px; color:var(--faint); }

/* ── 6. 段落骨架 ─────────────────────────────────────────────────────── */
/* 段间距收紧：8vw→6vw、104→84。上一版段与段之间空得像翻页，散就散在这 */
.sec{ padding:clamp(44px,6vw,84px) 0; position:relative; }
.sec.tight{ padding-top:clamp(24px,4vw,44px); }
.sec + .sec{ border-top:1px solid var(--line-2); }

.sec-hd{ max-width:64ch; margin-bottom:clamp(30px,4vw,50px); }
.sec-no{
  display:inline-block; font-family:var(--font-display); font-size:13px;
  letter-spacing:.2em; text-transform:uppercase; color:var(--acc);
  padding-bottom:14px; font-weight:700;
}
.sec-hd h2{ font-size:clamp(27px,4.2vw,42px); letter-spacing:-.035em; }
.sec-hd p{ margin:13px 0 0; color:var(--ink-2); font-size:16px; max-width:58ch; }

/* ── 7. 按钮 / 标签 ──────────────────────────────────────────────────── */
.btn{
  display:inline-flex; align-items:center; gap:9px;
  padding:12px 22px; border-radius:99px; font-size:15px; font-weight:650;
  border:1px solid var(--line); background:var(--panel-solid); color:var(--ink);
  transition:.24s var(--ease); cursor:pointer;
}
.btn i{
  font-style:normal; font-family:var(--font-display); font-size:14px;
  color:var(--acc); font-weight:700;
}
.btn:hover{ translate:0 -2px; border-color:rgba(var(--acc-rgb),.5);
  box-shadow:var(--shadow-lift); }
.btn.solid{
  background:var(--acc); border-color:var(--acc);
  color:var(--on-acc); box-shadow:0 10px 26px -12px rgba(var(--acc-rgb),.9);
}
.btn.solid i{ color:currentColor; opacity:.82; }
.btn.solid:hover{ filter:brightness(1.07); }

.chip{
  padding:8px 17px; border-radius:99px; font-size:14px; font-weight:600;
  border:1px solid var(--line); background:var(--panel); color:var(--ink-2);
  cursor:pointer; transition:.22s var(--ease); font-family:inherit;
}
.chip i{ font-style:normal; font-family:var(--font-display); opacity:.6; margin-left:3px; }
.chip:hover{ color:var(--ink); border-color:rgba(var(--acc-rgb),.4); }
.chip.on{ background:var(--ink); color:var(--bg); border-color:var(--ink); }
.filters{ display:flex; flex-wrap:wrap; gap:9px; margin-bottom:34px; }

/* ── 8. 主打（featured）───────────────────────────────────────────────── */
/* 卡顶压一张真实界面截图：纯文字卡在宽屏下会空掉一大半，图文才立得住。
   图用负 margin 顶满卡宽（卡自带 1px border + 24px padding），下方文字沿用
   原 padding —— 没图的项目不渲染 .fimg，不会留空框。
   aspect 用 4/3 而非 16/10：横图（1.31）几乎零裁切，竖图（0.56）还能露出
   状态栏到首屏内容；再扁一档手机截图就只剩一条抬头了。 */
.feat-grid{ display:grid; grid-template-columns:repeat(auto-fit,minmax(300px,1fr)); gap:14px; }
.feat{
  position:relative; display:flex; flex-direction:column; gap:11px;
  padding:24px 24px 22px; border-radius:var(--r-lg);
  background:var(--panel-solid); border:1px solid var(--line);
  box-shadow:var(--shadow); overflow:hidden;
  transition:translate .3s var(--ease), box-shadow .3s var(--ease),
             border-color .3s var(--ease);
}
.feat .fimg{
  margin:-24px -24px 0; position:relative; display:block; overflow:hidden;
  aspect-ratio:4/3; border-bottom:1px solid var(--line-2);
  background:rgba(var(--ink-rgb),.07),var(--panel);
}
.feat .fimg img{
  width:100%; height:100%; display:block;
  object-fit:cover; object-position:top center;   /* 界面标题一律在上方，从下缘裁 */
  transition:transform .55s var(--ease);
}
/* 光从卡面扫过去 —— 悬停时唯一的位移之外的反馈 */
.feat .fimg::after{
  content:""; position:absolute; inset:0; pointer-events:none;
  background:linear-gradient(105deg,transparent 42%,
             rgba(255,255,255,.26) 50%,transparent 58%);
  translate:-130% 0; transition:translate .75s var(--ease);
}
.feat:hover .fimg img{ transform:scale(1.05); }
.feat:hover .fimg::after{ translate:130% 0; }
.feat::before{
  content:""; position:absolute; z-index:2; left:0; top:0; height:3px; width:0;
  background:var(--acc); transition:width .45s var(--ease);
}
.feat:hover{ translate:0 -5px; box-shadow:var(--shadow-lift);
  border-color:rgba(var(--acc-rgb),.34); }
/* 按下去要有回应，不然点了像没点 */
.feat:active{ translate:0 -1px; transition-duration:.07s; box-shadow:var(--shadow); }
.feat:hover::before{ width:100%; }
.feat .fno{ font-family:var(--font-display); font-size:12.5px; letter-spacing:.16em;
  color:var(--faint); }
.feat h3{ font-size:21px; letter-spacing:-.025em; }
.feat p{ margin:0; font-size:14.5px; color:var(--ink-2); line-height:1.7; flex:1; }
.feat .tags{ display:flex; flex-wrap:wrap; gap:6px; }
.tag{
  font-family:var(--font-mono); font-size:11px; padding:3px 9px;
  border-radius:6px; background:rgba(var(--acc-rgb),.1);
  color:var(--acc); font-weight:600;
}
.feat .go{ display:inline-flex; align-items:center; gap:7px; font-size:14px;
  font-weight:650; color:var(--acc); }
.feat .go svg{ transition:transform .25s var(--ease); }
.feat:hover .go svg{ transform:translateX(4px); }

/* ── 9. 索引行（全站最有辨识度的一块）────────────────────────────────── */
.idx{ list-style:none; margin:0; padding:0; counter-reset:row; }
.idx li{ counter-increment:row; }
.idx a{
  /* 分类/平台/状态三列锁死列宽：写 auto 的话每行按自己那格的内容各自撑开，
     分类与状态就会逐行左右窜 —— 这就是「看着不齐」的来源。
     宽度取各列实测最宽（分类 65 / 平台 67 / 状态 60）再留几像素，
     访客机上字体回退略有差异也不至于压出格；超了由 overflow 兜底。 */
  display:grid; grid-template-columns:auto minmax(0,1fr) 74px 78px 66px auto;
  gap:clamp(12px,2.2vw,26px);
  align-items:center; padding:19px 16px; margin-inline:-16px;
  border-top:1px solid var(--line-2); position:relative; transition:.26s var(--ease);
}
.idx li:last-child a{ border-bottom:1px solid var(--line-2); }
.idx a::before{
  content:""; position:absolute; left:0; top:0; bottom:0; width:0;
  background:rgba(var(--acc-rgb),.07);
  transition:width .34s var(--ease); z-index:-1;
}
.idx a:hover::before{ width:100%; }
.idx .n{
  font-family:var(--font-display); font-size:14px; color:var(--faint);
  min-width:30px; font-weight:700;
}
.idx .n::before{ content:counter(row,decimal-leading-zero); }
.idx .t{ display:flex; flex-direction:column; gap:3px; min-width:0; }
.idx .t b{ font-size:clamp(17px,2.1vw,20.5px); font-weight:700; letter-spacing:-.02em; }
.idx .t span{ font-size:13.5px; color:var(--faint); line-height:1.55;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.idx .c{ font-family:var(--font-mono); font-size:11.5px; color:var(--acc); white-space:nowrap;
  overflow:hidden; text-overflow:ellipsis; }
.idx .s{
  font-size:12.5px; padding:4px 11px; border-radius:99px; white-space:nowrap;
  border:1px solid var(--line); color:var(--ink-2); background:var(--panel);
}
.idx .s.live{ color:var(--acc); border-color:rgba(var(--acc-rgb),.42);
  background:rgba(var(--acc-rgb),.09); }
/* 分类/平台/状态的外层容器。桌面让它不产生盒子（display:contents），
   三个格子直接成为栅格项 —— 前面锁死的三列列宽与列间距一个字都不变；
   小屏才生成盒子并转成 flex，把三个短标签收进同一行。 */
.idx .m{ display:contents; }
/* 平台标签：和页头那枚 .page-tag.plat 同一套实心主题色块。
   浅色主题强调色深 → 白字，深色主题强调色被提亮 → 翻转成深字。 */
.idx .p{
  font-size:12.5px; padding:4px 11px; border-radius:99px; white-space:nowrap;
  background:var(--acc); color:var(--on-acc); border:1px solid var(--acc);
  overflow:hidden; text-overflow:ellipsis;
}
.idx a:hover .t b{ color:var(--acc); }
.idx .arw{ opacity:0; translate:-8px 0; transition:.26s var(--ease); color:var(--acc); }
.idx a:hover .arw{ opacity:1; translate:0 0; }
.idx li.hidden{ display:none; }

/* ── 10. 作品页分组 ──────────────────────────────────────────────────── */
.group{ margin-bottom:clamp(34px,5vw,56px); }
.group.hidden{ display:none; }
.group-hd{
  display:flex; align-items:baseline; gap:14px; padding-bottom:14px;
  margin-bottom:6px; border-bottom:1.5px solid var(--line);
}
.group-hd h2{ font-size:clamp(20px,2.6vw,25px); }
.group-hd span{ font-size:13.5px; color:var(--faint); }
.group-hd .cnt{ margin-left:auto; font-family:var(--font-display);
  font-size:14px; color:var(--acc); font-weight:700; }

/* ── 11. 写作 ────────────────────────────────────────────────────────── */
.write-grid{ display:grid; grid-template-columns:repeat(auto-fit,minmax(280px,1fr)); gap:18px; }
.write-card{
  display:flex; flex-direction:column; gap:9px; padding:24px;
  border-radius:var(--r-lg); background:var(--panel-solid);
  border:1px solid var(--line); transition:.3s var(--ease);
}
.write-card:hover{ translate:0 -4px; box-shadow:var(--shadow-lift);
  border-color:rgba(var(--acc-rgb),.34); }
.write-card .wc-top{ display:flex; align-items:center; gap:9px;
  font-family:var(--font-mono); font-size:11.5px; color:var(--acc); letter-spacing:.08em; }
.write-card h3{ font-size:19px; }
.write-card p{ margin:0; font-size:14.5px; color:var(--ink-2); }
.write-card .go{ margin-top:4px; font-size:14px; font-weight:650; color:var(--acc); }

.notice{
  display:flex; flex-direction:column; gap:8px;
  padding:22px 24px; border-radius:var(--r-lg); margin-bottom:clamp(30px,4vw,46px);
  /* rgba(acc,.07) 叠在不透明 panel-solid 上 == color-mix(acc 7%,panel-solid)，
     预乘 alpha 与背景多层叠加同一算法，精确等价。 */
  background:rgba(var(--acc-rgb),.07),var(--panel-solid);
  border:1px solid rgba(var(--acc-rgb),.26);
}
.notice b{ font-size:15px; color:var(--acc); }
.notice p{ margin:0; font-size:14.5px; color:var(--ink-2); }

.afdian-box{
  display:flex; flex-wrap:wrap; align-items:center; gap:22px; justify-content:space-between;
  padding:clamp(24px,4vw,38px); border-radius:var(--r-lg);
  background:var(--panel-solid); border:1px solid var(--line); box-shadow:var(--shadow);
}
.afdian-box b{ font-family:var(--font-mono); font-size:clamp(16px,2.4vw,22px);
  letter-spacing:-.02em; color:var(--acc); }
.afdian-box p{ margin:8px 0 0; font-size:14.5px; color:var(--ink-2); max-width:56ch; }

.more{ margin-top:30px; }

/* ── 12. 内页头 ──────────────────────────────────────────────────────── */
.page-head{
  padding:clamp(38px,6vw,70px) 0 clamp(26px,4vw,42px);
  position:relative; overflow:hidden;
}
.page-head::after{
  content:""; position:absolute; left:0; right:0; bottom:0; height:1px;
  background:linear-gradient(90deg,transparent,var(--line),transparent);
}
.crumb{ display:flex; flex-wrap:wrap; align-items:center; gap:9px;
  font-size:13.5px; color:var(--faint); margin-bottom:24px; }
.crumb a:hover{ color:var(--acc); }
.crumb i{ font-style:normal; opacity:.5; }
.crumb span{ color:var(--ink-2); }

.page-hd h1{ font-size:clamp(34px,6.2vw,60px); letter-spacing:-.04em; }
/* 中文为主的状态/栏目字样，等宽字打中文会掉回系统默认字形，加字距更散 ——
   换成卡片正文同款无衬线。 */
.page-tag{
  display:inline-block; margin-bottom:16px; padding:5px 14px; border-radius:99px;
  font-family:var(--font-sans); font-size:12.5px; letter-spacing:.02em;
  background:rgba(var(--acc-rgb),.12); color:var(--acc);
  border:1px solid rgba(var(--acc-rgb),.32); font-weight:600;
}
.page-tag.ext{ background:var(--line-2); color:var(--ink-2); border-color:var(--line); }
/* 平台徽章用实心主题色块，和要点卡的行标签一套；
   浅色主题强调色深 → 白字，深色主题强调色被提亮 → 翻转成深字。 */
.page-tag.plat{ background:var(--acc); color:var(--on-acc); border-color:var(--acc); }
.page-tag + .page-tag{ margin-left:8px; }

.meta-row{ display:flex; flex-wrap:wrap; gap:10px 26px; margin-top:26px; }
.meta{ font-size:14px; color:var(--ink-2); }
.meta b{ color:var(--faint); font-weight:600; margin-right:8px;
  font-family:var(--font-mono); font-size:11.5px; letter-spacing:.08em; }
.link-row{ display:flex; flex-wrap:wrap; gap:11px; margin-top:28px; }
.top10-data{ display:none; margin-top:16px; background:#111118; border:1px solid #2a2a35;
  border-radius:8px; padding:12px 14px; color:#c8d0e0; font-family:monospace; font-size:12px;
  line-height:1.6; white-space:pre-wrap; word-break:break-word; text-align:left;
  user-select:text; -webkit-user-select:text; }
.top10-data.show{ display:block; }

/* ── 13. 详情两栏 ────────────────────────────────────────────────────── */
.two-col{ display:grid; grid-template-columns:1.55fr .95fr; gap:clamp(26px,5vw,58px);
  align-items:start; }

.prose{ font-size:16.5px; color:var(--ink-2); line-height:1.85; }
.prose p{ margin:0 0 20px; }
.prose h2 + p{ font-size:18.5px; color:var(--ink); line-height:1.75; }
.prose h2{
  font-size:20px; color:var(--ink); margin:38px 0 15px; padding-top:22px;
  border-top:1px solid var(--line-2);
}
.prose h2:first-child{ margin-top:0; padding-top:0; border-top:0; }
.prose strong{ color:var(--ink); }

.stack-block{ margin-top:34px; }
.stack-block h3{ font-family:var(--font-mono); font-size:11.5px; letter-spacing:.14em;
  text-transform:uppercase; color:var(--faint); margin-bottom:12px; font-weight:600; }
.stack-list{ display:flex; flex-wrap:wrap; gap:8px; }

.side-card{
  position:sticky; top:88px; padding:26px 24px; border-radius:var(--r-lg);
  background:var(--panel-solid); border:1px solid var(--line); box-shadow:var(--shadow);
}
.side-card h3{ font-size:13px; font-family:var(--font-mono); letter-spacing:.14em;
  text-transform:uppercase; color:var(--faint); font-weight:600; margin-bottom:16px; }
/* 作品内页要点卡的标题：做成主题色块，和下面的行标签成一套。
   只给它加类，关于页那张 side-card 的标题不动。 */
.side-card h3.card-tag{
  display:inline-block; font-family:var(--font-sans); font-size:13px; font-weight:700;
  letter-spacing:.04em; text-transform:none; color:var(--on-acc); background:var(--acc);
  padding:5px 13px; border-radius:8px;
}
.ticks{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:11px; }
.ticks li{ position:relative; padding-left:24px; font-size:14.5px; color:var(--ink-2);
  line-height:1.6; }
.ticks li::before{
  content:""; position:absolute; left:0; top:.62em; width:11px; height:6px;
  border-left:2px solid var(--acc); border-bottom:2px solid var(--acc);
  rotate:-45deg;
}
/* 事实行：标签在前，值在后。事实只在这里出现一次，散文里不再重复。
   标签用卡片正文的同款字体 —— 等宽字打中文会掉回系统默认字形，再加 .1em 字距
   就散得不成样子。做成主题色块：浅色主题强调色深 → 白字（6:1）；
   深色主题强调色被提亮 → 必须翻转成深字，白字压亮块会掉到 2:1。 */
.ticks.facts li{ padding-left:0; display:flex; gap:12px; align-items:center;
  padding-bottom:11px; border-bottom:1px solid var(--line-2); }
.ticks.facts li:last-child{ padding-bottom:0; border-bottom:0; }
.ticks.facts li::before{ display:none; }
.ticks.facts b{ flex:0 0 auto; display:inline-block; min-width:56px; text-align:center;
  font-family:var(--font-sans); font-size:13px; font-weight:700; letter-spacing:.02em;
  color:var(--on-acc); background:var(--acc); padding:4px 10px; border-radius:8px; line-height:1.35; }
.ticks.links{ gap:7px; }
.ticks.links li{ padding-left:0; }
.ticks.links li::before{ display:none; }
/* 「在别处找到我」这三个是站外落点，做成强调色块，和卡片里其它内容分开。
   浅色主题强调色压得深 → 白字（6:1）；深色主题强调色是提亮过的（#ff7065 这类）
   → 必须配深字，白字压上去对比度会掉到 2:1 以下。 */
.ticks.links a{
  display:flex; flex-direction:column; gap:2px; padding:11px 14px;
  border:1px solid var(--acc); border-radius:11px;
  background:var(--acc); color:var(--on-acc);
  transition:.24s var(--ease);
}
.ticks.links a:hover{ filter:brightness(1.07); translate:0 -2px;
  box-shadow:0 10px 26px -14px rgba(var(--acc-rgb),.9); }
.ticks.links b{ font-size:14.5px; color:currentColor; }
.ticks.links span{ font-size:12.5px; color:currentColor; }
.side-note{ margin:20px 0 0; padding-top:16px; border-top:1px solid var(--line-2);
  font-size:13px; color:var(--faint); line-height:1.7; }

.skills{ display:flex; flex-wrap:wrap; gap:9px; margin-top:-4px; }
.skills span{
  padding:8px 15px; border-radius:99px; font-size:14px; font-weight:600;
  background:var(--panel-solid); border:1px solid var(--line); color:var(--ink-2);
  transition:.22s var(--ease);
}
.skills span:hover{ color:var(--acc); border-color:rgba(var(--acc-rgb),.44);
  translate:0 -2px; }

/* ── 13b. 产品页章节（步骤条 / 更新日志 / 常见问题 / 说明）
   两个旧独立站（蜻蜓伴读、TTBOX）正文搬进来后的样子，只有这两页
   会输出。强调色在这里只允许挂在 ≥19px 粗体上 —— 那是「大字」阈值 3:1，
   而强调色做 15px 小字贴着 4.5 的边，换个主题就可能掉下去。 */
.steps{ list-style:none; margin:0; padding:0; display:grid; }
.steps > li{
  display:grid; grid-template-columns:clamp(44px,7vw,78px) minmax(0,1fr);
  gap:clamp(13px,2vw,26px); align-items:start;
  padding:clamp(17px,2.3vw,25px) 0;
  border-top:1px solid var(--line-2);
}
.steps > li:first-child{ border-top:0; padding-top:0; }
.steps .sn{
  font-family:var(--font-display); font-weight:800; line-height:.95;
  font-size:clamp(21px,3vw,30px); letter-spacing:-.05em; color:var(--acc);
}
.steps h3{ margin:0 0 7px; font-size:clamp(16.5px,2vw,20px); letter-spacing:-.02em; }
.steps p{ margin:0; color:var(--ink-2); font-size:15.5px; line-height:1.75; max-width:62ch; }

.changelog{ list-style:none; margin:0; padding:0; display:grid; gap:12px; }
.changelog > li{
  display:grid; gap:11px;
  padding:clamp(15px,2vw,20px) clamp(16px,2vw,24px);
  background:var(--panel); border:1px solid var(--line-2); border-radius:var(--r);
}
.changelog .clv{
  font-family:var(--font-display); font-weight:800; font-size:19px;
  letter-spacing:-.02em; color:var(--acc); justify-self:start; line-height:1.2;
}
.changelog li ul{ margin:0; padding:0; list-style:none; display:grid; gap:7px; }
.changelog li ul li{
  color:var(--ink-2); font-size:15.5px; line-height:1.75;
}
.changelog li ul li::before{
  content:""; display:inline-block; width:5px; height:5px; border-radius:50%;
  background:var(--acc); vertical-align:.34em; margin-right:9px;
}
.changelog .clt b{
  display:block; margin-bottom:9px; font-size:15.5px; font-weight:700;
  letter-spacing:-.01em; color:var(--ink);
}
@media (min-width:700px){
  .changelog > li{ grid-template-columns:minmax(0,auto) minmax(0,1fr);
    gap:4px 26px; align-items:start; }
}

.faq{ display:grid; gap:11px; }
.faq details{
  background:var(--panel); border:1px solid var(--line-2);
  border-radius:var(--r); transition:border-color .26s var(--ease);
}
.faq details[open]{ border-color:rgba(var(--acc-rgb),.4); }
.faq summary{
  list-style:none; cursor:pointer; display:flex; gap:16px;
  align-items:center; justify-content:space-between;
  padding:16px clamp(16px,2vw,22px); font-size:16px; font-weight:650;
  letter-spacing:-.01em;
  transition:background .2s var(--ease);
}
.faq summary::-webkit-details-marker{ display:none; }
/* 悬停给底色不给文字色：换色要在 16px 正文上重过 4.5:1，不值当 */
.faq summary:hover{ background:rgba(var(--acc-rgb),.08); }
.faq summary::after{
  content:"+"; flex:none; color:var(--acc);
  font-size:24px; font-weight:700; line-height:1;
  transition:transform .28s var(--ease);
}
.faq details[open] summary::after{ transform:rotate(45deg); }
.faq details > div{
  padding:0 clamp(16px,2vw,22px) 18px; color:var(--ink-2);
  font-size:15.5px; line-height:1.8; max-width:74ch;
}

.disclaimer{
  margin:0; max-width:82ch; padding:clamp(18px,2.4vw,24px) clamp(18px,2.4vw,26px);
  background:var(--panel); border:1px solid var(--line-2);
  border-left:3px solid var(--acc); border-radius:var(--r);
  color:var(--ink-2); font-size:15px; line-height:1.85;
}
.grp-grid{ display:grid; gap:10px; }
.grp-card{ background:#1a1a22; border:1px solid #2a2a35; border-radius:10px; padding:14px; }
.grp-card b{ display:block; font-size:13px; color:#b0b8c8; margin-bottom:8px; }
.grp-text{ width:100%; max-width:100%; background:#111118; border:1px solid #2a2a35; border-radius:6px; padding:10px 12px; font-family:monospace; font-size:12px; line-height:1.55; color:#c8d0e0; overflow-x:auto; overflow-y:hidden; white-space:pre-wrap; word-break:break-word; resize:none; cursor:text; min-height:72px; box-sizing:border-box; user-select:text !important; -webkit-user-select:text !important; -moz-user-select:text !important; -ms-user-select:text !important; }
.grp-text:focus{ outline:2px solid #3a7ae4; }
.grp-text.selected{ outline:3px solid #3a7ae4; background:#16162a; transition:outline .15s ease; }
.grp-line{ display:flex; align-items:center; gap:10px; margin-top:8px; flex-wrap:wrap; }
.grp-label{ font-size:11px; color:#777; flex-shrink:1; }
.cp-btn{ flex:none; height:30px; padding:0 14px; font-size:12px; background:#2a7ae4; color:#fff; border:none; border-radius:6px; cursor:pointer; white-space:nowrap; }
.grp-hint{ font-size:11px; color:#777; margin-top:6px; }
.cp-icon-btn{ position:absolute; top:8px; right:8px; height:28px; width:28px; padding:0; font-size:14px; background:#2a7ae4; color:#fff; border:none; border-radius:6px; cursor:pointer; line-height:28px; text-align:center; white-space:nowrap; flex:none; }
.grp-card{ position:relative; background:#1a1a22; border:1px solid #2a2a35; border-radius:10px; padding:36px 14px 14px; }

.disclaimer p{ margin:0; }
.disclaimer ol{ margin:0; padding-left:1.35em; display:grid; gap:12px; }
.disclaimer li{ color:var(--ink-2); font-size:15px; line-height:1.85; }

/* ── 14. 翻页 / CTA ──────────────────────────────────────────────────── */
.pager{ border-top:1px solid var(--line-2); padding:0; }
.pager .wrap{ display:grid; grid-template-columns:1fr auto 1fr; gap:14px; align-items:stretch; }
.pg{
  display:flex; flex-direction:column; gap:4px; justify-content:center;
  padding:24px 4px; transition:.24s var(--ease);
}
.pg small{ font-family:var(--font-mono); font-size:11px; color:var(--faint); letter-spacing:.1em; }
.pg span{ font-size:17px; font-weight:700; letter-spacing:-.02em; }
.pg:hover span{ color:var(--acc); }
.pg.next{ text-align:right; }
.pg.mid{ text-align:center; align-items:center; }
.pg.mid span{ font-size:14.5px; color:var(--ink-2); font-weight:600; }

.cta-sec{ padding-bottom:clamp(56px,8vw,96px); }
.cta-box{
  display:flex; flex-wrap:wrap; gap:26px; align-items:center; justify-content:space-between;
  padding:clamp(28px,5vw,52px); border-radius:calc(var(--r-lg) + 8px);
  background:
    linear-gradient(135deg,rgba(var(--acc-rgb),.12),rgba(var(--acc-rgb),.04)),
    var(--panel-solid);
  border:1px solid rgba(var(--acc-rgb),.26);
}
.cta-box h2{ font-size:clamp(24px,3.6vw,36px); letter-spacing:-.03em; }
.cta-box p{ margin:10px 0 0; color:var(--ink-2); font-size:15.5px; }
.cta-acts{ display:flex; gap:12px; flex-wrap:wrap; }

/* ── 15. 页脚 ────────────────────────────────────────────────────────── */
.foot{ border-top:1px solid var(--line); padding:clamp(42px,6vw,66px) 0 28px;
  background:rgba(var(--bg2-rgb),.7); }
.foot-grid{ display:grid; grid-template-columns:1.5fr repeat(3,1fr); gap:clamp(22px,4vw,44px); }
.foot-mark{ display:block; margin:0 0 12px; border-radius:12px; }
.foot-grid b{ font-size:17px; letter-spacing:-.02em; }
.foot-grid p{ margin:9px 0 0; font-size:14px; color:var(--faint); max-width:34ch; }
/* 页脚用 h3 不用 h4 —— h1→h2→h4 会跳级，无障碍审计会直接判 heading-order 不合格 */
.foot-grid h3{ font-family:var(--font-mono); font-size:11px; letter-spacing:.14em;
  text-transform:uppercase; color:var(--faint); margin-bottom:14px; font-weight:600; }
.foot-grid a{ display:block; font-size:14.5px; color:var(--ink-2); padding:4px 0;
  transition:.2s var(--ease); }
.foot-grid a:hover{ color:var(--acc); translate:3px 0; }
/* 致谢块：复用 .disclaimer 那个盒子，只是里面换成可点的上游链接 */
.disclaimer.credits li{ list-style:none; }
.disclaimer.credits a{
  color:var(--acc); font-weight:650;
  border-bottom:1px solid rgba(var(--acc-rgb),.42);
  transition:border-color .2s var(--ease);
}
.disclaimer.credits a:hover{ border-bottom-color:currentColor; }
.disclaimer.credits span{ color:var(--ink-2); }

.foot-bar{ display:flex; flex-wrap:wrap; gap:10px 24px; justify-content:space-between;
  margin-top:clamp(30px,4vw,48px); padding-top:22px; border-top:1px solid var(--line-2);
  font-size:13px; color:var(--faint); }
/* 备案号：两个号并排，都能点到官方查询 */
.foot-bar .beian{ display:flex; flex-wrap:wrap; gap:6px 18px; }
.foot-bar a{ color:inherit; border-bottom:1px solid transparent; transition:.2s var(--ease); }
.foot-bar a:hover{ color:var(--acc); border-bottom-color:currentColor; }

/* ── 16. 入场动效：纯 CSS 滚动时间轴，不碰 JS ─────────────────────────
   这里刻意不用 IntersectionObserver + .in 那一套：只要内容可见性挂在 JS
   类上，app.js 404、被拦截、或标签页不渲染（rAF/IO 不触发）时就会停在
   opacity:0，整站白屏。改成 CSS 动画后，两条分支的终点都是可见：
     · 支持 animation-timeline：滚动到视口内才播，播完 = 1
     · 不支持（@supports not）：一进页面就播完，播完 = 1
     · 动画被系统关掉：fill 不生效，元素按原样显示 = 1
   四条路都不可能停在透明，所以这里不需要任何兜底 JS。 */
@keyframes rise{ from{ opacity:0; transform:translateY(20px); } to{ opacity:1; transform:translateY(0); } }

@supports (animation-timeline: view()){
  .motion [data-reveal]{
    animation:rise .6s var(--ease) both;
    animation-timeline:view();
    animation-range:entry 0% entry 60%;
  }
}
@supports not (animation-timeline: view()){
  /* 老浏览器没有滚动时间轴，退化成"整页进场播一次就完"，终点同样是可见 */
  .motion [data-reveal]{ animation:rise .6s var(--ease) both; }
}

/* ── 17. 减少动效：进场动画整段关掉，内容直接是最终态 ───────────────── */
@media (prefers-reduced-motion:reduce){
  .motion [data-reveal]{ animation:none !important; opacity:1 !important; translate:0 0 !important; transform:none !important; }
  .bgfx::before,.bgfx::after,
  .hero-bg .layer,.hero-bg .glow{ animation:none !important; }
  /* 轮播在减少动效下由 JS 关掉自动切换，CSS 这里保证叠放状态下仍有淡入淡出的终点 */
  .hero-side.js-on .slide{ transition-duration:.01ms; }
}

/* ── 18. 响应式 ──────────────────────────────────────────────────────── */
@media (max-width:1000px){
  .hero-in{ grid-template-columns:1fr; }
  /* 移动端只关掉视差位移，轮播是内容，绝不能整段 display:none */
  .motion .hero-side{ transform:none; }
  .hero-side{ align-self:stretch; }
  .two-col{ grid-template-columns:1fr; }
  .side-card{ position:static; }
  .foot-grid{ grid-template-columns:1fr 1fr; }
}

@media (max-width:860px){
  .burger{ display:grid; }
  .nav{
    position:absolute; left:0; right:0; top:64px;
    flex-direction:column; gap:2px; padding:12px var(--pad) 18px;
    background:var(--bg-2); border-bottom:1px solid var(--line);
    box-shadow:var(--shadow-lift);
    opacity:0; visibility:hidden; translate:0 -10px; transition:.26s var(--ease);
  }
  .nav.open{ opacity:1; visibility:visible; translate:0 0; }
  .nav a{ padding:12px 14px; border-radius:11px; font-size:16px; }
  .burger[aria-expanded=true] span:nth-child(1){ translate:0 5.7px; rotate:45deg; }
  .burger[aria-expanded=true] span:nth-child(2){ opacity:0; }
  .burger[aria-expanded=true] span:nth-child(3){ translate:0 -5.7px; rotate:-45deg; }

  .stats{ grid-template-columns:repeat(2,1fr); gap:22px 14px; }
  .idx a{ grid-template-columns:auto 1fr; gap:6px 14px; padding:17px 14px; margin-inline:-14px; }
  .idx .m{ display:flex; flex-wrap:wrap; gap:7px 13px; align-items:center;
    grid-column:2; justify-self:start; }
  /* 三个标签在小屏同样锁死宽度（74/78/66，与桌面栅格列宽同一组数字），
     逐行才对得上；总宽 244px，极窄屏放不下时整排换行 —— 每行元素完全相同，
     换行位置也完全相同，行高仍然一致 */
  .idx .c{ width:74px; flex:none; }
  .idx .p{ width:78px; flex:none; }
  .idx .s{ width:66px; flex:none; }
  .idx .arw{ display:none; }
  .idx .t span{ white-space:normal; }
  .pager .wrap{ grid-template-columns:1fr; }
  .pg,.pg.next{ text-align:left; }
  .pg.next{ align-items:flex-start; }
  .pg.mid{ display:none; }
  .cta-box{ flex-direction:column; align-items:flex-start; }
}

@media (max-width:520px){
  .foot-grid{ grid-template-columns:1fr; }
  /* 不整段隐藏品牌副行——「码头哥作品集」是用户指定名称，只是在小屏改小字号 */
  .brand-txt{ font-size:17px; letter-spacing:-.02em; }
  .stats dt{ font-size:32px; }
  .slide{ grid-template-columns:60px 1fr; gap:13px; padding:14px; }
  .slide-shot{ border-radius:13px; }   /* 宽高走基线 100% + aspect-ratio，跟着列宽走；此处再锁 60px 会与 74px 列错位 */
  .slide-glyph{ font-size:26px; }
  .hero-side.js-on .hero-carousel{ min-height:236px; }
  .hero-side.js-on .slide{ grid-template-columns:74px 1fr; }
  .feats{ grid-template-columns:1fr; }
}

/* 打印：只留内容，动效与装饰全去 */
@media print{
  .bgfx,.hero-bg,.topbar,.tools,.pager,.filters{ display:none !important; }
  body{ background:#fff; color:#000; }
  .motion [data-reveal]{ animation:none !important; opacity:1 !important; translate:0 0 !important; transform:none !important; }
}
