/* ============================================================
   阅历 · 阅读长河  ——  暖纸墨书香
   米白纸底 · 墨色衬线 · 朱砂印章 · 泥金书框
   v2：透视纵深水岸 · 水中倒影 · 年份水印
   ============================================================ */

:root {
  --paper: #f4efe3;
  --paper-2: #ece4d3;
  --paper-3: #e6dcc7;
  --ink: #2a2723;
  --ink-2: #4d473d;
  --ink-soft: #7c7466;
  --line: rgba(42, 39, 35, 0.16);
  --line-soft: rgba(42, 39, 35, 0.07);
  --vermilion: #b03a26;          /* 朱砂 · 印章 */
  --vermilion-deep: #8f2d1d;
  --gold: #b3894a;               /* 泥金 · 史诗书框 */
  --gold-soft: #cbb27f;
  --wash: #5f7f86;               /* 黛青 · 河水 */
  --wash-2: #8aa7a8;
  --wash-deep: #4a666e;
  --shadow-book: 0 8px 18px rgba(42, 39, 35, 0.24);
  --shadow-epic: 0 18px 44px rgba(42, 39, 35, 0.32);
  --serif: "Noto Serif SC", "Songti SC", "STSong", "SimSun", serif;
  --callig: "Ma Shan Zheng", "Noto Serif SC", cursive;
  --hand: "Long Cang", "Noto Serif SC", cursive;
  --wl: 62%;                     /* 水面线：JS 会覆写成 px */
}

* { box-sizing: border-box; }
html, body { height: 100%; margin: 0; }

body {
  font-family: var(--serif);
  color: var(--ink);
  background: var(--paper);
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

#app { position: relative; height: 100vh; display: flex; flex-direction: column; }

/* ---------- 纸纹（去掉账本竖线，只留纤维颗粒 + 天光） ---------- */
.stage::before {
  content: "";
  position: absolute; inset: 0;
  pointer-events: none; z-index: 0;
  background:
    radial-gradient(120% 70% at 50% 0%, #f8f4ea 0%, rgba(248,244,234,0) 60%),
    linear-gradient(180deg, #f6f2e8 0%, var(--paper) 48%, #efe8da 100%);
}
.stage::after {
  content: "";
  position: absolute; inset: 0;
  pointer-events: none; z-index: 1;
  mix-blend-mode: multiply; opacity: .55;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)' opacity='0.055'/%3E%3C/svg%3E");
}

/* 四周柔光收边，聚焦中央 */
.vignette {
  position: absolute; inset: 0; z-index: 25; pointer-events: none;
  background:
    linear-gradient(90deg, rgba(244,239,227,.85) 0, rgba(244,239,227,0) 5%,
                    rgba(244,239,227,0) 95%, rgba(244,239,227,.85) 100%),
    linear-gradient(180deg, rgba(244,239,227,.5) 0, rgba(244,239,227,0) 9%);
}

/* ---------- 顶栏 ---------- */
.topbar {
  position: relative; z-index: 40;
  display: flex; align-items: center; justify-content: space-between;
  gap: 20px; flex-wrap: wrap;
  padding: 16px 28px 14px;
  border-bottom: 1px solid var(--line);
  background: linear-gradient(180deg, #f8f4ea 0%, rgba(244,239,227,.9) 100%);
  backdrop-filter: blur(6px);
}
.brand { display: flex; align-items: center; gap: 14px; min-width: 0; }
.seal {
  flex: none;
  width: 52px; height: 52px;
  display: grid; place-items: center;
  background: var(--vermilion);
  color: #f7f1e6;
  font-family: var(--callig);
  font-size: 24px; line-height: 1;
  border-radius: 8px 6px 9px 5px;      /* 不规则印章边 */
  box-shadow: 0 4px 12px rgba(176, 58, 38, 0.35), inset 0 0 0 2px rgba(247,241,230,.25);
  transform: rotate(-2deg);
}
.brand-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.brand-title { font-size: 24px; font-weight: 700; letter-spacing: 6px; }
.brand-sub { color: var(--ink-soft); letter-spacing: 3px; font-family: var(--hand); font-size: 15px; }

.topbar-right { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.stat { font-size: 13px; color: var(--ink-2); letter-spacing: 1px; white-space: nowrap; }
.stat strong { color: var(--vermilion); font-weight: 700; }

.yearnav { display: flex; gap: 4px; }
.yearnav button {
  font-family: var(--serif);
  border: 1px solid var(--line);
  background: transparent; color: var(--ink-2);
  padding: 5px 12px; border-radius: 999px;
  font-size: 13px; letter-spacing: 2px; cursor: pointer;
  transition: all .25s ease;
}
.yearnav button:hover, .yearnav button.on {
  border-color: var(--vermilion); color: var(--vermilion); background: rgba(176,58,38,.06);
}

.ghost-btn {
  font-family: var(--serif);
  border: 1px solid var(--line);
  background: transparent; color: var(--ink-2);
  padding: 6px 14px; border-radius: 999px; font-size: 13px; letter-spacing: 2px;
  cursor: pointer; transition: all .25s ease;
}
.ghost-btn:hover { border-color: var(--ink); color: var(--ink); }

/* ---------- 舞台与世界 ---------- */
/* 舞台内全域禁选：拖动时框选到书名签/刻度会翻出蓝底选中态，很破画面。
   原先只在 .ymark 上加了 user-select:none，其余部分浏览器都当可选文字。
   抽屉不在 .stage 内，所以书名/作者/笔记仍然可以复制。 */
.stage, .stage * {
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}
.stage { position: relative; flex: 1; overflow: hidden; cursor: grab; }
.stage.dragging { cursor: grabbing; }
.stage.dragging .book { transition: none; }
.world {
  position: absolute; top: 0; left: 0; height: 100%;
  transform-origin: 0 0; will-change: transform; z-index: 2;
}

/* ---------- 年份水印（大字沉在纸里） ---------- */
.yearmarks { position: absolute; inset: 0; pointer-events: none; z-index: 1; }
.ymark {
  position: absolute; top: calc(var(--wl) - 300px);
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  transform: translateX(-50%);
  color: rgba(42, 39, 35, 0.055);
  user-select: none;
}
.ymark .ym-num { font-size: 168px; font-weight: 900; letter-spacing: 12px; line-height: .9; }
.ymark .ym-gz { font-family: var(--callig); font-size: 38px; letter-spacing: 10px; opacity: .8; }

/* ---------- 远岸（地平线纵深，仅贴水面一线） ---------- */
.banks { position: absolute; inset: 0; pointer-events: none; z-index: 2; }
.bank-far {
  position: absolute; left: 0; right: 0;
  top: calc(var(--wl) - 46px); height: 46px;
  background: linear-gradient(180deg,
    rgba(138,167,168,0) 0%,
    rgba(138,167,168,.10) 62%,
    rgba(95,127,134,.24) 100%);
}

/* ---------- 远岸山影（极淡，只在水面线附近露出一线，不糊上半部） ---------- */
.mountains {
  position: absolute; left: 0; right: 0;
  top: calc(var(--wl) - 132px); height: 132px;
  z-index: 1; pointer-events: none; overflow: hidden;
}
.mountains::before {
  content: ""; position: absolute; left: -4%; right: -4%; bottom: 0; height: 62%;
  background:
    radial-gradient(58% 100% at 14% 100%, rgba(122,146,150,.20) 0 54%, transparent 78%),
    radial-gradient(46% 100% at 37% 100%, rgba(102,128,134,.16) 0 56%, transparent 80%),
    radial-gradient(64% 100% at 61% 100%, rgba(126,150,152,.18) 0 52%, transparent 76%),
    radial-gradient(42% 100% at 84% 100%, rgba(108,132,138,.15) 0 58%, transparent 82%);
  filter: blur(3px);
  mask-image: linear-gradient(180deg, transparent 0%, #000 55%, #000 100%);
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 55%, #000 100%);
}

/* ---------- 河流 ----------
   河已搬出 .world（见 index.html 注释），铺满整个舞台、不随拖动平移。
   z-index 2：压在书(.world 的 2 里，书自己 20)之下、粒子(1)之上。 */
.river {
  position: absolute; left: 0; right: 0;
  top: var(--wl); bottom: 0;
  pointer-events: none; overflow: hidden; z-index: 2;
  background: linear-gradient(180deg,
    rgba(74,102,110,.52) 0%,
    rgba(74,102,110,.40) 14%,
    rgba(92,120,126,.24) 38%,
    rgba(130,154,154,.10) 62%,
    rgba(170,182,176,.03) 82%,
    rgba(200,204,192,0) 100%);
}
/* 水面线：亮起的一道 */
.riverline {
  position: absolute; left: 0; right: 0; top: 0; height: 2px;
  background: linear-gradient(180deg, rgba(255,255,255,.9), rgba(95,127,134,.6));
  box-shadow: 0 0 10px rgba(255,255,255,.7), 0 1px 3px rgba(60,90,96,.35);
}
/* 流纹：细长横向水痕，越远越密（近乎平行于水面）。
   平移量由 JS 逐帧写进 --flow-a/--flow-b —— 拖动要能实时改流速，
   而 CSS animation 中途改 animation-duration 会跳相位，只能换成 JS 驱动。
   拉伸（湍流感）走 --flow-k：拖得越急纹路被拉得越长。 */
.flow {
  position: absolute; left: -60%; right: -60%; height: 100%; top: 0;
  will-change: transform;
}
.flow-a {
  opacity: .55;
  background:
    repeating-linear-gradient(178.6deg,
      transparent 0 15px, rgba(255,255,255,.30) 15px 17px, transparent 17px 42px);
  transform: translate3d(var(--flow-a, 0px), 0, 0) scaleX(var(--flow-k, 1));
  mask-image: linear-gradient(180deg, rgba(0,0,0,.9) 0%, rgba(0,0,0,.45) 34%, transparent 66%);
  -webkit-mask-image: linear-gradient(180deg, rgba(0,0,0,.9) 0%, rgba(0,0,0,.45) 34%, transparent 66%);
}
.flow-b {
  opacity: .4;
  background:
    repeating-linear-gradient(181.4deg,
      transparent 0 34px, rgba(255,255,255,.22) 34px 37px, transparent 37px 96px);
  transform: translate3d(var(--flow-b, 0px), 0, 0) scaleX(var(--flow-k, 1));
  mask-image: linear-gradient(180deg, rgba(0,0,0,.8) 0%, transparent 52%);
  -webkit-mask-image: linear-gradient(180deg, rgba(0,0,0,.8) 0%, transparent 52%);
}

/* 粼光：水面上缓慢漂移的碎光斑。
   只铺在贴近水面线的一带（越往下水越深越暗，光斑该消失），
   用两层不同频率的 radial-gradient 反向漂移，避免看出重复周期。 */
.glint {
  position: absolute; left: -60%; right: -60%; top: 0; height: 42%;
  opacity: .5; will-change: transform;
  transform: translate3d(var(--glint-x, 0px), 0, 0);
  background:
    radial-gradient(10px 2.4px at 12% 22%, rgba(255,255,255,.85), transparent 70%),
    radial-gradient(7px 2px at 27% 47%, rgba(255,255,255,.7), transparent 70%),
    radial-gradient(13px 2.6px at 41% 15%, rgba(255,255,255,.8), transparent 70%),
    radial-gradient(6px 1.8px at 56% 58%, rgba(255,255,255,.62), transparent 70%),
    radial-gradient(11px 2.4px at 68% 31%, rgba(255,255,255,.78), transparent 70%),
    radial-gradient(8px 2px at 83% 66%, rgba(255,255,255,.6), transparent 70%),
    radial-gradient(12px 2.5px at 94% 40%, rgba(255,255,255,.75), transparent 70%);
  background-size: 520px 100%;
  background-repeat: repeat-x;
  mask-image: linear-gradient(180deg, rgba(0,0,0,.25) 0%, #000 18%, rgba(0,0,0,.5) 58%, transparent 100%);
  -webkit-mask-image: linear-gradient(180deg, rgba(0,0,0,.25) 0%, #000 18%, rgba(0,0,0,.5) 58%, transparent 100%);
}
/* 第二层：更疏、更慢、反向，破掉单层的重复感 */
.glint::after {
  content: ""; position: absolute; inset: 0;
  transform: translate3d(var(--glint-x2, 0px), 0, 0);
  background:
    radial-gradient(16px 3px at 18% 34%, rgba(255,255,255,.5), transparent 72%),
    radial-gradient(9px 2.2px at 49% 12%, rgba(255,255,255,.42), transparent 72%),
    radial-gradient(14px 2.8px at 77% 52%, rgba(255,255,255,.46), transparent 72%);
  background-size: 890px 100%;
  background-repeat: repeat-x;
}

/* ---------- 天空粒子（四季）----------
   在 .stage 下、.world 外：它是"天上"的东西，不该跟着河被拖走，
   也不该随缩放变大变小。
   z-index 1（不是 4）：书虽然写着 z-index 20，但它们关在 z-index:2 的
   .world 里 —— 只要 .sky ≥ 2 就会盖在全部 99 本书的封面上。粒子当远景，
   压在 .world 之下、山影(1)之后；.stage::after 的噪点还会再盖一层，
   粒子跟着一起吃到纸纹，不会浮在画面外。 */
.sky {
  position: absolute; inset: 0; z-index: 1;
  pointer-events: none;
}

/* ---------- 河源题词 / 河口署名 ---------- */
/* 竖排四行，从右往左读（中式）。挂在 .world 里，所以钉在河源那段空水域上。
   默认透明，靠 JS 在拖近时加 .on 淡入 —— "寻他千百度"的过程要留着。 */
.epigraph {
  position: absolute; z-index: 10;
  display: flex; flex-direction: row-reverse; gap: 26px;
  transform: translateX(-50%);
  opacity: 0; transition: opacity 1.4s ease;
  pointer-events: none;
}
.epigraph.on { opacity: 1; }
.ep-col {
  writing-mode: vertical-rl;
  font-family: var(--callig);
  font-size: 34px; letter-spacing: 10px; line-height: 1;
  color: rgba(42, 39, 35, .52);
  text-shadow: 0 1px 0 rgba(255,255,255,.5);
}
/* 后两句是"回首"之后的顿悟，压低一档、稍稍下沉，读起来有停顿 */
.ep-col:nth-child(1), .ep-col:nth-child(2) { margin-top: 34px; opacity: .86; }
/* 「灯火阑珊」：背后透出一点暖光。青碧的水在下半屏，暖光只落在纸底上不打架 */
.epigraph::before {
  content: ""; position: absolute; z-index: -1;
  left: 50%; top: 50%; width: 460px; height: 460px;
  transform: translate(-50%, -50%);
  background: radial-gradient(circle, rgba(214,164,92,.20) 0%, rgba(214,164,92,.08) 38%, transparent 70%);
  opacity: 0; transition: opacity 2.6s ease .6s;
}
.epigraph.on::before { opacity: 1; }

/* 河口署名：字号明显小一号，就是个彩蛋，别喧宾夺主 */
.colophon {
  position: absolute; z-index: 10;
  transform: translateX(-50%);
  writing-mode: vertical-rl;
  font-family: var(--hand);
  font-size: 17px; letter-spacing: 6px; line-height: 1;
  color: rgba(42, 39, 35, .38);
  text-shadow: 0 1px 0 rgba(255,255,255,.5);
  opacity: 0; transition: opacity 1.4s ease;
  pointer-events: none; white-space: nowrap;
}
.colophon.on { opacity: 1; }

/* 竖版：河源在最上方，题词转成横排（竖排会顶到河里去） */
body.vertical .epigraph {
  flex-direction: column; gap: 8px;
  align-items: center; transform: translateX(-50%);
}
body.vertical .ep-col {
  writing-mode: horizontal-tb;
  font-size: 25px; letter-spacing: 6px;
}
body.vertical .ep-col:nth-child(1), body.vertical .ep-col:nth-child(2) { margin-top: 0; }
/* 竖排容器是 row-reverse，改横排后视觉顺序会倒过来，用 order 掰回来 */
body.vertical .ep-col:nth-child(1) { order: 4; }
body.vertical .ep-col:nth-child(2) { order: 3; }
body.vertical .ep-col:nth-child(3) { order: 2; }
body.vertical .ep-col:nth-child(4) { order: 1; }
body.vertical .epigraph::before { width: 320px; height: 320px; }
body.vertical .colophon { writing-mode: horizontal-tb; font-size: 14px; letter-spacing: 4px; }

/* ---------- 标尺：刻度沉入水中 ---------- */
.ruler { position: absolute; inset: 0; pointer-events: none; z-index: 6; }
.tick {
  position: absolute; top: var(--wl);
  transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 5px;
}
.tick::before { content: ""; width: 1px; background: rgba(255,255,255,.5); }
.tick.year::before { height: 30px; background: linear-gradient(180deg, rgba(255,255,255,.85), rgba(255,255,255,0)); }
.tick.month::before { height: 12px; }
.tick .t-label { white-space: nowrap; color: rgba(40,58,62,.62); text-shadow: 0 1px 0 rgba(255,255,255,.45); }
.tick.year .t-label { font-size: 16px; font-weight: 700; color: rgba(35,52,56,.78); letter-spacing: 3px; }
.tick.year .t-gz { font-family: var(--hand); font-size: 13px; color: rgba(40,58,62,.5); letter-spacing: 2px; }
.tick.month .t-label { font-size: 11px; letter-spacing: 1px; }

/* ---------- 模糊日期的「雾带」 ---------- */
.mistlayer { position: absolute; inset: 0; pointer-events: none; z-index: 4; }
.mist-label { z-index: 24; }              /* 标签浮到书之上 */
.mistband {
  position: absolute;
  background:
    radial-gradient(88% 58% at 50% 62%, rgba(252,250,246,.92) 0%, rgba(250,247,241,.66) 46%, rgba(248,245,238,0) 80%),
    linear-gradient(180deg, rgba(246,243,236,0) 0%, rgba(248,245,239,.55) 40%, rgba(244,240,232,.62) 76%, rgba(240,236,227,0) 100%);
  filter: blur(10px);
}
.mistband::after {                        /* 第二层慢飘的雾气，制造流动感 */
  content: ""; position: absolute; inset: -8% -3%;
  background:
    radial-gradient(36% 44% at 20% 56%, rgba(255,253,249,.78), transparent 72%),
    radial-gradient(42% 50% at 55% 44%, rgba(255,253,249,.70), transparent 74%),
    radial-gradient(32% 42% at 84% 60%, rgba(255,253,249,.66), transparent 72%);
  filter: blur(14px);
  animation: drift 26s ease-in-out infinite alternate;
}
@keyframes drift { to { transform: translateX(26px) translateY(-6px); } }
/* 浮在书之前的薄雾：让雾中的书真的"在雾里" */
.mistfront { position: absolute; inset: 0; pointer-events: none; z-index: 12; }
.mistfront .veil {
  position: absolute;
  background:
    radial-gradient(70% 52% at 30% 64%, rgba(250,248,243,.42), transparent 74%),
    radial-gradient(64% 48% at 72% 58%, rgba(250,248,243,.38), transparent 74%);
  filter: blur(16px);
  animation: drift 34s ease-in-out infinite alternate-reverse;
}

.mist-edge {
  position: absolute; bottom: 0; height: 1px; left: 0; right: 0;
  background: repeating-linear-gradient(90deg, rgba(124,116,102,.42) 0 7px, transparent 7px 15px);
}
.mist-label {
  position: absolute; left: 50%; transform: translateX(-50%);
  font-size: 16px; letter-spacing: 3px; color: var(--ink-soft);
  font-family: var(--hand); white-space: nowrap;
  background: rgba(248,245,238,.9); padding: 3px 18px; border-radius: 999px;
  border: 1px dashed var(--line);
}

/* ---------- 书 ---------- */
.books { position: absolute; inset: 0; z-index: 8; }
.book {
  position: absolute;
  transform: translateX(-50%);
  cursor: pointer;
  background: none; border: none; padding: 0;
  transition: transform .35s cubic-bezier(.34,1.4,.64,1);
  --w: 72px; --h: 107px;
}
.book:focus-visible { outline: 2px solid var(--vermilion); outline-offset: 4px; border-radius: 4px; }

.book .cov {
  position: relative; display: block;
  width: var(--w); height: var(--h);
  border-radius: 2px 4px 4px 2px;
  overflow: hidden;
  box-shadow: var(--shadow-book);
  transition: transform .3s cubic-bezier(.34,1.4,.64,1), box-shadow .3s ease;
  background: var(--paper-2);
}
.book .cov img { width: 100%; height: 100%; object-fit: cover; display: block; }
.book .cov::after {                       /* 书脊高光 */
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 6px;
  background: linear-gradient(90deg, rgba(0,0,0,.30), rgba(255,255,255,.16) 55%, rgba(0,0,0,.05));
}
.book:hover { z-index: 20; }
.book:hover .cov { transform: translateY(-9px) rotate(-1.2deg); box-shadow: 0 22px 40px rgba(42,39,35,.34); }

/* 水中倒影：从水面线起算（--sink = 书底到水面的距离） */
.book .refl {
  position: absolute; left: 0; top: calc(100% + var(--sink, 0px));
  width: var(--w); height: calc(var(--h) * .62);
  overflow: hidden; pointer-events: none;
  opacity: .4; filter: blur(1.4px) saturate(.6) brightness(.94);
  mask-image: linear-gradient(180deg, rgba(0,0,0,.95), rgba(0,0,0,.32) 46%, transparent 92%);
  -webkit-mask-image: linear-gradient(180deg, rgba(0,0,0,.95), rgba(0,0,0,.32) 46%, transparent 92%);
}

/* 每本书的着地水波（远处的更小更淡） */
.book::before {
  content: ""; position: absolute; left: 50%;
  top: calc(100% + var(--sink, 0px) - 5px);
  width: calc(var(--w) * 1.5); height: 11px;
  transform: translateX(-50%);
  border-radius: 50%;
  border: 1px solid rgba(255,255,255,.42);
  box-shadow: 0 5px 0 -2px rgba(255,255,255,.24);
  pointer-events: none;
}
/* 立在水里的书，脚下压一点水影 */
.book .cov { --dummy: 0; }
.book .refl img, .book .refl .rf {
  width: var(--w); height: var(--h);
  object-fit: cover; display: block;
  transform: scaleY(-1); transform-origin: top;
  margin-top: calc(var(--h) * -1);
}
.book .refl .rf { display: block; }

/* 书名签 */
.book .tag {
  position: absolute; left: 50%; top: calc(100% + 10px);
  transform: translateX(-50%) translateY(4px);
  background: rgba(30,27,23,.9); color: var(--paper);
  font-size: 12px; letter-spacing: 1px; white-space: nowrap;
  padding: 4px 10px; border-radius: 3px;
  opacity: 0; pointer-events: none;
  transition: opacity .25s ease, transform .25s ease;
  z-index: 22; backdrop-filter: blur(3px);
}
.book:hover .tag, .book.selected .tag { opacity: 1; transform: translateX(-50%) translateY(0); }
.book .tag::before {
  content: ""; position: absolute; left: 50%; top: -4px; transform: translateX(-50%);
  border: 4px solid transparent; border-bottom-color: rgba(30,27,23,.9);
}

/* 体量：常规 / 厚重 / 史诗（尺寸由 JS 给，这里留默认兜底） */
.book.s1 { --w: 94px; --h: 140px; }
.book.s2 { --w: 140px; --h: 210px; z-index: 6; }

/* 史诗 · 泥金重框地标 + 河中涟漪 */
.book.s2 .cov {
  box-shadow: var(--shadow-epic);
  border: 2px solid var(--gold);
  outline: 1px solid rgba(179,137,74,.38); outline-offset: 3px;
}
.book.s2 .cov::before {                   /* 泥金内框 */
  content: ""; position: absolute; inset: 4px; z-index: 2;
  border: 1px solid rgba(179,137,74,.55); border-radius: 2px; pointer-events: none;
}
.book.s2::before {                        /* 镇河之石：更宽更多圈的涟漪 */
  width: calc(var(--w) * 2.05); height: 20px;
  border-color: rgba(255,255,255,.58);
  box-shadow: 0 8px 0 -3px rgba(255,255,255,.36), 0 16px 0 -7px rgba(255,255,255,.22);
}
.book.s1 .cov { box-shadow: 0 12px 26px rgba(42,39,35,.27); }
.book.s1::before { width: calc(var(--w) * 1.7); height: 14px; border-color: rgba(255,255,255,.5); }
/* 远处的水波收小变淡 */
.book.d2::before { opacity: .6; height: 8px; }
.book.d3::before { opacity: .42; height: 6px; }

/* 体量与纵深的尺寸由 JS 行内写 --w/--h（随缩放联动），这里只管质感差异 */
.book.d1 { opacity: .97; }
.book.d2 { opacity: .94; filter: saturate(.94); }
.book.d3 { opacity: .86; filter: saturate(.84); }
.book.d1 .cov, .book.d2 .cov, .book.d3 .cov { box-shadow: 0 7px 16px rgba(42,39,35,.24); }
.book.d2 .refl, .book.d3 .refl { opacity: .18; }

/* 雾中的书（无精确日期） */
.book.fuzzy .cov { box-shadow: 0 6px 16px rgba(42,39,35,.16); }
.book.fuzzy .cov img { filter: saturate(.84) contrast(.95); }
.book.fuzzy::before { opacity: .35; }     /* 雾中的书，水波也朦胧 */
.book.fuzzy .refl { opacity: .2; }

/* 藏书章（挚爱） */
.book .chop {
  position: absolute; right: -7px; top: -7px; z-index: 6;
  width: 26px; height: 26px; display: grid; place-items: center;
  background: var(--vermilion); color: #f7f1e6;
  font-family: var(--callig); font-size: 15px;
  border-radius: 5px 4px 6px 3px;
  box-shadow: 0 3px 8px rgba(176,58,38,.4), inset 0 0 0 1.5px rgba(247,241,230,.3);
  transform: rotate(6deg);
  pointer-events: none;
}
.book.d2 .chop, .book.d3 .chop { width: 19px; height: 19px; font-size: 11px; }

/* 生成的文字封面（无真实封面时兜底） */
.cov.textcov { display: flex; flex-direction: column; justify-content: space-between; padding: 7px 5px; }
.cov.textcov::before {                    /* 兜底封面的细边框，避免大色块空 */
  content: ""; position: absolute; inset: 4px; z-index: 1;
  border: 1px solid rgba(245,239,226,.32); border-radius: 1px; pointer-events: none;
}
.cov.textcov .tc-title {
  font-family: var(--serif); font-weight: 700; color: #f5efe2;
  font-size: calc(var(--w) * .19); line-height: 1.3; letter-spacing: 2px;
  writing-mode: vertical-rl;              /* 竖排更像书脊 */
  max-height: 100%; overflow: hidden;
  align-self: center; margin-top: 3px; z-index: 2;
}
.cov.textcov .tc-author {
  font-size: calc(var(--w) * .12); color: rgba(245,239,226,.72); letter-spacing: 1px;
  text-align: center; font-family: var(--serif);
  border-top: 1px solid rgba(245,239,226,.25); padding-top: 3px; z-index: 2;
}
.book.d3 .cov.textcov .tc-author { display: none; }

/* ---------- 详情抽屉 ---------- */
.drawer-mask {
  position: fixed; inset: 0; z-index: 60;
  background: rgba(30,27,23,.34);
  opacity: 0; pointer-events: none; transition: opacity .35s ease;
}
.drawer-mask.open { opacity: 1; pointer-events: auto; }
.drawer {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 70;
  width: min(430px, 92vw);
  background: linear-gradient(180deg, #f8f4ea, var(--paper) 30%);
  border-left: 1px solid var(--line);
  box-shadow: -24px 0 60px rgba(42,39,35,.25);
  transform: translateX(102%);
  transition: transform .45s cubic-bezier(.32,.72,.24,1);
  overflow-y: auto;
}
.drawer.open { transform: translateX(0); }
.drawer-close {
  position: absolute; top: 14px; right: 16px; z-index: 2;
  width: 36px; height: 36px; border-radius: 50%;
  border: 1px solid var(--line); background: var(--paper);
  color: var(--ink-2); font-size: 24px; line-height: 1; cursor: pointer;
  transition: all .25s ease;
}
.drawer-close:hover { border-color: var(--vermilion); color: var(--vermilion); transform: rotate(90deg); }
.drawer-body { padding: 40px 34px 60px; }

.d-cov {
  position: relative; width: 168px; height: 248px; margin: 6px auto 26px;
  border-radius: 4px 7px 7px 4px; overflow: hidden;
  box-shadow: var(--shadow-epic);
  background: var(--paper-2);
}
.d-cov img { width: 100%; height: 100%; object-fit: cover; display: block; }
.d-cov::after { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 11px;
  background: linear-gradient(90deg, rgba(0,0,0,.3), rgba(255,255,255,.14) 55%, rgba(0,0,0,.05)); }
.d-cov.epic { border: 2px solid var(--gold); outline: 1px solid rgba(179,137,74,.4); outline-offset: 4px; }
.d-cov.textcov { display:flex; flex-direction:column; justify-content:space-between; padding:16px 12px; }
.d-cov.textcov .tc-title { font-family:var(--serif); font-weight:700; color:#f5efe2; font-size:24px; letter-spacing:3px; writing-mode:vertical-rl; max-height:100%; overflow:hidden; align-self:center; }
.d-cov.textcov .tc-author { font-size:11px; color:rgba(245,239,226,.8); text-align:center; border-top:1px solid rgba(245,239,226,.3); padding-top:6px; }

.d-title { font-size: 28px; font-weight: 900; letter-spacing: 2px; text-align: center; margin: 0 0 6px; }
.d-meta { text-align: center; color: var(--ink-2); font-size: 14px; letter-spacing: 1px; line-height: 1.9; }
.d-meta .d-author { font-size: 15px; }
.d-date {
  margin: 18px auto 0; width: fit-content;
  font-family: var(--hand); font-size: 19px; color: var(--vermilion);
  letter-spacing: 2px; padding: 4px 16px;
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
}
.d-badge {
  margin: 16px auto 0; width: fit-content;
  font-size: 13px; letter-spacing: 4px; color: var(--gold);
  border: 1px solid rgba(179,137,74,.45); border-radius: 999px; padding: 4px 16px;
}
.d-divider { margin: 30px 0 18px; display: flex; align-items: center; gap: 12px; color: var(--ink-soft); }
.d-divider::before, .d-divider::after { content: ""; flex: 1; height: 1px; background: var(--line); }
.d-divider span { font-size: 12px; letter-spacing: 3px; }
.d-placeholder {
  color: var(--ink-soft); font-size: 14px; line-height: 2; letter-spacing: 1px;
  padding: 6px 2px;
}
.d-placeholder em { font-style: normal; color: var(--ink-2); border-bottom: 1px dashed var(--line); }

/* ---------- 舞台提示 ---------- */
.stage-hint {
  position: absolute; left: 50%; bottom: 22px; transform: translateX(-50%);
  z-index: 30; pointer-events: none;
  letter-spacing: 3px; color: var(--ink-soft);
  font-family: var(--hand); font-size: 16px;
  background: rgba(244,239,227,.72); padding: 4px 16px; border-radius: 999px;
  backdrop-filter: blur(4px);
  transition: opacity 1s ease;
}

/* ---------- 选中态 ---------- */
.book.selected { z-index: 21; }
.book.selected .cov { outline: 2px solid var(--vermilion); outline-offset: 3px; }

/* ============================================================
   竖版：河从上往下流，书左右交错排在两岸
   由 JS 判定竖屏后给 body 加 .vertical；桌面横版完全不受影响
   ============================================================ */
body.vertical .world { height: auto; }

/* 河道：竖着的一条，居中。宽度由 JS 的 VRIVER 写入 --vriver 保持同步。
   实测手机上河(234,237,236)与岸(245,241,230)只差 11 级灰，看不出是水；
   峰值提到 .58 并把两侧透明段收窄，让河缘成一条能读出的边界。 */
body.vertical .river {
  /* bottom:0 而不是 auto：河已搬出 .world，高度不再由 JS 写
     （原先是 riverEl.style.height = worldH）。留 auto 会让它塌成 0 高，
     竖版整条河消失 —— 踩过一次。现在铺满舞台即可，水纹沿轴均匀，不必跟世界一样长。 */
  top: 0; bottom: 0; left: 50%; right: auto;
  width: var(--vriver, 22%); transform: translateX(-50%);
  background: linear-gradient(90deg,
    rgba(170,182,176,0) 0%,
    rgba(120,148,152,.26) 6%,
    rgba(88,118,126,.46) 22%,
    rgba(70,100,110,.58) 50%,
    rgba(88,118,126,.46) 78%,
    rgba(120,148,152,.26) 94%,
    rgba(170,182,176,0) 100%);
}
/* 水面线在竖版里是「河中心的一道亮线」 */
body.vertical .riverline {
  left: 50%; right: auto; top: 0; bottom: 0;
  width: 2px; height: auto; transform: translateX(-50%);
  background: linear-gradient(90deg, rgba(255,255,255,.25), rgba(255,255,255,.75), rgba(255,255,255,.25));
  box-shadow: 0 0 12px rgba(255,255,255,.55);
}
/* 流纹转成横向细纹，自上而下流动。同样由 JS 逐帧驱动（见 .flow 注释），
   竖版位移走 Y，拉伸走 scaleY。 */
body.vertical .flow { left: 0; right: 0; top: -60%; bottom: -60%; height: auto; width: auto; }
body.vertical .flow-a {
  background: repeating-linear-gradient(88.6deg,
    transparent 0 15px, rgba(255,255,255,.26) 15px 17px, transparent 17px 42px);
  transform: translate3d(0, var(--flow-a, 0px), 0) scaleY(var(--flow-k, 1));
  mask-image: linear-gradient(90deg, transparent 0%, rgba(0,0,0,.85) 34%, rgba(0,0,0,.85) 66%, transparent 100%);
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, rgba(0,0,0,.85) 34%, rgba(0,0,0,.85) 66%, transparent 100%);
}
body.vertical .flow-b {
  background: repeating-linear-gradient(91.4deg,
    transparent 0 34px, rgba(255,255,255,.2) 34px 37px, transparent 37px 96px);
  transform: translate3d(0, var(--flow-b, 0px), 0) scaleY(var(--flow-k, 1));
  mask-image: linear-gradient(90deg, transparent 0%, rgba(0,0,0,.7) 38%, rgba(0,0,0,.7) 62%, transparent 100%);
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, rgba(0,0,0,.7) 38%, rgba(0,0,0,.7) 62%, transparent 100%);
}
/* 竖版粼光：沿河道竖着铺，光斑横躺（水面在这里是俯视的一条带） */
body.vertical .glint {
  left: 0; right: 0; top: 0; bottom: 0; height: auto; width: auto;
  transform: translate3d(0, var(--glint-x, 0px), 0);
  background-size: 100% 520px;
  background-repeat: repeat-y;
  mask-image: linear-gradient(90deg, transparent 0%, #000 30%, #000 70%, transparent 100%);
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, #000 30%, #000 70%, transparent 100%);
}
body.vertical .glint::after {
  transform: translate3d(0, var(--glint-x2, 0px), 0);
  background-size: 100% 890px;
  background-repeat: repeat-y;
}

/* 竖版没有「远岸地平线」和「山影」，收掉免得糊在河上 */
body.vertical .banks, body.vertical .mountains { display: none; }

/* 书：站在河两岸，朝河心微微侧身 */
body.vertical .book { transform: translate(-50%, 0); }
body.vertical .book .refl { display: none; }      /* 竖版不做水中倒影 */
body.vertical .book::before { display: none; }    /* 也没有着地涟漪 */
body.vertical .book.vleft .cov { transform: perspective(600px) rotateY(9deg); }
body.vertical .book.vright .cov { transform: perspective(600px) rotateY(-9deg); }
body.vertical .book.vleft:hover .cov { transform: perspective(600px) rotateY(9deg) translateY(-6px); }
body.vertical .book.vright:hover .cov { transform: perspective(600px) rotateY(-9deg) translateY(-6px); }
/* 书名签改到书下方居中（竖版空间够）。
   .tag 默认 opacity:0 靠 :hover 点亮 —— 触屏没有 hover，竖版会永远看不到书名。
   所以竖版改成常显，并换成浅底墨字，免得一排黑标签压过封面。 */
body.vertical .book .tag {
  top: calc(100% + 6px);
  opacity: 1; transform: translateX(-50%);
  background: none; backdrop-filter: none; padding: 2px 4px;
  color: var(--ink-2); font-size: 11px; letter-spacing: .5px;
  max-width: calc(var(--w) + 42px);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  text-shadow: 0 1px 2px rgba(244,239,227,.9);
  /* 横版签靠 hover 点亮、z-index:22 浮在所有书之上是对的；
     竖版常显就必须跟着自己那本书沉下去，否则被压住的书的签会浮到
     压它的那本书上面，看起来像张错位的标签。 */
  z-index: auto;
}
/* 后面压上来的书会盖住前一本的签（实测：签中心 x=300 落在压它那本的
   308–376 区间里）。让签靠河侧对齐 —— 河那一侧永远是空的，压上来的书
   只会从岸外侧叠过来。争 z-index 没用，压制发生在书与书之间。 */
body.vertical .book.vleft .tag { left: auto; right: 0; transform: none; text-align: right; }
body.vertical .book.vright .tag { left: 0; right: auto; transform: none; text-align: left; }
body.vertical .book .tag::before { display: none; }   /* 常显就不要小尖角了 */

/* 年份水印：沉在河道中央。手机屏小、底色浅，0.055 的墨几乎看不见，加深一档 */
body.vertical .ymark { transform: translate(-50%, -50%); color: rgba(42, 39, 35, 0.10); }
body.vertical .ymark .ym-num { font-size: 104px; letter-spacing: 6px; }
body.vertical .ymark .ym-gz { font-size: 26px; }

/* 月份刻度：放在河道正中的空槽里。
   河槽宽约 91px 而标签只有 46px，正好容得下；
   放到河缘反而会伸进两岸的书堆里被盖住。 */
body.vertical .tick {
  left: 50%; transform: translate(-50%, -50%);
  flex-direction: row; align-items: center; gap: 6px;
  white-space: nowrap;
}
body.vertical .tick::before { width: 16px; height: 1px; }
body.vertical .tick.year::before {
  width: 30px; height: 1px;
  background: linear-gradient(90deg, rgba(255,255,255,0), rgba(255,255,255,.85));
}
body.vertical .tick.month::before { width: 11px; }
/* 河底色浅，刻度得比横版更实才读得出 */
body.vertical .tick .t-label { color: rgba(32,48,52,.82); text-shadow: 0 1px 2px rgba(255,255,255,.9); }
body.vertical .tick.month .t-label { font-size: 12px; }

/* 雾段：横跨整条河的一段 */
body.vertical .mist-label { transform: translate(-50%, -50%); }

/* 顶部/底部柔光收边改成上下（竖版是纵向滚动） */
body.vertical .vignette {
  background:
    linear-gradient(180deg, rgba(244,239,227,.9) 0, rgba(244,239,227,0) 7%,
                    rgba(244,239,227,0) 93%, rgba(244,239,227,.9) 100%);
}

/* ---------- 响应式 ---------- */
@media (max-width: 720px) {
  .topbar { padding: 10px 14px; gap: 10px; flex-wrap: nowrap; }
  .brand-title { font-size: 18px; letter-spacing: 2px; }
  .brand-sub { display: none; }
  .seal { width: 38px; height: 38px; font-size: 17px; }
  .yearnav { display: none; }
  .stat { display: none; }
  .topbar-right { gap: 8px; min-width: 0; }
  .brand { flex: none; min-width: 0; }
  .brand-title { white-space: nowrap; }
  /* 窄屏按钮留在顶栏里。
     注意：不能用 position:fixed 把它浮到右下角——.topbar 有 backdrop-filter，
     那会让它成为 fixed 后代的包含块，按钮只会被钉在顶栏内部再被裁掉。 */
  .ghost-btn { padding: 6px 13px; font-size: 12px; letter-spacing: 1px; flex: none; }
  /* left:50% 会让可用宽只剩一半 → 文案折行还溢出舞台底。
     改成靠自身宽度居中，并压住字距保证一行放得下。 */
  .stage-hint {
    font-size: 12.5px; bottom: 14px;
    left: 0; right: 0; transform: none;
    width: fit-content; max-width: calc(100% - 24px);
    margin: 0 auto; letter-spacing: .5px; white-space: nowrap;
  }
  .ymark .ym-num { font-size: 88px; letter-spacing: 4px; }
  .ymark .ym-gz { font-size: 22px; }
  .mist-label { font-size: 13px; letter-spacing: 1px; padding: 3px 12px; }
  .drawer-body { padding: 32px 22px 48px; }
  .d-cov { width: 140px; height: 206px; }
  .d-title { font-size: 24px; }
}
@media (max-width: 520px) {
  .stat { display: none; }                /* 窄屏优先保「回到河口」按钮 */
}
@media (prefers-reduced-motion: reduce) {
  .mistband::after, .mistfront .veil { animation: none; }
  /* 流纹/粼光/粒子都是 JS 驱动的，退化逻辑在 app.js 的 REDUCED 分支里：
     水流冻在常速的静止相位，粒子完全不生成。这里只兜住淡入过渡。 */
  .epigraph, .colophon, .epigraph::before { transition-duration: .01ms; }
}
