/* ===== styles.css ===== */
:root{
  /* 页面只支持亮色方案，配合 head 里的 color-scheme 声明，挡掉浏览器强制深色 */
  color-scheme: light;
    /* 表面 */
    --paper:#FBF8F3;
    --raised:#FFFFFF;
    --sunken:#F5F1E8;
    /* 文字：四级灰阶，后两级按 WCAG AA 校准
       ink-3 #6F6758 → 5.28:1（原 #7A7264 实测 4.49:1，差 0.01 未达标）
       ink-mute #8C8476 → 4.18:1，专用于占位符与微标签
       ink-4 #AAA294 → 2.39:1，仅限非文本装饰（边框、分隔点） */
    --ink:#191714;
    --ink-2:#5C564C;
    --ink-3:#6F6758;
    --ink-mute:#8C8476;
    --ink-4:#AAA294;
    /* 线条 */
    --line:#E7E1D5;
    --line-soft:#F1ECE3;
    /* 强调：朱砂 */
    --accent:#8A362B;
    --accent-soft:#F7EDEA;
    --accent-line:#D6B0A8;
    /* 字体 */
    --serif:'Songti SC','Noto Serif SC',Georgia,serif;
    --sans:-apple-system,'PingFang SC','Hiragino Sans GB',system-ui,sans-serif;
    /* 节奏 */
    --ease:cubic-bezier(.22,1,.36,1);
    --dur:200ms;
    --r-sm:7px;
    --r-md:10px;
    --r-lg:14px;
    --shadow-1:0 1px 2px rgba(25,23,20,.04), 0 4px 14px rgba(25,23,20,.05);
    --shadow-2:0 2px 6px rgba(25,23,20,.06), 0 14px 40px rgba(25,23,20,.10);
  }
  *{box-sizing:border-box;margin:0;padding:0}
  html,body{height:100%}
  body{
    font-family:var(--sans);
    background:var(--paper);
    color:var(--ink);
    -webkit-font-smoothing:antialiased;
    -moz-osx-font-smoothing:grayscale;
    overflow:hidden;
    font-feature-settings:"tnum";
  }
  .app{height:100vh;display:flex;flex-direction:column}
  .app[hidden]{display:none}

  /* ---------- 顶栏 ---------- */
  .topbar{
    height:60px;flex:0 0 60px;
    display:flex;align-items:center;justify-content:space-between;
    padding:0 24px;
    border-bottom:1px solid var(--line);
    background:var(--paper);
    z-index:20;
  }
  .brand{display:flex;align-items:baseline;gap:12px;min-width:0}
  .back-btn{
    width:28px;height:28px;flex:0 0 auto;align-self:center;
    display:flex;align-items:center;justify-content:center;
    border:1px solid transparent;border-radius:var(--r-sm);
    background:transparent;color:var(--ink-3);cursor:pointer;
    transition:background var(--dur) var(--ease), color var(--dur) var(--ease);
  }
  .back-btn:hover{background:var(--sunken);color:var(--ink)}
  .brand h1{
    font-family:var(--serif);
    font-size:19px;font-weight:500;letter-spacing:.1em;
    white-space:nowrap;
  }
  .brand .meta{
    font-size:12px;color:var(--ink-3);letter-spacing:.03em;
    white-space:nowrap;
  }
  .brand .meta b{font-weight:400;color:var(--ink-2)}
  .brand .meta .dot{color:var(--ink-4);margin:0 6px}
  /* 新建的谱没有堂号和修次（只有「创修」），空值会让顶栏出现「· 创修 · 2026」这样以点开头的怪样子。
     让空 b 连同它后面的分隔点一起消失。:empty 对纯空白文本不生效，所以这里的值必须是''，不能是空格。 */
  .brand .meta b:empty{display:none}
  .brand .meta b:empty + .dot{display:none}
  .tools{display:flex;align-items:center;gap:8px;flex:0 0 auto}
  .search{
    display:flex;align-items:center;gap:7px;
    height:32px;padding:0 11px;
    border:1px solid var(--line);border-radius:var(--r-sm);
    background:var(--raised);
    transition:border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
  }
  .search:focus-within{
    border-color:var(--ink-4);
    box-shadow:0 0 0 3px rgba(25,23,20,.05);
  }
  .search svg{flex:0 0 auto;color:var(--ink-3)}
  .search input{
    border:none;outline:none;background:transparent;
    font-family:var(--sans);font-size:13px;color:var(--ink);
    width:120px;
  }
  .search input::placeholder{color:var(--ink-mute)}
  .search-wrap{position:relative}
  .search-clear{
    flex:0 0 auto;width:16px;height:16px;
    display:flex;align-items:center;justify-content:center;
    border:none;background:transparent;cursor:pointer;
    color:var(--ink-mute);font-size:10px;line-height:1;padding:0;
    border-radius:50%;transition:color var(--dur) var(--ease),background var(--dur) var(--ease);
  }
  .search-clear[hidden]{display:none}
  .search-clear:hover{color:var(--ink);background:var(--sunken)}
  .search-empty{
    position:absolute;right:0;top:calc(100% + 7px);z-index:30;
    display:flex;align-items:center;gap:7px;
    padding:8px 12px;white-space:nowrap;
    background:var(--raised);border:1px solid var(--line);
    border-radius:var(--r-sm);box-shadow:var(--shadow-2);
    font-size:12px;color:var(--ink-2);letter-spacing:.02em;
    animation:menuIn 160ms var(--ease);
  }
  .search-empty[hidden]{display:none}
  .search-empty b{font-weight:400;color:var(--accent)}
  .btn{
    height:32px;padding:0 14px;
    border:1px solid var(--line);border-radius:var(--r-sm);
    background:var(--raised);
    font-family:var(--sans);font-size:13px;color:var(--ink-2);
    cursor:pointer;white-space:nowrap;
    transition:border-color var(--dur) var(--ease), color var(--dur) var(--ease),
               background var(--dur) var(--ease), transform 120ms var(--ease);
  }
  .btn:hover{border-color:var(--ink-4);color:var(--ink);transform:translateY(-1px)}
  .btn:active{transform:translateY(0)}
  .btn.primary{
    background:var(--ink);border-color:var(--ink);color:#FBF8F3;
  }
  .btn.primary:hover{background:#2E2A25;border-color:#2E2A25}
  /* 危险操作：删除。平时与普通按钮同色，hover 才显朱砂，避免误按 */
  .btn.danger{color:var(--ink-2)}
  .btn.danger:hover{
    color:var(--accent);border-color:var(--accent-line);
    background:var(--accent-soft);
  }
  .btn.ghost{background:transparent;border-color:transparent;color:var(--ink-2)}
  .btn.ghost:hover{background:var(--sunken);border-color:transparent}
  .btn.accent{border-color:var(--accent-line);color:var(--accent);background:transparent}
  .btn.accent:hover{border-color:var(--accent);background:var(--accent-soft)}
  /* 禁用态：降透明度 + 屏蔽指针，hover 样式不再触发 */
  .btn:disabled,.btn-lg:disabled{
    opacity:.4;cursor:not-allowed;pointer-events:none;
    transform:none;box-shadow:none;
  }

  /* ---------- 主体 ---------- */
  .body{flex:1;display:flex;min-height:0;position:relative}

  .stage-wrap{
    flex:1;position:relative;overflow:hidden;
    background:var(--paper);
    cursor:grab;
  }
  .stage-wrap.dragging{cursor:grabbing}
  .stage{
    position:absolute;top:0;left:0;
    transform-origin:0 0;
    will-change:transform;
  }
  #edges{position:absolute;top:0;left:0;pointer-events:none;overflow:visible}
  #edges path{
    fill:none;stroke:#DCD4C5;stroke-width:1;
    transition:stroke var(--dur) var(--ease);
  }
  #edges path.hi{stroke:var(--accent);stroke-width:1.5;stroke-linecap:round}
  #nodes{position:relative}

  /* ---------- 节点 ---------- */
  @keyframes nodeIn{
    from{opacity:0;transform:translateY(6px)}
    to{opacity:1;transform:translateY(0)}
  }
  /* 姓名超长时（实测 18 字可把节点撑破、压到 55px 宽）不许折行，一律省略号。
     节点是定宽 100×76，内容一旦折行就会溢出到下一格，连同连线一起错位。 */
  .node .nm, .node .sp{
    max-width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  }

  .node{
    position:absolute;
    width:100px;height:76px;
    padding:10px 11px;
    display:flex;flex-direction:column;justify-content:center;
    background:var(--raised);
    border:1px solid var(--line);
    border-radius:var(--r-sm);
    cursor:pointer;
    user-select:none;
    animation:nodeIn 340ms var(--ease) backwards;
    transition:border-color var(--dur) var(--ease),
               box-shadow var(--dur) var(--ease),
               transform var(--dur) var(--ease),
               background var(--dur) var(--ease);
  }
  .node:hover{
    border-color:#CDC4B3;
    box-shadow:var(--shadow-1);
    transform:translateY(-2px);
  }
  .node.sel{
    border-color:var(--accent);
    background:var(--accent-soft);
    box-shadow:0 2px 10px rgba(138,54,43,.10);
    transform:translateY(-1px);
  }
  .node.dim{opacity:.28}
  /* 悬停某人时，只留他的祖先链和后代，其余退成背景。
     比搜索的 .dim(.28) 更暗：搜索是「筛掉不匹配的人」，这里是「只看这一支」，
     其余的连同他们的姓名年号都不需要辨认。 */
  #nodes.branching .node{opacity:.13;transition:opacity .16s var(--ease)}
  #nodes.branching .node.lit{opacity:1}
  .node.female .nm{color:#6E625D}
  .node .nm{
    font-family:var(--serif);
    font-size:15px;font-weight:500;letter-spacing:.05em;
    line-height:1.3;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  }
  .node .yr{
    font-size:11.5px;color:var(--ink-3);
    line-height:1.45;margin-top:2px;
    font-variant-numeric:tabular-nums;letter-spacing:.02em;
  }
  .node .sp{
    font-size:11px;color:var(--ink-3);
    line-height:1.4;margin-top:1px;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  }
  .node .sp::before{content:'配 ';color:var(--ink-mute)}

  /* ---------- 长姓名 ----------
     节点定宽 100，姓名区实际内容宽 76px（宋体 15px / 字距 .05em）。
     实测：4 字 63.0px 放得下，5 字 78.8px 溢出 2.8px。
     所以默认单行省略，hover 或键盘聚焦时向右展开全名：
     不换行、不改节点尺寸、不触发重排。 */
  .node:hover,
  .node:focus-visible{z-index:5}
  .node:hover .nm,
  .node:focus-visible .nm{
    width:max-content;max-width:220px;
    overflow:visible;text-overflow:clip;
    position:relative;z-index:3;
    padding:2px 6px;margin:-2px -6px;
    background:var(--raised);
    border-radius:3px;
    box-shadow:0 2px 12px rgba(25,23,20,.13), 0 0 0 1px var(--line);
  }

  /* ---------- 世代标尺（固定于视口左侧，垂直跟随缩放） ---------- */
  .rules{
    position:absolute;left:0;top:0;bottom:0;width:52px;
    pointer-events:none;z-index:6;
    /* 从纸色渐隐到透明：用户硬把画布拖到最左时，节点从这层底下穿过去，
       文字被柔和遮住，不会和「三世」压成一片。
       纯色块会显得像画布缺了一块，渐变不会。
       不透明段定 72%（37.4px）不是随手取的：节点姓名单字宽 8.6px、文字左缘 27.3px 时
       「建」占 27.3–35.9，要让它完全消失，不透明段必须越过 36px（36/52 = 69%）。
       取 72% 留余量，过渡段还有 14.6px，不会变成硬边。 */
    background:linear-gradient(to right,
      var(--paper) 0%, var(--paper) 72%, rgba(251,248,243,0) 100%);
  }
  .rule{
    position:absolute;left:0;
    padding-left:13px;
    font-size:11px;color:var(--ink-3);
    letter-spacing:.16em;
    font-family:var(--serif);
    white-space:nowrap;
    text-shadow:0 0 5px var(--paper), 0 0 5px var(--paper), 0 0 5px var(--paper);
    transition:top var(--dur) var(--ease);
  }
  .rule::before{
    content:'';position:absolute;left:0;top:7px;
    width:6px;height:1px;background:#C6BDAE;
  }

  /* ---------- 缩放控件 ---------- */
  .zoom{
    position:absolute;right:22px;bottom:22px;
    z-index:9;
    display:flex;flex-direction:column;
    background:var(--raised);
    border:1px solid var(--line);border-radius:var(--r-sm);
    overflow:hidden;
    box-shadow:var(--shadow-1);
  }
  .zoom button{
    width:33px;height:33px;
    border:none;background:transparent;
    font-size:15px;color:var(--ink-2);cursor:pointer;
    line-height:1;
    transition:background var(--dur) var(--ease), color var(--dur) var(--ease);
  }
  .zoom button:hover{background:var(--sunken);color:var(--ink)}
  .zoom button + button{border-top:1px solid var(--line-soft)}
  .zoom .lvl{
    font-size:10px;color:var(--ink-3);text-align:center;
    padding:5px 0 6px;border-top:1px solid var(--line-soft);
    font-variant-numeric:tabular-nums;letter-spacing:.02em;
  }

  /* ---------- 详情面板 ---------- */
  .panel{
    flex:0 0 340px;width:340px;
    border-left:1px solid var(--line);
    background:var(--raised);
    display:flex;flex-direction:column;
    overflow-y:auto;
  }
  .panel-empty{
    flex:1;display:flex;flex-direction:column;
    align-items:center;justify-content:center;
    gap:10px;color:var(--ink-3);
    font-size:13px;padding:40px 32px;
    text-align:center;line-height:1.7;
  }
  .panel-empty .hint{font-size:12px;color:var(--ink-mute);line-height:1.9}

  /* ---------- 空谱状态 ---------- */
  .stage-empty{
    position:absolute;inset:0;z-index:8;
    display:flex;flex-direction:column;
    align-items:center;justify-content:center;
    gap:0;text-align:center;padding:32px;
    background:var(--paper);
  }
  .stage-empty[hidden]{display:none}
  .stage-empty .seal-lg{
    width:44px;height:44px;border-radius:8px;
    background:var(--accent);color:#FBF8F3;
    font-family:var(--serif);font-size:22px;
    display:flex;align-items:center;justify-content:center;
    margin-bottom:22px;
  }
  .stage-empty h3{
    font-family:var(--serif);font-size:19px;font-weight:500;
    letter-spacing:.06em;
  }
  .stage-empty p{
    margin-top:10px;font-size:12.5px;color:var(--ink-3);
    line-height:1.9;max-width:300px;
  }
  .stage-empty .btn{margin-top:22px;height:36px;padding:0 18px}

  @keyframes panelIn{
    from{opacity:0;transform:translateY(8px)}
    to{opacity:1;transform:translateY(0)}
  }
  #panelBody{animation:panelIn 240ms var(--ease)}

  .p-head{position:relative;padding:24px 24px 20px;border-bottom:1px solid var(--line-soft)}
  .p-seal{
    position:absolute;right:24px;top:22px;
    width:34px;height:52px;
    display:flex;align-items:center;justify-content:center;
    writing-mode:vertical-rl;letter-spacing:.1em;
    font-family:var(--serif);font-size:11.5px;
    color:var(--accent);
    background:var(--accent-soft);
    border:1px solid var(--accent-line);border-radius:4px;
  }
  .p-gen{
    font-size:11px;color:var(--accent);letter-spacing:.18em;
    margin-bottom:12px;font-family:var(--serif);
  }
  .p-name{
    font-family:var(--serif);
    font-size:27px;font-weight:500;letter-spacing:.08em;
    line-height:1.15;
  }
  .p-courtesy{font-size:12px;color:var(--ink-3);margin-top:9px;letter-spacing:.04em}
  .p-life{
    font-size:13px;color:var(--ink-2);margin-top:15px;
    font-variant-numeric:tabular-nums;letter-spacing:.03em;
  }
  .p-body{padding:20px 24px;flex:1}
  .p-row{
    display:flex;gap:14px;
    padding:10px 0;
    border-bottom:1px dashed var(--line-soft);
    font-size:13px;
  }
  .p-row:last-child{border-bottom:none}
  .p-row .k{flex:0 0 52px;color:var(--ink-3);font-size:12px;padding-top:1px;letter-spacing:.02em}
  .p-row .v{flex:1;color:var(--ink);line-height:1.7}
  .p-row .v .sep{color:var(--ink-mute);margin:0 3px}
  .p-row .v .link{
    color:var(--accent);cursor:pointer;
    border-bottom:1px solid var(--accent-line);
    transition:border-color var(--dur) var(--ease);
  }
  .p-row .v .link:hover{border-bottom-color:var(--accent)}
  /* 访客提示：说清「这是示例、登录后才能改」，不要让人以为功能坏了 */
  .guest-banner{
    margin:0 0 14px;padding:10px 12px;
    display:flex;align-items:center;justify-content:space-between;gap:12px;
    background:var(--accent-soft);border:1px solid var(--accent-line);
    border-radius:var(--r-sm);
    font-size:12.5px;line-height:1.7;color:var(--ink-2);
  }
  .guest-banner .link{
    flex:0 0 auto;color:var(--accent);cursor:pointer;
    border-bottom:1px solid rgba(138,54,43,.3);font-size:12.5px;
  }

  .p-note{line-height:1.9;color:var(--ink-2);font-size:13px;white-space:pre-wrap}
  /* 三千字的行述不能把面板撑爆，先折八行，点开看全文 */
  .p-note.clamp{
    display:-webkit-box;-webkit-line-clamp:8;-webkit-box-orient:vertical;
    overflow:hidden;
  }
  .p-note-more{
    margin-top:6px;font-size:12px;color:var(--accent);cursor:pointer;
    border-bottom:1px solid rgba(138,54,43,.28);display:inline-block;
  }
  .p-note-more:hover{border-bottom-color:var(--accent)}

  .p-actions{
    padding:16px 24px 20px;
    display:flex;gap:8px;flex-wrap:wrap;
    border-top:1px solid var(--line-soft);
  }
  .p-actions .btn{height:30px;font-size:12px;padding:0 11px}

  .p-upsell{
    margin:0 24px 24px;
    padding:14px 16px;
    background:var(--sunken);
    border-radius:var(--r-md);
  }
  .p-upsell .u-title{
    font-size:12.5px;color:var(--ink);font-weight:500;
    display:flex;align-items:center;gap:7px;
  }
  .p-upsell .u-title::before{
    content:'';flex:0 0 auto;
    width:2px;height:10px;background:var(--accent);
  }
  .p-upsell .u-desc{
    font-size:12px;color:var(--ink-3);line-height:1.7;margin-top:6px;
  }
  .p-upsell .u-act{
    margin-top:10px;font-size:12px;color:var(--accent);
    cursor:pointer;display:inline-block;
    border-bottom:1px solid var(--accent-line);
  }
  .p-upsell .u-act:hover{border-bottom-color:var(--accent)}
  /* 看过几个人之后收成一行（panel.js 记次数）。这块挂在每个族人的面板底部，
     翻几十个人就出现几十次，一直占着一整块地方并不合适。 */
  .p-upsell.is-mini{padding:10px 16px}
  .p-upsell.is-mini .u-act{margin-top:0}

  /* ---------- 弹层 ---------- */
  .modal{
    position:fixed;inset:0;z-index:100;
    background:rgba(25,23,20,.26);
    display:flex;align-items:center;justify-content:center;
    padding:24px;
    animation:fadeIn 180ms var(--ease);
  }
  .modal[hidden]{display:none}
  @keyframes fadeIn{from{opacity:0}to{opacity:1}}
  @keyframes sheetIn{
    from{opacity:0;transform:translateY(10px) scale(.985)}
    to{opacity:1;transform:translateY(0) scale(1)}
  }
  .sheet{
    width:100%;max-width:440px;
    background:var(--raised);
    border-radius:var(--r-lg);
    padding:24px;
    box-shadow:var(--shadow-2);
    animation:sheetIn 220ms var(--ease);
    /* 两列网格：性别/出生年并排，其余占满一行。
       原来用 inline-block 50% + 外边距，行内空白会撑爆一行导致折行 */
    display:grid;grid-template-columns:1fr 1fr;column-gap:14px;
    /* 行述改成多行文本后弹窗会长高，超过视口就自己滚，不顶出屏幕 */
    max-height:calc(100vh - 48px);
    overflow-y:auto;
  }
  .sheet > h2, .sheet > .sub, .sheet > .sheet-foot, .sheet > .field:not(.half){grid-column:1/-1}
  .sheet h2{
    font-family:var(--serif);font-size:18px;font-weight:500;
    margin-bottom:4px;letter-spacing:.05em;
  }
  .sheet .sub{font-size:12.5px;color:var(--ink-3);margin-bottom:20px;line-height:1.7}
  .field{margin-bottom:14px}
  .field label{display:flex;align-items:baseline;justify-content:space-between;gap:12px;font-size:12px;color:var(--ink-3);margin-bottom:6px;letter-spacing:.02em}
  .field input,.field select{
    width:100%;height:38px;padding:0 12px;
    border:1px solid var(--line);border-radius:var(--r-sm);
    font-family:var(--sans);font-size:13px;color:var(--ink);
    background:var(--raised);outline:none;
    transition:border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
  }
  .field input:focus,.field select:focus{
    border-color:var(--ink-4);
    box-shadow:0 0 0 3px rgba(25,23,20,.05);
  }
  .field input::placeholder{color:var(--ink-mute)}
  /* 行述：长文本。用宋体、行高 1.9，读起来像谱面；高度随内容长，上限 46vh 后内部滚动 */
  .field textarea{
    width:100%;min-height:132px;max-height:46vh;
    padding:10px 12px;
    border:1px solid var(--line);border-radius:var(--r-sm);
    font-family:var(--serif);font-size:13.5px;line-height:1.9;
    color:var(--ink);background:var(--raised);
    outline:none;resize:vertical;display:block;
    transition:border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
  }
  .field textarea:focus{
    border-color:var(--ink-4);
    box-shadow:0 0 0 3px rgba(25,23,20,.05);
  }
  .field textarea::placeholder{
    color:var(--ink-mute);
    font-family:var(--sans);font-size:12.5px;line-height:1.75;
  }
  .field.error textarea{
    border-color:var(--accent);
    box-shadow:0 0 0 3px rgba(138,54,43,.07);
  }
  /* 字数：轻量挂在标签右侧，不跟主标签抢注意力 */
  .f-count{
    font-size:11.5px;color:var(--ink-mute);
    letter-spacing:.02em;font-variant-numeric:tabular-nums;
  }
  .f-count.over{color:var(--accent)}
  /* 输入错误态 */
  .field.error input,.field.error select{
    border-color:var(--accent);
    box-shadow:0 0 0 3px rgba(138,54,43,.07);
  }
  .field .err{
    display:none;margin-top:6px;
    font-size:11.5px;color:var(--accent);letter-spacing:.02em;
  }
  .field.error .err{display:block}
  .field.half{min-width:0}
  .sheet-foot{display:flex;justify-content:flex-end;gap:8px;margin-top:22px}

  /* ---------- 增值服务抽屉 ---------- */
  .drawer{position:fixed;inset:0;z-index:120;display:flex;justify-content:flex-end}
  .drawer[hidden]{display:none}
  .drawer-mask{
    position:absolute;inset:0;background:rgba(25,23,20,.32);
    animation:fadeIn 200ms var(--ease);
  }
  @keyframes drawerIn{from{transform:translateX(100%)}to{transform:translateX(0)}}
  .drawer-panel{
    position:relative;width:420px;max-width:94vw;height:100%;
    background:var(--raised);
    display:flex;flex-direction:column;
    box-shadow:-12px 0 48px rgba(25,23,20,.14);
    animation:drawerIn 280ms var(--ease);
  }
  .drawer-head{
    padding:22px 24px 18px;
    border-bottom:1px solid var(--line-soft);
    display:flex;align-items:flex-start;justify-content:space-between;gap:16px;
  }
  .drawer-head h2{
    font-family:var(--serif);font-size:18px;font-weight:500;letter-spacing:.05em;
  }
  .drawer-head .sub{font-size:12.5px;color:var(--ink-3);margin-top:7px;line-height:1.7}
  .icon-btn{
    flex:0 0 auto;width:28px;height:28px;border-radius:var(--r-sm);
    border:none;background:transparent;cursor:pointer;
    color:var(--ink-3);font-size:16px;line-height:1;
    display:flex;align-items:center;justify-content:center;
    transition:background var(--dur) var(--ease), color var(--dur) var(--ease);
  }
  .icon-btn:hover{background:var(--sunken);color:var(--ink)}
  .drawer-body{flex:1;overflow-y:auto;padding:20px 24px 28px}
  .lede{
    font-size:13px;color:var(--ink-2);line-height:1.85;
    padding-bottom:20px;border-bottom:1px solid var(--line-soft);
  }
  .svc{border-bottom:1px solid var(--line-soft);padding:20px 0}
  .svc:last-of-type{border-bottom:none}
  .svc-top{display:flex;align-items:baseline;justify-content:space-between;gap:12px}
  .svc h3{
    font-family:var(--serif);font-size:15px;font-weight:500;letter-spacing:.04em;
  }
  .svc-badge{
    font-size:11px;line-height:1.5;color:var(--accent);
    border:1px solid var(--accent-line);border-radius:4px;
    background:var(--accent-soft);
    padding:2px 7px;letter-spacing:.04em;white-space:nowrap;
  }
  .svc-desc{font-size:12.5px;color:var(--ink-3);line-height:1.7;margin-top:7px}
  .tier{
    display:grid;grid-template-columns:1fr auto;gap:3px 12px;
    padding:11px 0;border-bottom:1px dashed var(--line-soft);
  }
  .tier:last-child{border-bottom:none}
  .tier-name{font-size:13px;color:var(--ink)}
  .tier-price{
    font-size:13px;font-weight:500;color:var(--ink);
    font-variant-numeric:tabular-nums;white-space:nowrap;
  }
  .tier-desc{grid-column:1/-1;font-size:12px;color:var(--ink-3);line-height:1.65}
  /* 利润档位单独加重，避免十档价格视觉权重完全一样 */
  .tier.hot .tier-name{color:var(--ink);font-weight:500}
  .tier.hot .tier-price{color:var(--accent)}
  .svc-note{
    margin-top:10px;font-size:11.5px;color:var(--ink-3);
    line-height:1.7;padding-left:10px;border-left:2px solid var(--line);
  }
  .drawer-foot{
    padding:14px 24px 18px;border-top:1px solid var(--line-soft);
    font-size:11.5px;color:var(--ink-3);line-height:1.7;background:var(--sunken);
  }

  /* ---------- 提示条 ---------- */
  .toast{
    position:fixed;left:50%;bottom:34px;
    transform:translateX(-50%) translateY(10px);
    background:var(--ink);color:#FBF8F3;
    font-size:12.5px;padding:10px 18px;border-radius:var(--r-sm);
    opacity:0;pointer-events:none;
    transition:opacity 200ms var(--ease), transform 200ms var(--ease);
    z-index:200;letter-spacing:.02em;
    box-shadow:var(--shadow-1);
  }
  .toast.on{opacity:1;transform:translateX(-50%) translateY(0)}

  /* ==================================================================
     首页
     ================================================================== */
  .site{
    position:fixed;inset:0;
    overflow-y:auto;overflow-x:hidden;
    background-color:var(--paper);
    background-image:radial-gradient(circle at 1px 1px, rgba(25,23,20,.07) 1px, transparent 0);
    background-size:24px 24px;
    -webkit-overflow-scrolling:touch;
  }
  .site[hidden]{display:none}

  .nav{
    position:sticky;top:0;z-index:10;
    height:66px;
    display:flex;align-items:center;justify-content:space-between;
    padding:0 40px;
    background:var(--paper);
    border-bottom:1px solid transparent;
    transition:border-color var(--dur) var(--ease);
  }
  .nav.scrolled{border-bottom-color:var(--line)}
  .nav-progress{
    position:absolute;left:0;bottom:-1px;height:2px;width:0;
    background:var(--accent);
    transition:width 90ms linear;
    border-radius:0 2px 2px 0;
  }
  .nav-brand{
    display:flex;align-items:center;gap:10px;
    font-family:var(--serif);font-size:19px;font-weight:500;
    letter-spacing:.14em;cursor:pointer;
  }
  .seal{
    width:24px;height:24px;border-radius:5px;
    background:var(--accent);
    display:inline-flex;align-items:center;justify-content:center;
    color:#FBF8F3;font-size:12px;letter-spacing:0;
    font-family:var(--serif);
    flex:0 0 auto;
  }
  .nav-links{display:flex;align-items:center;gap:30px}
  .nav-links a{
    font-size:13.5px;color:var(--ink-2);text-decoration:none;
    letter-spacing:.03em;cursor:pointer;
    transition:color var(--dur) var(--ease);
  }
  .nav-links a:hover{color:var(--ink)}
  .nav-right{display:flex;align-items:center;gap:10px}

  /* ---- Hero ---- */
  .hero{
    max-width:1240px;margin:0 auto;
    padding:76px 40px 68px;
    display:grid;grid-template-columns:0.92fr 1.08fr;
    gap:56px;align-items:center;
  }
  .hero-eyebrow{
    display:inline-flex;align-items:center;gap:8px;
    font-size:11.5px;color:var(--ink-3);letter-spacing:.18em;
    margin-bottom:26px;
  }
  .hero-eyebrow::before{
    content:'';width:20px;height:1px;
    background:var(--accent);
  }
  .hero h1{
    font-family:var(--serif);
    font-size:clamp(34px,4.1vw,54px);
    font-weight:500;line-height:1.24;
    letter-spacing:.01em;
    color:var(--ink);
  }
  .hero h1 em{
    font-style:normal;color:var(--accent);
  }
  .hero-sub{
    margin-top:24px;
    font-size:15.5px;line-height:2;color:var(--ink-2);
    max-width:430px;
  }
  .hero-cta{
    margin-top:36px;
    display:flex;align-items:center;gap:12px;flex-wrap:wrap;
  }
  .btn-lg{
    height:46px;padding:0 26px;
    border-radius:8px;
    font-size:14px;letter-spacing:.03em;
    font-family:var(--sans);
    cursor:pointer;
    transition:transform 140ms var(--ease), background 200ms var(--ease),
               border-color 200ms var(--ease), box-shadow 200ms var(--ease);
  }
  .btn-lg.solid{
    background:var(--ink);color:#FBF8F3;border:1px solid var(--ink);
  }
  .btn-lg.solid:hover{background:#2E2A25;border-color:#2E2A25;transform:translateY(-1px);
    box-shadow:0 6px 20px rgba(25,23,20,.16)}
  .btn-lg.outline{
    background:transparent;color:var(--ink);border:1px solid var(--line);
  }
  .btn-lg.outline:hover{border-color:var(--ink-4);transform:translateY(-1px)}
  .hero-note{
    margin-top:18px;font-size:12px;color:var(--ink-3);letter-spacing:.02em;
  }

  @keyframes heroIn{
    from{opacity:0;transform:translateY(16px)}
    to{opacity:1;transform:translateY(0)}
  }
  .hero-left > *{animation:heroIn 720ms var(--ease) backwards}
  .hero-left > *:nth-child(1){animation-delay:60ms}
  .hero-left > *:nth-child(2){animation-delay:120ms}
  .hero-left > *:nth-child(3){animation-delay:200ms}
  .hero-left > *:nth-child(4){animation-delay:280ms}
  .hero-left > *:nth-child(5){animation-delay:340ms}
  .hero-visual{position:relative;min-width:0;animation:heroIn 900ms var(--ease) 240ms backwards}
  .hv-tilt{
    transition:transform 420ms cubic-bezier(.22,1,.36,1);
    transform:perspective(1000px) rotateY(var(--ry,0deg)) rotateX(var(--rx,0deg));
    will-change:transform;
  }
  .hero > *, .facts-inner > *, .values > *, .services > *, .cta-inner > *{min-width:0}
  .hero-visual svg, .preview-stage svg{
    display:block!important;width:100%!important;
    max-width:100%!important;height:auto!important;
  }
  .hero-visual{max-width:100%;overflow:hidden}
  .hero-visual svg{display:block;width:100%;height:auto}
  .hv-node{
    fill:#FFF;stroke:var(--line);stroke-width:1;
  }
  .hv-node.accent{fill:var(--accent-soft);stroke:var(--accent-line)}
  .hv-node.hi{stroke:var(--accent);stroke-width:1.5}
  .hv-line.hi{stroke:var(--accent);stroke-width:1.6}
  .hv-line{
    stroke:#D9D1C2;stroke-width:1;fill:none;
    stroke-dasharray:1;stroke-dashoffset:1;
    transition:stroke-dashoffset 640ms cubic-bezier(.4,0,.2,1);
  }
  .hv-line.on{stroke-dashoffset:0}
  .hv-g{
    opacity:0;
    transform-box:fill-box;transform-origin:center;
    transform:translateY(-5px) scale(.94);
    transition:opacity 560ms cubic-bezier(.22,1,.36,1),
               transform 560ms cubic-bezier(.22,1,.36,1);
  }
  .hv-g.on{opacity:1;transform:translateY(0) scale(1)}
  .hv-name{
    font-family:var(--serif);font-size:11px;fill:var(--ink);
    letter-spacing:.04em;
  }
  .hv-name.accent{fill:var(--accent)}
  .hv-name.hi{fill:var(--accent);font-weight:500}
  .hv-year{font-size:8px;fill:var(--ink-3);letter-spacing:.02em}
  .hv-caption{
    font-size:10px;fill:var(--ink-3);letter-spacing:.14em;
    font-family:var(--serif);
  }

  /* ---- 能力条 ---- */
  .facts{
    border-top:1px solid var(--line);
    border-bottom:1px solid var(--line);
    background:var(--sunken);
  }
  .facts-inner{
    max-width:1240px;margin:0 auto;
    padding:0 40px;
    display:grid;grid-template-columns:repeat(4,1fr);
  }
  .fact{
    padding:28px 0 28px 26px;
    border-left:1px solid var(--line-soft);
  }
  .fact:first-child{border-left:none;padding-left:0}
  .fact .n{
    font-family:var(--serif);font-size:28px;font-weight:500;
    letter-spacing:.02em;line-height:1.2;
  }
  .fact .n small{font-size:13px;font-weight:400;color:var(--ink-3);margin-left:3px}
  .fact .l{
    margin-top:7px;font-size:12.5px;color:var(--ink-3);letter-spacing:.03em;
  }

  /* ---- 通用区块 ---- */
  .sec{max-width:1240px;margin:0 auto;padding:88px 40px}
  .sec-head{max-width:600px;margin-bottom:48px}
  .sec-eyebrow{
    font-size:11.5px;color:var(--accent);letter-spacing:.2em;
    margin-bottom:16px;display:block;
  }
  .sec h2{
    font-family:var(--serif);
    font-size:clamp(24px,2.4vw,31px);
    font-weight:500;line-height:1.34;letter-spacing:.02em;
  }
  .sec-desc{
    margin-top:14px;font-size:14px;line-height:1.95;color:var(--ink-2);
  }

  /* ---- 三项能力 ---- */
  .values{
    display:grid;grid-template-columns:repeat(3,1fr);
    gap:0;
  }
  .value{
    padding:32px 32px 0 0;
    border-top:1.5px solid var(--ink);
  }
  .value + .value{padding-left:32px;border-left:1px solid var(--line-soft)}
  .value .idx{
    font-family:var(--serif);font-size:12px;color:var(--accent);
    letter-spacing:.1em;margin-bottom:18px;
  }
  .value h3{
    font-family:var(--serif);font-size:18px;font-weight:500;
    letter-spacing:.03em;line-height:1.5;
  }
  .value p{
    margin-top:14px;font-size:13.5px;line-height:1.95;color:var(--ink-2);
  }

  /* ---- 产品预览 ---- */
  .preview{
    max-width:940px;margin:0 auto;
    border:1px solid var(--line);border-radius:var(--r-lg);
    background:var(--raised);
    overflow:hidden;
    cursor:pointer;
    transition:border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
               transform var(--dur) var(--ease);
  }
  .preview:hover{
    border-color:var(--ink-4);
    box-shadow:var(--shadow-2);
    transform:translateY(-3px);
  }
  .preview-bar{
    height:42px;display:flex;align-items:center;gap:7px;
    padding:0 16px;border-bottom:1px solid var(--line-soft);
    background:var(--sunken);
  }
  .preview-bar i{
    width:9px;height:9px;border-radius:50%;
    background:#DCD5C7;display:block;
  }
  .preview-bar span{
    margin-left:10px;font-size:11.5px;color:var(--ink-3);letter-spacing:.06em;
    font-family:var(--serif);
  }
  .preview-stage{
    padding:34px 28px;background:var(--paper);
    display:flex;justify-content:center;overflow:hidden;
  }
  .preview-stage svg{width:100%;max-width:760px;height:auto}

  /* ---- 服务 ---- */
  /* 1 主推横卡 + 2 小卡：主推占满一行，图在左、文在右，形成真实层级 */
  .services{display:grid;grid-template-columns:1fr 1fr;gap:20px}
  .svc-card{
    position:relative;overflow:hidden;
    display:flex;flex-direction:column;
    background:var(--raised);
    border:1px solid var(--line);border-radius:var(--r-md);
    transition:border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
               transform var(--dur) var(--ease);
  }
  .svc-card::before{
    content:'';position:absolute;left:0;top:0;height:2px;width:0;
    background:var(--accent);z-index:2;
    transition:width 320ms var(--ease);
  }
  .svc-card:hover{
    border-color:var(--ink-4);box-shadow:var(--shadow-1);
    transform:translateY(-2px);
  }
  .svc-card:hover::before{width:100%}
  /* 卡片整块可点（绑定在 services.js）。上面的 hover 上浮已经像能点了，
     这里补指针与键盘焦点——只靠 hover 的话，键盘用户根本不知道这里能按。 */
  .svc-card[data-svc]{cursor:pointer}
  .svc-card[data-svc]:focus-visible{outline:2px solid var(--accent);outline-offset:3px}
  .svc-card.lead{
    grid-column:1/-1;
    display:grid;grid-template-columns:1.04fr 1fr;
    background:#FFFCFA;
    border-color:var(--accent-line);
  }
  .svc-card.lead::before{width:100%}

  /* 实物图 */
  .svc-media{
    position:relative;overflow:hidden;flex:0 0 auto;
    background:var(--sunken);
  }
  .svc-media img{
    display:block;width:100%;height:100%;object-fit:cover;
    filter:saturate(.9) contrast(1.02);
    transition:transform 720ms var(--ease);
  }
  .svc-card:hover .svc-media img{transform:scale(1.035)}
  .svc-card:not(.lead) .svc-media{aspect-ratio:2/1}
  .svc-card.lead .svc-media{height:100%;min-height:320px}

  .svc-flag{
    position:absolute;left:0;top:0;z-index:3;
    font-size:10.5px;letter-spacing:.1em;
    color:var(--accent);
    background:rgba(255,252,250,.93);
    padding:6px 12px;
    border-radius:0 0 var(--r-sm) 0;
  }

  .svc-body{
    display:flex;flex-direction:column;flex:1;
    padding:22px 24px 24px;
  }
  .svc-card.lead .svc-body{padding:40px 44px;justify-content:center}
  .svc-kicker{
    font-size:11px;letter-spacing:.18em;color:var(--accent);
    margin-bottom:14px;font-family:var(--serif);
  }
  .svc-card h3{
    font-family:var(--serif);font-size:16px;font-weight:500;letter-spacing:.04em;
  }
  .svc-card.lead h3{font-size:clamp(21px,2vw,25px);letter-spacing:.07em}
  .svc-card p{
    margin-top:11px;font-size:12.5px;line-height:1.85;color:var(--ink-2);
    text-wrap:pretty;
  }
  .svc-card.lead p{
    margin-top:16px;font-size:13.5px;line-height:2;max-width:410px;
  }

  /* 价格：档位之间拉开字重与字号，主推卡的价格是次级卡的一倍半 */
  .svc-price{
    margin-top:18px;display:flex;align-items:baseline;
    gap:6px;flex-wrap:wrap;
  }
  .svc-price .pv{
    font-family:var(--serif);font-size:23px;line-height:1;
    letter-spacing:.01em;font-variant-numeric:tabular-nums;
  }
  .svc-card.lead .svc-price .pv{font-size:34px}
  .svc-price .pu{font-size:12px;color:var(--ink-3);letter-spacing:.02em}
  .svc-price .pv-sub{
    font-size:12px;color:var(--ink-3);letter-spacing:.02em;
    padding-left:12px;margin-left:6px;
    border-left:1px solid var(--line);
  }

  .svc-card .go{
    margin-top:auto;padding-top:20px;
    font-size:12.5px;color:var(--accent);
    display:inline-block;width:fit-content;cursor:pointer;
  }
  .svc-card .go span{
    border-bottom:1px solid var(--accent-line);padding-bottom:2px;
    transition:border-color var(--dur) var(--ease);
  }
  .svc-card .go:hover span{border-bottom-color:var(--accent)}
  /* 主推卡正文居中排，链接不推到卡底，避免价格与链接之间空一大截 */
  .svc-card.lead .go{margin-top:0;padding-top:26px}

  /* ---- 底部 CTA ---- */
  .cta-band{
    position:relative;overflow:hidden;
    background:var(--ink);
  }
  .cta-band::before{
    content:'谱';
    position:absolute;right:-2%;top:50%;
    transform:translateY(-50%);
    font-family:var(--serif);font-size:clamp(180px,22vw,280px);line-height:.8;
    color:rgba(251,248,243,.055);
    pointer-events:none;user-select:none;
    letter-spacing:0;
  }
  .cta-inner{
    position:relative;z-index:1;
    max-width:1240px;margin:0 auto;
    padding:104px 40px;
    display:flex;align-items:center;justify-content:space-between;gap:56px;
  }
  .cta-inner h2{
    font-family:var(--serif);
    font-size:clamp(22px,2.2vw,30px);
    font-weight:500;line-height:1.42;letter-spacing:.03em;
    color:#FBF8F3;
  }
  .cta-inner p{
    margin-top:14px;font-size:13.5px;line-height:1.9;max-width:520px;
    color:rgba(251,248,243,.58);
  }
  .btn-lg.light{
    background:#FBF8F3;color:var(--ink);border:1px solid #FBF8F3;
    flex:0 0 auto;
  }
  .btn-lg.light:hover{
    background:#fff;border-color:#fff;transform:translateY(-1px);
    box-shadow:0 8px 26px rgba(0,0,0,.28);
  }

  /* ---- Footer ---- */
  .foot{
    max-width:1240px;margin:0 auto;
    padding:44px 40px 56px;
    display:flex;align-items:flex-start;justify-content:space-between;gap:40px;
    border-top:1px solid var(--line);
  }
  .foot-left{display:flex;flex-direction:column;gap:12px}
  .foot-brand{
    display:flex;align-items:center;gap:10px;
    font-family:var(--serif);font-size:15px;letter-spacing:.14em;
  }
  .foot-copy{font-size:11.5px;color:var(--ink-3);line-height:1.9}
  /* 备案号容器：只给排版，**不给 display**。
     [hidden] 会被任何 display 规则覆盖（站长后台 #gate 已经踩过一次），
     空值时要靠 hidden 彻底不占位。 */
  .foot-icp{margin-top:7px;display:inline-block}
  .foot-icp[hidden]{display:none!important}
  .foot-icp a{color:var(--ink-4);text-decoration:none;margin-right:14px;font-size:11px}
  .foot-icp a:hover{color:var(--accent)}
  .foot-links{display:flex;gap:28px;flex-wrap:wrap}
  .foot-links a{
    font-size:12px;color:var(--ink-3);text-decoration:none;cursor:pointer;
    transition:color var(--dur) var(--ease);
  }
  .foot-links a:hover{color:var(--ink)}

  /* ---- 个人中心下拉 ---- */
  .user-wrap{position:relative}
  .avatar{
    width:32px;height:32px;border-radius:50%;
    background:var(--accent-soft);
    border:1px solid var(--accent-line);
    color:var(--accent);
    font-family:var(--serif);font-size:13px;
    display:flex;align-items:center;justify-content:center;
    cursor:pointer;
    transition:transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
  }
  .avatar:hover{transform:translateY(-1px);box-shadow:var(--shadow-1)}
  /* 访客态是「登录」按钮，不是头像：32px 的圆放不下两个字，
     而这是访客唯一能看到的登录入口，不能让他猜「登」是什么意思。 */
  .avatar.guest{
    width:auto;min-width:32px;padding:0 12px;border-radius:16px;
    background:var(--sunken);border-color:var(--line);color:var(--ink-2);
    font-family:var(--sans);font-size:12.5px;letter-spacing:.06em;
  }
  .avatar.guest:hover{border-color:var(--ink-4);color:var(--ink)}
  .menu{
    position:absolute;right:0;top:calc(100% + 10px);
    width:216px;
    background:var(--raised);
    border:1px solid var(--line);border-radius:var(--r-md);
    box-shadow:var(--shadow-2);
    padding:6px;
    z-index:40;
    animation:menuIn 160ms var(--ease);
  }
  .menu[hidden]{display:none}
  @keyframes menuIn{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}
  .menu-user{
    padding:10px 12px 12px;border-bottom:1px solid var(--line-soft);margin-bottom:6px;
  }
  .menu-user .mu-name{font-size:13px;color:var(--ink)}
  .menu-user .mu-sub{font-size:11.5px;color:var(--ink-3);margin-top:3px}
  .menu-item{
    display:flex;align-items:center;gap:8px;
    padding:9px 12px;border-radius:6px;
    font-size:12.5px;color:var(--ink-2);cursor:pointer;
    transition:background var(--dur) var(--ease), color var(--dur) var(--ease);
  }
  .menu-item:hover{background:var(--sunken);color:var(--ink)}
  /* 危险项置灰：只降透明度，**不写 pointer-events:none**——
     点不动会被当成界面卡死；照常接收点击，由 handleAccountAction 给出解释 */
  .menu-item.disabled{opacity:.45}
  .menu-item.disabled:hover{background:transparent;color:var(--ink-2)}
  .menu-sep{height:1px;background:var(--line-soft);margin:6px 0}

  /* ---- 字体切换器 ---- */
  .font-pop{
    position:absolute;right:0;top:calc(100% + 10px);
    width:280px;
    background:var(--raised);
    border:1px solid var(--line);border-radius:var(--r-md);
    box-shadow:var(--shadow-2);
    padding:8px;
    z-index:40;
    animation:menuIn 160ms var(--ease);
  }
  .font-pop[hidden]{display:none}
  /* 版本戳：分辨「看到的是不是最新一版」 */
  .fp-build{
    margin-top:10px;padding-top:10px;
    border-top:1px solid var(--line-soft);
    font-size:11px;color:var(--ink-mute);letter-spacing:.02em;
  }
  .font-pop .fp-head{
    padding:8px 10px 10px;font-size:11px;color:var(--ink-3);
    letter-spacing:.1em;border-bottom:1px solid var(--line-soft);margin-bottom:6px;
  }
  .font-opt{
    display:flex;align-items:center;justify-content:space-between;gap:10px;
    padding:10px;border-radius:6px;cursor:pointer;
    transition:background var(--dur) var(--ease);
  }
  .font-opt:hover{background:var(--sunken)}
  .font-opt.on{background:var(--accent-soft)}
  .font-opt .fo-name{font-size:14px;color:var(--ink);letter-spacing:.04em}
  .font-opt .fo-meta{font-size:10px;color:var(--ink-3);margin-top:3px;letter-spacing:.02em}
  .font-opt .fo-tick{
    width:14px;height:14px;flex:0 0 auto;color:var(--accent);
    opacity:0;transition:opacity var(--dur) var(--ease);
  }
  .font-opt.on .fo-tick{opacity:1}
  .font-loading{
    padding:8px 10px;font-size:11px;color:var(--ink-3);
  }

  /* ---- 滚动呈现 ---- */
  .reveal{
    opacity:0;transform:translateY(20px);
    transition:opacity 640ms var(--ease), transform 640ms var(--ease);
  }
  .reveal.in{opacity:1;transform:none}

  /* ---- 首页响应式 ---- */
  @media (max-width:600px){
    .nav-right .btn{display:none}
    .hero h1{font-size:32px;line-height:1.3}
    .hero-sub{font-size:14.5px;line-height:1.95}
    .btn-lg{height:44px;padding:0 20px;font-size:13.5px}
    .fact{padding:20px 0 20px 16px}
    .fact .n{font-size:23px}
    .fact .l{font-size:12px}
    .sec h2{font-size:22px}
  }

  @media (max-width:960px){
    .nav{padding:0 22px}
    .nav-links{display:none}
    .hero{grid-template-columns:1fr;gap:48px;padding:52px 22px 56px}
    .hero-sub{max-width:none}
    .hero-visual{order:2}
    .facts-inner{grid-template-columns:repeat(2,1fr);padding:0 22px}
    .fact{padding:22px 0 22px 20px}
    .fact:nth-child(3){border-left:none;padding-left:0}
    .fact:nth-child(3),.fact:nth-child(4){border-top:1px solid var(--line-soft)}
    .sec{padding:64px 22px}
    .values{grid-template-columns:1fr;gap:0}
    .value{padding:26px 0 0}
    .value + .value{padding-left:0;border-left:none}
    .services{grid-template-columns:1fr}
    .svc-card.lead{grid-template-columns:1fr}
    .svc-card.lead .svc-media{height:auto;min-height:0;aspect-ratio:16/10}
    .svc-card.lead .svc-body{padding:26px 24px 26px}
    .svc-card.lead .svc-price .pv{font-size:28px}
    .cta-inner{flex-direction:column;align-items:flex-start;padding:56px 22px;gap:26px}
    .foot{flex-direction:column;padding:36px 22px 44px}
  }

  /* 键盘可见的焦点环 */
  :focus-visible{
    outline:2px solid var(--accent);
    outline-offset:2px;
  }
  .node:focus-visible{outline-offset:3px}

  @media (prefers-reduced-motion: reduce){
    *,*::before,*::after{animation-duration:1ms !important;transition-duration:1ms !important}
  }

  /* ---------- 谱学术语：触发点 ---------- */
  .term{
    color:var(--accent);
    border-bottom:1px dashed var(--accent-line);
    cursor:help;padding-bottom:1px;
    transition:border-color var(--dur) var(--ease),background var(--dur) var(--ease);
  }
  .term:hover{border-bottom-color:var(--accent);background:var(--accent-soft)}
  .term:focus-visible{
    outline:none;border-radius:2px;
    border-bottom-color:var(--accent);
    box-shadow:0 0 0 2px var(--accent-soft);
  }
  .field label .term{font-size:11.5px;margin-left:3px}

  /* 气泡：贴着词的小浮层，不打断操作 */
  .term-pop{
    position:fixed;left:0;top:0;z-index:200;
    width:288px;max-width:calc(100vw - 24px);
    max-height:calc(100vh - 24px);overflow-y:auto;
    padding:14px 16px 15px;
    background:var(--raised);
    border:1px solid var(--line);
    border-radius:var(--r-md);
    box-shadow:var(--shadow-2);
    animation:popIn 140ms var(--ease);
  }
  .term-pop[hidden]{display:none}
  @keyframes popIn{from{opacity:0}to{opacity:1}}
  .term-pop .tp-term{
    display:flex;align-items:center;gap:9px;
    font-family:var(--serif);font-size:15px;font-weight:500;
    color:var(--ink);letter-spacing:.12em;margin-bottom:9px;
  }
  .term-pop .tp-term::after{content:'';flex:1;height:1px;background:var(--line-soft)}
  .term-pop p{font-size:12.5px;line-height:1.85;color:var(--ink-2);letter-spacing:.01em}
  .term-pop .tp-diff{color:var(--ink-3);margin-top:6px}
  /* 第三段是产品价值：谱上怎么记 */
  .term-pop .tp-record{
    margin-top:9px;padding:8px 10px;
    background:var(--sunken);
    border-left:2px solid var(--accent);
    border-radius:0 var(--r-sm) var(--r-sm) 0;
    color:var(--ink);
  }

  /* ---------- 详情面板：谱例 ---------- */
  /* 谱例：与照片区同属「附属区块」，用同一条实线上边界，
     不再单独用 1px 全边框 —— 面板里原来挤着虚线行、实线边、描边卡、底色卡四种分隔手法 */
  .p-gloss{
    margin:0;padding:16px 24px 18px;
    border-top:1px solid var(--line-soft);
  }
  .p-gloss .g-head{
    display:flex;align-items:center;gap:7px;
    font-size:12.5px;color:var(--ink);font-weight:500;
  }
  .p-gloss .g-head::before{
    content:'';flex:0 0 auto;width:2px;height:10px;background:var(--accent);
  }
  .p-gloss .g-note{
    margin-left:auto;
    font-size:11.5px;color:var(--ink-mute);font-weight:400;letter-spacing:.02em;
  }
  .p-gloss .g-line{
    margin-top:10px;font-size:13px;line-height:1.95;color:var(--ink);
  }
  .p-gloss .g-line .dot{color:var(--ink-4);margin:0 6px}
  .p-gloss .g-foot{
    margin-top:9px;font-size:12.5px;line-height:2;color:var(--ink-3);
  }

  /* ---------- 空谱状态：指南入口 ---------- */
  .stage-empty .se-link{
    margin-top:14px;font-size:12.5px;color:var(--ink-3);
  }
  .stage-empty .se-link button{
    border:none;background:transparent;padding:0;
    font-family:var(--sans);font-size:12.5px;color:var(--accent);
    cursor:pointer;border-bottom:1px solid var(--accent-line);
  }
  .stage-empty .se-link button:hover{border-bottom-color:var(--accent)}

  /* ---------- 指南浮层 ---------- */
  .guide{
    position:fixed;inset:0;z-index:140;
    display:flex;align-items:center;justify-content:center;
    padding:32px;
  }
  .guide[hidden]{display:none}
  .guide-mask{
    position:absolute;inset:0;
    background:rgba(25,23,20,.42);
    animation:fadeIn 200ms var(--ease);
  }
  .guide-panel{
    position:relative;
    width:100%;max-width:660px;max-height:86vh;
    background:var(--paper);
    border-radius:var(--r-lg);
    display:flex;flex-direction:column;overflow:hidden;
    box-shadow:var(--shadow-2);
    animation:sheetIn 220ms var(--ease);
  }
  .guide-head{
    flex:0 0 auto;padding:22px 32px 18px;
    border-bottom:1px solid var(--line-soft);
    display:flex;align-items:flex-start;justify-content:space-between;gap:16px;
  }
  .guide-head h2{
    font-family:var(--serif);font-size:18px;font-weight:500;
    letter-spacing:.05em;color:var(--ink);
  }
  .guide-close{
    flex:0 0 auto;width:28px;height:28px;
    display:flex;align-items:center;justify-content:center;
    border:none;background:transparent;cursor:pointer;
    color:var(--ink-3);font-size:18px;line-height:1;
    border-radius:var(--r-sm);
    transition:background var(--dur) var(--ease),color var(--dur) var(--ease);
  }
  .guide-close:hover{background:var(--sunken);color:var(--ink)}
  .guide-body{
    flex:1;overflow-y:auto;padding:24px 32px 28px;
    font-size:14.5px;line-height:2;color:var(--ink-2);
  }
  .guide-body .gd-lead{font-size:15px;line-height:1.95;color:var(--ink);margin-bottom:12px}
  .guide-body h3{
    position:relative;
    font-family:var(--serif);font-size:16px;font-weight:500;
    color:var(--ink);letter-spacing:.04em;line-height:1.6;
    margin:28px 0 11px;padding-left:12px;
  }
  /* 竖线用伪元素，高度随行盒走，比 border-left 更贴字 */
  .guide-body h3::before{
    content:'';position:absolute;left:0;top:.18em;bottom:.18em;
    width:2px;background:var(--accent);
  }
  .guide-body p{margin-bottom:12px}
  .guide-body b{font-weight:500;color:var(--ink)}
  .guide-body ul{margin:0 0 12px;padding-left:0;list-style:none}
  .guide-body li{position:relative;padding-left:14px;margin-bottom:4px}
  .guide-body li::before{
    content:'';position:absolute;left:2px;top:.86em;
    width:3px;height:3px;border-radius:50%;background:var(--ink-4);
  }
  .guide-foot{
    flex:0 0 auto;padding:16px 32px;
    border-top:1px solid var(--line-soft);
    display:flex;align-items:center;justify-content:space-between;gap:16px;
  }
  .guide-foot .gf-note{font-size:12px;color:var(--ink-3);line-height:1.7}

  @media (max-width:600px){
    .guide{padding:0;align-items:flex-end}
    .guide-panel{max-width:none;max-height:92vh;border-radius:var(--r-lg) var(--r-lg) 0 0}
    .guide-head{padding:20px 20px 16px}
    .guide-head h2{font-size:18px}
    .guide-body{padding:18px 20px 24px;font-size:14px;line-height:1.95}
    .guide-foot{padding:14px 20px;flex-direction:column;align-items:stretch;gap:10px}
    .guide-foot .gf-note{display:none}
    .guide-foot .btn{width:100%}
    .term-pop{width:auto;max-width:calc(100vw - 24px)}
    .p-gloss{margin:0 16px 14px}
  }

  /* ---------- 服务状态标识 ---------- */
  .svc-top h3{margin-right:auto}
  .svc-state{
    flex:0 0 auto;font-size:11px;line-height:1.5;letter-spacing:.04em;white-space:nowrap;
    padding:2px 7px;border-radius:4px;border:1px solid var(--line);
  }
  /* 主推角标用实底，状态标用描边：两个并排时不再长得一模一样 */
  .svc-state.is-quote{color:var(--accent);border-color:var(--accent-line);background:transparent}
  .svc-state.is-off{color:var(--ink-mute);border-color:var(--line);background:var(--sunken)}
  .svc-state.is-bought{color:var(--ink-2);border-color:var(--line);background:var(--sunken)}
  .svc-act{
    margin-top:14px;width:100%;height:34px;
    border:1px solid var(--line);border-radius:var(--r-sm);
    background:var(--raised);cursor:pointer;
    font-family:var(--sans);font-size:12.5px;color:var(--ink-2);
    transition:border-color var(--dur) var(--ease),color var(--dur) var(--ease),background var(--dur) var(--ease);
  }
  .svc-act:hover{border-color:var(--ink-4);color:var(--ink);background:var(--sunken)}

  /* ---------- 详情面板：照片区 ---------- */
  .p-photos{padding:16px 24px 14px;border-top:1px solid var(--line-soft)}
  .ph-head{display:flex;align-items:baseline;justify-content:space-between;gap:10px;margin-bottom:10px}
  .ph-head span:first-child{font-size:12px;color:var(--ink-3);letter-spacing:.02em}
  .ph-count{font-size:11.5px;color:var(--ink-mute)}
  .ph-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}
  /* 还没有照片时，不要留一个孤零零的三分之一宽虚线方块，横过来铺满一行 */
  .ph-grid:has(> .ph-add:only-child){grid-template-columns:1fr}
  .ph-grid:has(> .ph-add:only-child) .ph-add{aspect-ratio:auto;height:68px;font-size:22px}
  .ph-item{position:relative;aspect-ratio:1;border-radius:var(--r-sm);overflow:hidden;background:var(--sunken)}
  .ph-item img{width:100%;height:100%;object-fit:cover;display:block;cursor:zoom-in}
  .ph-del{
    position:absolute;top:4px;right:4px;width:20px;height:20px;
    display:flex;align-items:center;justify-content:center;
    border:none;border-radius:50%;cursor:pointer;
    background:rgba(25,23,20,.62);color:#FBF8F3;font-size:13px;line-height:1;
    opacity:0;transition:opacity var(--dur) var(--ease);
  }
  .ph-item:hover .ph-del,.ph-item:focus-within .ph-del{opacity:1}
  .ph-add{
    display:flex;align-items:center;justify-content:center;
    aspect-ratio:1;border:1px dashed var(--line);border-radius:var(--r-sm);
    color:var(--ink-mute);font-size:20px;cursor:pointer;
    transition:border-color var(--dur) var(--ease),color var(--dur) var(--ease),background var(--dur) var(--ease);
  }
  .ph-add:hover{border-color:var(--accent-line);color:var(--accent);background:var(--accent-soft)}
  .ph-buy{
    margin-top:10px;width:100%;height:32px;
    border:1px solid var(--accent-line);border-radius:var(--r-sm);
    background:var(--raised);cursor:pointer;
    font-family:var(--sans);font-size:12px;color:var(--accent);
    transition:border-color var(--dur) var(--ease),background var(--dur) var(--ease);
  }
  .ph-buy:hover{border-color:var(--accent);background:var(--accent-soft)}


  .ph-note{
    margin-top:8px;font-size:11.5px;color:var(--ink-mute);
    line-height:1.7;letter-spacing:.01em;
  }

  /* 照片大图 —— 必须锁在 #photoView 上。
     .pv 这个类名同时被服务卡的价格数值用过（<span class="pv">399</span>），
     按类名上样式会让三个价格数字变成 position:fixed 的深色全屏遮罩，
     滚到服务区就是一片黑。 */
  #photoView{
    position:fixed;inset:0;z-index:180;
    background:rgba(20,18,16,.92);
    display:flex;align-items:center;justify-content:center;
    padding:40px;cursor:zoom-out;
  }
  #photoView[hidden]{display:none}
  #photoView img{max-width:100%;max-height:100%;object-fit:contain}

  /* ---------- 付费说明：底部滑出 ---------- */
  .pay{position:fixed;inset:0;z-index:150;display:flex;align-items:flex-end;justify-content:center}
  .pay[hidden]{display:none}
  .pay-mask{position:absolute;inset:0;background:rgba(25,23,20,.42);animation:fadeIn 200ms var(--ease)}
  .pay-panel{
    position:relative;width:100%;max-width:540px;max-height:82vh;
    background:var(--paper);
    border-radius:var(--r-lg) var(--r-lg) 0 0;
    display:flex;flex-direction:column;
    box-shadow:0 -10px 48px rgba(25,23,20,.2);
    animation:payUp 280ms var(--ease);
  }
  @keyframes payUp{from{transform:translateY(100%)}to{transform:translateY(0)}}
  .pay-head{
    flex:0 0 auto;padding:22px 24px 18px;
    display:flex;align-items:flex-start;justify-content:space-between;gap:16px;
    border-bottom:1px solid var(--line-soft);
  }
  .pay-headtext{min-width:0}
  .pay-kicker{
    display:inline-block;font-size:11px;letter-spacing:.04em;line-height:1.5;
    color:var(--accent);border:1px solid var(--accent-line);
    background:var(--accent-soft);border-radius:4px;padding:2px 7px;
  }
  .pay-head h2{
    font-family:var(--serif);font-size:18px;font-weight:500;
    letter-spacing:.05em;margin-top:9px;color:var(--ink);
  }
  .pay-body{flex:1;overflow-y:auto;padding:18px 24px 22px}
  .pay-lead{font-size:13.5px;line-height:1.95;color:var(--ink)}
  .pay-points{margin:14px 0 0;padding:0;list-style:none}
  .pay-points li{
    position:relative;padding-left:14px;margin-bottom:7px;
    font-size:12.5px;line-height:1.85;color:var(--ink-2);
  }
  .pay-points li::before{
    content:'';position:absolute;left:2px;top:.78em;
    width:4px;height:1px;background:var(--accent);
  }
  .pay-price{
    margin-top:14px;padding:9px 12px;
    background:var(--sunken);border-radius:var(--r-sm);
    font-size:12.5px;color:var(--ink);letter-spacing:.02em;
  }
  .pay-ask{margin-top:20px;padding-top:18px;border-top:1px solid var(--line-soft)}
  .pay-ask[hidden]{display:none}
  .pay-ask label{display:block;font-size:12px;color:var(--ink-3);line-height:1.7;margin-bottom:9px}
  .pay-row{display:flex;gap:8px}
  .pay-row input{
    flex:1;min-width:0;height:38px;padding:0 12px;
    border:1px solid var(--line);border-radius:var(--r-sm);
    font-family:var(--sans);font-size:13px;color:var(--ink);
    background:var(--raised);outline:none;
    transition:border-color var(--dur) var(--ease),box-shadow var(--dur) var(--ease);
  }
  .pay-row input:focus{border-color:var(--ink-4);box-shadow:0 0 0 3px rgba(25,23,20,.05)}
  .pay-row .btn{height:38px;flex:0 0 auto}
  .pay-hint{font-size:11.5px;color:var(--accent);margin-top:7px;line-height:1.6}
  .pay-done{
    margin-top:18px;padding:14px 16px;
    background:var(--accent-soft);border-left:2px solid var(--accent);
    border-radius:0 var(--r-sm) var(--r-sm) 0;
    font-size:12.5px;line-height:1.9;color:var(--ink-2);
  }
  .pay-done[hidden]{display:none}
  .pay-done strong{font-weight:500;color:var(--ink)}
  .pay-foot{
    flex:0 0 auto;padding:14px 24px 18px;
    border-top:1px solid var(--line-soft);
    display:flex;align-items:center;justify-content:space-between;gap:14px;
  }
  .pay-note{font-size:11.5px;color:var(--ink-3);line-height:1.7}

  /* ---------- 导出 ---------- */
  .exp{position:fixed;inset:0;z-index:150;display:flex;align-items:flex-end;justify-content:center}
  .exp[hidden]{display:none}
  .exp-mask{position:absolute;inset:0;background:rgba(25,23,20,.42);animation:fadeIn 200ms var(--ease)}
  .exp-panel{
    position:relative;width:100%;max-width:540px;max-height:84vh;
    background:var(--paper);border-radius:var(--r-lg) var(--r-lg) 0 0;
    display:flex;flex-direction:column;
    box-shadow:0 -10px 48px rgba(25,23,20,.2);
    animation:payUp 280ms var(--ease);
  }
  .exp-head{
    flex:0 0 auto;padding:22px 24px 18px;
    border-bottom:1px solid var(--line-soft);
    display:flex;align-items:flex-start;justify-content:space-between;gap:16px;
  }
  .exp-head h2{font-family:var(--serif);font-size:18px;font-weight:500;letter-spacing:.05em}
  .exp-head p{font-size:12.5px;color:var(--ink-3);margin-top:7px;line-height:1.7}
  .exp-body{flex:1;overflow-y:auto;padding:6px 24px 20px}
  .exp-item{display:flex;align-items:center;gap:16px;padding:16px 0;border-bottom:1px solid var(--line-soft)}
  .exp-item:last-child{border-bottom:none}
  .exp-info{flex:1;min-width:0}
  .exp-info h3{
    font-size:13.5px;font-weight:500;color:var(--ink);
    display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  }
  .exp-free{
    font-size:11px;font-weight:400;letter-spacing:.04em;line-height:1.5;
    color:var(--ink-3);border:1px solid var(--line);
    border-radius:4px;padding:2px 7px;
  }
  .exp-info p{font-size:12.5px;color:var(--ink-3);line-height:1.75;margin-top:6px}
  .exp-item .btn{flex:0 0 auto;height:32px;font-size:12.5px;padding:0 14px;white-space:nowrap}
  .exp-photos{font-size:11.5px;color:var(--ink-mute);line-height:1.7;margin-top:10px}
  .exp-photos[hidden]{display:none}
  .exp-sep{height:1px;background:var(--line);margin:8px 0}
  .exp-item.is-paid .exp-info h3::after{
    content:'按项目计价';font-size:11px;font-weight:400;
    letter-spacing:.04em;line-height:1.5;
    color:var(--accent);background:var(--accent-soft);
    border-radius:4px;padding:2px 7px;
  }
  .exp-foot{
    flex:0 0 auto;padding:14px 24px 18px;
    border-top:1px solid var(--line-soft);
    font-size:11.5px;color:var(--ink-3);line-height:1.7;
  }

  @media (max-width:600px){
    .pay-panel,.exp-panel{max-width:none}
    .pay-head,.exp-head{padding-left:20px;padding-right:20px}
    .pay-body,.exp-body{padding-left:20px;padding-right:20px}
    .pay-foot,.exp-foot{padding-left:20px;padding-right:20px}
    .pay-foot .pay-note{display:none}
    .pay-row{flex-direction:column}
    .pay-row .btn{width:100%}
    .exp-item{flex-direction:column;align-items:stretch;gap:10px}
    .exp-item .btn{width:100%}
  }

/* ==================================================================
   后台管理 #/admin
   DOM 与 class 由 lib/admin.js 运行时生成，这里只管样式。
   2026-10-30 从 admin.js 的 ADMIN_CSS 常量搬过来，类名一个未改。
   ================================================================== */

/* ---- 顶栏待审红点 ---- */
.adm-dot{
  position:absolute;top:-3px;right:-4px;min-width:16px;height:16px;
  padding:0 4px;border-radius:9px;background:var(--accent);color:#FBF8F3;
  font-family:var(--sans);font-size:10px;line-height:16px;text-align:center;
  letter-spacing:0;pointer-events:none;
}
.adm-dot[hidden]{display:none}

/* ---- 世系页的待审标记 ---- */
.pend-tag{
  display:inline-block;margin-left:7px;padding:1px 6px;border-radius:3px;
  font-family:var(--sans);font-size:10.5px;font-weight:400;letter-spacing:.04em;
  color:var(--accent);background:var(--accent-soft);border:1px solid var(--accent-line);
  vertical-align:2px;
}
.pend-banner{
  margin:0 24px;padding:9px 12px;
  background:var(--accent-soft);border-left:2px solid var(--accent);
  font-size:12px;color:var(--ink-2);letter-spacing:.02em;
}

/* ---- 骨架 ---- */
.adm-body{flex:1;display:flex;min-height:0;background:var(--paper)}

/* 左侧 tab 栏：底色比内容区深一档，加右侧细线，形成「导轨」而不是糊成一片 */
.adm-tabs{
  flex:0 0 176px;width:176px;padding:18px 12px;
  border-right:1px solid var(--line);
  background:var(--sunken);
  display:flex;flex-direction:column;gap:2px;
}
/* hidden 属性必须压得住 display:flex，否则 js 用 hidden 藏起来的 tab 照样显示。
   这跟之前 .pv 那个 bug 同源：作者样式优先级高于 UA 的 [hidden]{display:none}。 */
.adm-tabs[hidden], .adm-tab[hidden], .adm-badge[hidden]{display:none !important}
/* 一个 tab 都不可见时整栏收起，否则族员会看到一个 176px 的空竖条 */
.adm-tabs:not(:has(.adm-tab:not([hidden]))){display:none}

.adm-tab{
  position:relative;
  display:flex;align-items:center;justify-content:space-between;gap:8px;
  padding:9px 12px;border:none;border-radius:var(--r-sm);background:transparent;
  font-family:var(--sans);font-size:13px;color:var(--ink-2);
  cursor:pointer;text-align:left;letter-spacing:.02em;
  transition:background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.adm-tab:hover{background:var(--line-soft)}
/* 选中态：朱砂左栏 + 暖白底 + 朱砂字 + 加粗，四种信号叠起来才一眼可辨 */
.adm-tab.on{background:var(--accent-soft);color:var(--accent);font-weight:500}
.adm-tab.on::before{
  content:'';position:absolute;left:0;top:50%;
  width:2px;height:16px;margin-top:-8px;
  background:var(--accent);border-radius:1px;
}
.adm-tab .adm-badge{
  min-width:18px;padding:0 5px;border-radius:9px;
  font-size:10.5px;line-height:17px;text-align:center;
  background:var(--accent);color:#FBF8F3;
}
.adm-tab .adm-badge[hidden]{display:none}

.adm-panel{flex:1;min-width:0;overflow-y:auto;padding:0 32px 60px}
/* 顶部留白从 panel 的 padding 挪到标题的 margin：sticky 表头按滚动容器顶边吸附，
   panel 留 26px 内边距会让表头永远差 26px，露出正在滚走的内容。 */

.adm-h{
  font-family:var(--serif);font-size:17px;font-weight:500;
  letter-spacing:.05em;color:var(--ink);margin:26px 0 6px;
}
.adm-sub{font-size:12.5px;line-height:1.8;color:var(--ink-3);margin-bottom:20px;max-width:640px}
.adm-sub b{color:var(--ink-2);font-weight:500}

.adm-search{
  width:100%;max-width:280px;height:32px;padding:0 11px;margin-bottom:14px;
  border:1px solid var(--line);border-radius:var(--r-sm);
  font-family:var(--sans);font-size:12.5px;color:var(--ink);
  background:var(--raised);outline:none;
}
.adm-search:focus{border-color:var(--ink-4)}

/* ---- 表格 ----------------------------------------------------
   table-layout:fixed 才压得住列宽。改前是 auto，浏览器按内容分，
   1920 下五列宽 [384,256,444,327,253]，忽宽忽窄。
   ---------------------------------------------------------------- */
.adm-table{width:100%;border-collapse:separate;border-spacing:0;table-layout:fixed;font-size:12.5px}

.adm-table th{
  padding:8px 10px;text-align:left;font-weight:500;
  font-size:11.5px;letter-spacing:.06em;color:var(--ink-3);
  background:var(--sunken);
  border-top:1px solid var(--line);
  border-bottom:1px solid var(--line);
  white-space:nowrap;
}
/* 表头吸顶。必须配 border-collapse:separate —— collapse 模式下 Chrome 的 sticky
   表头会丢边框、甚至把表头整块裁掉。156 行滚到中段看不见列名，这个不能省。 */
.adm-table thead th{
  position:sticky;top:0;z-index:3;
  box-shadow:inset 0 -1px 0 var(--line);
}
.adm-table td{
  padding:7px 10px;height:38px;box-sizing:border-box;
  border-bottom:1px solid var(--line-soft);
  color:var(--ink-2);vertical-align:middle;
}
.adm-table tr:hover td{background:var(--sunken)}
.adm-table .adm-name{color:var(--ink);font-weight:500}
.adm-table select{
  height:24px;padding:0 6px;border:1px solid var(--line);border-radius:5px;
  font-family:var(--sans);font-size:12px;color:var(--ink-2);background:var(--raised);
}

/* 列宽：职级表（无下拉）与成员表（有下拉）分开给 */
.adm-table th:nth-child(1){width:28%}
.adm-table th:nth-child(2){width:22%}
.adm-table th:nth-child(3){width:22%}
.adm-table th:nth-child(4){width:14%}
.adm-table th:nth-child(5){width:14%}

.adm-table:has(tbody select) th:nth-child(1){width:24%}
.adm-table:has(tbody select) th:nth-child(2){width:16%}
.adm-table:has(tbody select) th:nth-child(3){width:22%}
.adm-table:has(tbody select) th:nth-child(4){width:19%}
.adm-table:has(tbody select) th:nth-child(5){width:19%}

/* 数字列右对齐，末列贴住右边缘，不在右侧留一块空 */
.adm-table:has(tbody select) th:nth-child(5),
.adm-table:has(tbody select) td:nth-child(5){text-align:right}

.adm-table:not(:has(tbody select)) th:nth-child(4),
.adm-table:not(:has(tbody select)) td:nth-child(4){text-align:right}

.adm-table:not(:has(tbody select)) th:nth-child(5),
.adm-table:not(:has(tbody select)) td:nth-child(5){text-align:right}

.adm-muted{color:var(--ink-mute)}
.adm-num{
  display:inline-block;min-width:18px;padding:0 5px;border-radius:9px;
  font-size:10.5px;line-height:16px;text-align:center;
  background:var(--accent-soft);color:var(--accent);
  font-variant-numeric:tabular-nums;
}
/* 0 不着色：连底色也去掉，只剩一个灰字，不抢视线 */
.adm-num.zero{background:transparent;color:var(--ink-mute)}

/* ---- 审核卡片 ---- */
.adm-card{
  border:1px solid var(--line);border-radius:var(--r-md);
  padding:16px 18px;margin-bottom:12px;background:var(--raised);
}
.adm-card-hd{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
.adm-card-hd h3{font-size:13.5px;font-weight:500;color:var(--ink);letter-spacing:.03em}
.adm-card-meta{font-size:11.5px;color:var(--ink-mute)}
.adm-diff{
  margin-top:10px;display:flex;flex-wrap:wrap;gap:6px 18px;
  font-size:12.5px;color:var(--ink-2);
}
.adm-diff span.k{color:var(--ink-3);font-size:11.5px;margin-right:5px}
.adm-diff .from{color:var(--ink-mute);text-decoration:line-through}
.adm-diff .arrow{color:var(--ink-4);margin:0 5px}
.adm-diff .to{color:var(--ink);font-weight:500}
.adm-acts{margin-top:12px;display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.adm-reject-box{margin-top:10px;display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.adm-reject-box input{
  flex:1;min-width:200px;height:30px;padding:0 10px;
  border:1px solid var(--line);border-radius:var(--r-sm);
  font-family:var(--sans);font-size:12.5px;color:var(--ink);
  background:var(--raised);outline:none;
}

/* ---- 空态：区块级（L2）----------------------------------------
   与页面级空态（世系 .stage-empty / 排版 .print-empty）共用一套字号：
   12.5px / 行高 1.9 / --ink-3。区别只在没有印章与标题——
   这两级的分工见 docs/当前状态.md 的「空态两级制」。
   ---------------------------------------------------------------- */
.adm-empty{
  margin-top:4px;max-width:560px;padding:40px 24px;text-align:center;
  font-size:12.5px;line-height:1.9;color:var(--ink-3);
  border:1px dashed var(--line);border-radius:var(--r-md);
  background:var(--raised);
}

/* ---- 表单 ---- */
.adm-form{display:flex;gap:9px;flex-wrap:wrap;align-items:flex-end;margin-top:16px}
.adm-form label{display:block;font-size:11.5px;color:var(--ink-3);margin-bottom:5px;letter-spacing:.04em}
.adm-form input,.adm-form select{
  height:32px;padding:0 10px;border:1px solid var(--line);border-radius:var(--r-sm);
  font-family:var(--sans);font-size:12.5px;color:var(--ink);background:var(--raised);outline:none;
}
.adm-form input:focus,.adm-form select:focus{border-color:var(--ink-4)}
.adm-form .grow{flex:1;min-width:150px}

/* ---- 设置页 ---- */
.adm-switch{
  display:flex;align-items:center;justify-content:space-between;gap:20px;
  padding:14px 0;border-bottom:1px solid var(--line-soft);
}
.adm-switch:last-child{border-bottom:none}
.adm-switch .t{font-size:13px;color:var(--ink)}
.adm-switch .d{font-size:11.5px;color:var(--ink-3);margin-top:4px;line-height:1.7}
.adm-seg{display:flex;gap:0;border:1px solid var(--line);border-radius:var(--r-sm);overflow:hidden;flex:0 0 auto}
.adm-seg button{
  padding:6px 13px;border:none;background:var(--raised);
  font-family:var(--sans);font-size:12px;color:var(--ink-3);cursor:pointer;
  transition:background var(--dur) var(--ease),color var(--dur) var(--ease);
}
.adm-seg button + button{border-left:1px solid var(--line)}
.adm-seg button.on{background:var(--accent-soft);color:var(--accent)}

.adm-actor{display:flex;align-items:center;gap:8px}
.adm-actor span{font-size:11.5px;color:var(--ink-3);letter-spacing:.04em}
.adm-actor select{
  height:30px;padding:0 8px;border:1px solid var(--line);border-radius:var(--r-sm);
  font-family:var(--sans);font-size:12.5px;color:var(--ink-2);background:var(--raised);
}
.adm-check{display:flex;align-items:center;gap:7px;font-size:12px;color:var(--ink-3);cursor:pointer}
.adm-check input{accent-color:var(--accent)}

/* ---- 管理权 ---- */
.adm-owner-list{margin-top:12px}
.adm-owner{display:flex;align-items:center;gap:10px;padding:10px 0;border-bottom:1px solid var(--line-soft)}
.adm-owner:last-child{border-bottom:none}
.adm-owner-name{font-size:13px;color:var(--ink)}
.adm-owner-meta{font-size:11.5px;color:var(--ink-3)}
.adm-owner-dead{font-size:11px;color:var(--ink-mute);border:1px solid var(--line);border-radius:3px;padding:1px 6px}
.adm-owner .btn{margin-left:auto;height:28px;font-size:12px}
.adm-note{font-size:11.5px;color:var(--ink-mute);line-height:1.75;margin-top:10px}

/* ---- 标记已故对话框 ---- */
.adm-dialog{margin-top:14px;padding:14px 16px;border:1px solid var(--line);border-radius:var(--r-sm);background:var(--sunken)}
.adm-dialog-hd{font-size:13px;color:var(--ink);margin-bottom:12px}
.adm-dialog label{display:block;font-size:12px;color:var(--ink-3);margin-bottom:10px;line-height:1.7}
.adm-dialog .adm-check{margin-bottom:12px}
.adm-input{display:block;width:100%;height:32px;margin-top:6px;padding:0 10px;
  border:1px solid var(--line);border-radius:var(--r-sm);background:var(--raised);
  font-family:var(--sans);font-size:13px;color:var(--ink);outline:none;
  transition:border-color var(--dur) var(--ease),box-shadow var(--dur) var(--ease);}
.adm-input:focus{border-color:var(--ink-4)}
.adm-input:disabled{background:var(--paper);color:var(--ink-mute);cursor:not-allowed}
.adm-input.err{border-color:var(--accent);box-shadow:0 0 0 2px rgba(138,54,43,.1)}
.adm-dialog select{display:block;width:100%;height:32px;margin-top:6px;padding:0 8px;
  border:1px solid var(--line);border-radius:var(--r-sm);background:var(--raised);
  font-family:var(--sans);font-size:12.5px;color:var(--ink);}
.adm-dlg-err{min-height:18px;font-size:12px;color:var(--accent);line-height:1.6}
.adm-dlg-acts{display:flex;gap:8px;justify-content:flex-end;margin-top:8px}
.adm-dlg-acts .btn{height:30px;font-size:12.5px}

/* ==================================================================
   谱的体检（#/check）
   只读诊断页：一张汇总卡 + 三组可折叠列表 + 两种空态。
   配色一律用 :root 里的变量，不新造颜色。
   ================================================================== */
.chk-body{flex:1 1 auto;overflow-y:auto;padding:34px 28px 90px}

.chk-head{max-width:880px;margin:0 auto 24px}
.chk-head h2{
  font-family:var(--serif);font-size:24px;font-weight:500;
  letter-spacing:.06em;color:var(--ink);
}
.chk-sub{margin-top:8px;font-size:12.5px;color:var(--ink-3);letter-spacing:.02em}

.chk-sum{display:flex;gap:8px;flex-wrap:wrap;margin-top:16px}
.chk-pill{font-size:12px;padding:4px 11px;border-radius:999px;letter-spacing:.02em}
.chk-pill.err{color:var(--accent);background:var(--accent-soft)}
.chk-pill.warn{color:var(--ink-2);background:var(--sunken)}
.chk-pill.info{color:var(--ink-3);background:var(--sunken)}

/* 只有「还能补」时用这一行，不摆药丸——免得看着像查出了问题 */
.chk-ok{margin-top:14px;font-size:12.5px;color:var(--ink-2);letter-spacing:.02em}

/* ---------- 分组 ---------- */
.chk-group{
  max-width:880px;margin:0 auto 14px;
  border:1px solid var(--line);border-radius:var(--r-md);
  background:var(--raised);overflow:hidden;
}
.chk-gh{
  list-style:none;cursor:pointer;user-select:none;
  display:flex;align-items:center;gap:10px;
  padding:14px 18px;font-size:13.5px;color:var(--ink);letter-spacing:.04em;
  transition:background var(--dur) var(--ease);
}
.chk-gh::-webkit-details-marker{display:none}
.chk-gh:hover{background:var(--sunken)}
.chk-gh:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.chk-gh::before{content:'';width:2px;height:12px;background:var(--accent);flex:0 0 auto}
.chk-group[data-g="warn"] .chk-gh::before,
.chk-group[data-g="info"] .chk-gh::before{background:var(--ink-4)}
.chk-gh::after{content:'展开';margin-left:auto;font-size:11.5px;color:var(--ink-mute)}
.chk-group[open] .chk-gh::after{content:'收起'}
.chk-group[open] .chk-gh{border-bottom:1px solid var(--line-soft)}
.chk-n{
  font-size:11.5px;color:var(--ink-3);background:var(--sunken);
  border-radius:999px;padding:2px 9px;font-variant-numeric:tabular-nums;
}

.chk-list{list-style:none;margin:0;padding:4px 0}
.chk-item{
  display:grid;grid-template-columns:1fr auto;grid-template-areas:"t go" "d go";
  gap:3px 16px;align-items:center;
  padding:12px 18px;cursor:pointer;
  border-bottom:1px solid var(--line-soft);
  transition:background var(--dur) var(--ease);
}
.chk-item:last-child{border-bottom:none}
.chk-item:hover{background:var(--sunken)}
.chk-t{grid-area:t;font-size:13px;color:var(--ink);line-height:1.6}
.chk-d{grid-area:d;font-size:11.5px;color:var(--ink-3);line-height:1.6}
.chk-go{grid-area:go;font-size:11.5px;color:var(--ink-mute);white-space:nowrap;
  transition:color var(--dur) var(--ease)}
.chk-item:hover .chk-go{color:var(--accent)}

/* ---------- 空态：印章 + 一句结论 ---------- */
.chk-clean{
  max-width:880px;margin:36px auto 0;padding:56px 24px;
  text-align:center;background:var(--raised);
  border:1px solid var(--line);border-radius:var(--r-lg);
}
.chk-seal{
  width:44px;height:44px;border-radius:8px;
  background:var(--accent);color:#FBF8F3;
  font-family:var(--serif);font-size:22px;
  display:flex;align-items:center;justify-content:center;
  margin:0 auto 20px;
}
.chk-clean h3{
  font-family:var(--serif);font-size:19px;font-weight:500;letter-spacing:.06em;color:var(--ink);
}
.chk-clean p{
  margin-top:10px;font-size:12.5px;color:var(--ink-3);line-height:1.9;
}
.chk-clean .btn{margin-top:22px;height:36px;padding:0 18px}

/* ==================================================================
   卷首文字（#/essays）
   左栏三篇、右栏编辑。这里是「编辑页」的样式；
   谱页上印出来的那三篇归 print.css 的 .pg-essay / .essay-*，
   两套类名不共用，改一边不会牵动另一边。
   ================================================================== */
.es-body{flex:1;display:flex;min-height:0}

.es-nav{
  flex:0 0 212px;width:212px;
  padding:22px 14px 32px;
  border-right:1px solid var(--line);
  background:var(--raised);
  overflow-y:auto;
}
.es-tab{
  display:block;width:100%;text-align:left;
  padding:11px 12px;margin-bottom:6px;
  border:1px solid transparent;border-radius:var(--r-sm);
  background:transparent;cursor:pointer;
  transition:background var(--dur) var(--ease),border-color var(--dur) var(--ease);
}
.es-tab:hover{background:var(--sunken)}
.es-tab.on{background:var(--accent-soft);border-color:var(--accent-line)}
.es-tab:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
.es-tab-n{
  display:flex;align-items:center;gap:6px;
  font-family:var(--serif);font-size:15px;letter-spacing:.1em;color:var(--ink);
}
.es-tab.on .es-tab-n{color:var(--accent)}
/* 写过的那篇点一个朱砂点，省得逐篇点开找「哪篇还没写」 */
.es-dot{width:5px;height:5px;border-radius:50%;background:var(--accent);flex:0 0 auto}
.es-tab-s{display:block;margin-top:4px;font-size:11.5px;color:var(--ink-3);line-height:1.6}
.es-note{
  margin-top:18px;padding-top:14px;border-top:1px solid var(--line-soft);
  font-size:11.5px;color:var(--ink-mute);line-height:1.85;
}
.es-note b{font-weight:400;color:var(--ink-2)}

.es-main{flex:1;min-width:0;overflow-y:auto;padding:28px 32px 96px}
.es-wrap{max-width:720px}
.es-field{display:block;margin-bottom:18px}
.es-label{display:block;margin-bottom:7px;font-size:11.5px;color:var(--ink-3);letter-spacing:.08em}

.es-input{
  width:100%;height:36px;padding:0 12px;
  border:1px solid var(--line);border-radius:var(--r-sm);
  background:var(--raised);
  font-family:var(--serif);font-size:14px;color:var(--ink);
  outline:none;
  transition:border-color var(--dur) var(--ease),box-shadow var(--dur) var(--ease);
}
.es-input:focus{border-color:var(--ink-4);box-shadow:0 0 0 3px rgba(25,23,20,.05)}
.es-input::placeholder{color:var(--ink-mute)}
.es-input:disabled{background:var(--paper);color:var(--ink-2);cursor:not-allowed}

/* 正文框：衬线、行距放到 2，接近谱页上的观感。用户在这里看到的就是印出来的样子 */
.es-area-wrap{position:relative}
.es-area{
  display:block;width:100%;min-height:320px;
  padding:14px 14px 34px;
  border:1px solid var(--line);border-radius:var(--r-sm);
  background:var(--raised);
  font-family:var(--serif);font-size:14px;line-height:2;color:var(--ink);
  outline:none;resize:vertical;
  transition:border-color var(--dur) var(--ease),box-shadow var(--dur) var(--ease);
}
.es-area:focus{border-color:var(--ink-4);box-shadow:0 0 0 3px rgba(25,23,20,.05)}
.es-area::placeholder{color:var(--ink-mute);font-size:13px;line-height:1.9}
.es-area:disabled{background:var(--paper);color:var(--ink-2);cursor:not-allowed}

/* 字数与「只有族长能改」都在正文框内部下沿，不占版面 */
.es-count{
  position:absolute;right:16px;bottom:10px;   /* 16px 是给 textarea 右下角那个缩放柄让位 */
  font-size:11px;color:var(--ink-mute);letter-spacing:.03em;
  pointer-events:none;font-variant-numeric:tabular-nums;
}
.es-ro{
  position:absolute;left:12px;bottom:10px;
  font-size:11px;color:var(--accent);letter-spacing:.03em;pointer-events:none;
}

/* 署名与落款并排。窄屏折行由 flex-wrap 兜住，不做断点 */
.es-row{display:flex;gap:16px;flex-wrap:wrap}
.es-row .es-field{flex:1 1 200px;min-width:0}

.es-saved{font-size:12px;color:var(--ink-3);opacity:0;transition:opacity .3s var(--ease)}
.es-saved.on{opacity:1}

/* ---------- 写作提纲（谱序 / 后记） ---------- */
.es-out{
  margin-top:8px;
  border:1px solid var(--line);border-radius:var(--r-md);
  background:var(--raised);overflow:hidden;
}
.es-out-h{
  display:flex;align-items:center;gap:10px;
  padding:13px 16px;cursor:pointer;user-select:none;
  font-size:12.5px;color:var(--ink-2);letter-spacing:.06em;
}
.es-out-h::-webkit-details-marker{display:none}
.es-out-h:hover{background:var(--sunken)}
.es-out-h::before{content:'▸';font-size:10px;color:var(--ink-mute)}
.es-out[open] .es-out-h::before{content:'▾'}
.es-out-n{margin-left:auto;font-size:11px;color:var(--ink-mute)}
.es-out-list{
  margin:0;padding:0 20px 12px 34px;
  font-size:13px;color:var(--ink-2);
}
.es-out-list li{padding:9px 0;border-top:1px solid var(--line-soft);line-height:1.8}
.es-out-list li::marker{color:var(--ink-mute);font-size:12px}
.es-out-list b{display:block;font-weight:400;color:var(--ink)}
.es-out-list span{display:block;margin-top:3px;font-size:11.5px;color:var(--ink-3);line-height:1.75}

/* ---------- 凡例条款 ---------- */
.es-clauses{
  margin-top:8px;
  border:1px solid var(--line);border-radius:var(--r-md);
  background:var(--raised);overflow:hidden;
}
.es-cl-h{padding:16px 18px 13px;border-bottom:1px solid var(--line-soft)}
.es-cl-h h3{font-size:13.5px;font-weight:500;color:var(--ink);letter-spacing:.06em}
.es-cl-h p{margin-top:6px;font-size:11.5px;color:var(--ink-3);line-height:1.8}
.es-cl-list{margin:0;padding:0;list-style:none}
.es-cl{padding:12px 18px;border-bottom:1px solid var(--line-soft)}
.es-cl:last-child{border-bottom:none}
.es-cl label{display:flex;align-items:flex-start;gap:10px;cursor:pointer}
.es-cl input{margin-top:3px;flex:0 0 auto;accent-color:var(--accent)}
.es-cl input:disabled{cursor:not-allowed}
.es-cl-t{font-family:var(--serif);font-size:13px;color:var(--ink);line-height:1.85}
.es-cl-h2{display:block;margin:4px 0 0 24px;font-size:11px;color:var(--ink-mute);line-height:1.7}
.es-cl-foot{
  display:flex;align-items:center;gap:12px;
  padding:12px 18px;border-top:1px solid var(--line-soft);background:var(--paper);
}
.es-cl-n{margin-right:auto;font-size:11.5px;color:var(--ink-3)}
.es-cl-n b{font-weight:500;color:var(--ink);font-variant-numeric:tabular-nums}

/* ==================================================================
   只读分享（#/s/<token>）
   横幅用 accent-soft 不用纯灰：灰的看起来像页面坏了。
   ================================================================== */
.share-bar{
  display:flex;align-items:center;gap:10px;
  height:36px;padding:0 18px;flex:0 0 auto;
  background:var(--accent-soft);border-bottom:1px solid var(--accent-line);
  font-size:12.5px;color:var(--ink-2);
}
.share-bar[hidden]{display:none}
.share-bar .sb-dot{width:6px;height:6px;border-radius:50%;background:var(--accent);flex:0 0 auto}
.share-bar .sb-t b{font-weight:600;color:var(--ink)}
.share-bar .sb-hint{color:var(--ink-3);margin-left:2px}
.share-bar .sb-cta{
  margin-left:auto;color:var(--accent);text-decoration:none;
  border-bottom:1px solid var(--accent-line);padding-bottom:1px;
}
.share-bar .sb-cta:hover{border-bottom-color:var(--accent)}

/* 链接失效页：整页居中，一句话 + 一个按钮。
   不要写「请联系管理员」——访客不知道该联系谁。 */
.share-err{
  position:fixed;inset:0;z-index:9000;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  padding:24px;text-align:center;background:var(--paper);
}
.share-err[hidden]{display:none}
.share-err .se-seal{
  width:46px;height:46px;border-radius:8px;
  background:var(--accent);color:#FBF8F3;
  font-family:var(--serif);font-size:23px;
  display:flex;align-items:center;justify-content:center;
  margin-bottom:20px;
}
.share-err h2{
  font-family:var(--serif);font-size:20px;font-weight:500;
  letter-spacing:.06em;color:var(--ink);
}
.share-err p{
  margin-top:12px;max-width:420px;
  font-size:12.5px;line-height:1.95;color:var(--ink-3);
}
.share-err .se-btn{
  margin-top:24px;height:38px;padding:0 22px;
  display:inline-flex;align-items:center;justify-content:center;
  border-radius:7px;background:var(--accent);color:#fff;
  font-size:13px;letter-spacing:.1em;text-decoration:none;
}

/* ---------- 分享浮层 ---------- */
.sh-lede{margin:0 0 16px;font-size:12.5px;color:var(--ink-2);line-height:1.85}
.sh-gen{display:flex;align-items:flex-end;gap:10px;margin-bottom:6px}
.sh-days{flex:1;min-width:0}
.sh-days span{display:block;font-size:11.5px;color:var(--ink-3);letter-spacing:.05em;margin-bottom:5px}
.sh-days select{
  width:100%;height:36px;padding:0 10px;
  border:1px solid var(--line);border-radius:7px;
  background:var(--paper);color:var(--ink);font-size:13px;outline:none;
}
.sh-days select:focus{border-color:var(--accent-line);background:#fff}
.sh-gen .ovl-btn{width:auto;flex:0 0 auto;padding:0 18px;margin-top:0;height:36px}
.sh-sec-h{
  margin:20px 0 8px;padding-top:14px;border-top:1px solid var(--line-soft);
  font-size:11.5px;letter-spacing:.08em;color:var(--ink-3);
}
.sh-empty{font-size:12px;color:var(--ink-mute);line-height:1.85;padding:8px 0}
.sh-item{
  border:1px solid var(--line);border-radius:9px;
  padding:10px 12px;margin-bottom:8px;background:var(--paper);
}
.sh-item.is-dead{opacity:.55}
.sh-item-t{font-size:12.5px;color:var(--ink)}
.sh-item-m{margin-top:3px;font-size:11.5px;color:var(--ink-3)}
.sh-item-m b{font-weight:600;color:var(--ink-2);font-variant-numeric:tabular-nums}
.sh-item-acts{display:flex;gap:6px;margin-top:8px}
.sh-mini{
  height:26px;padding:0 10px;border:1px solid var(--line);
  background:var(--raised);border-radius:6px;
  font-family:var(--sans);font-size:11.5px;color:var(--ink-2);cursor:pointer;
}
.sh-mini:hover{border-color:var(--accent-line);color:var(--accent)}
.sh-mini.danger:hover{border-color:#E3C9C4;color:var(--accent)}
.sh-mini:disabled{opacity:.45;cursor:default;border-color:var(--line);color:var(--ink-mute)}

/* ==================================================================
   连续录入浮条
   固定在画布底部居中，不占布局：它是一条「顺手继续」的捷径，
   不是必须处理的提示，所以不用模态、不加遮罩、不抢焦点。
   ================================================================== */
.more-bar{
  position:fixed;left:50%;bottom:28px;transform:translateX(-50%);
  z-index:120;
  display:flex;align-items:center;gap:8px;
  padding:9px 10px 9px 16px;
  background:var(--raised);border:1px solid var(--line);
  border-radius:var(--r-lg);
  box-shadow:0 8px 30px rgba(25,23,20,.16);
  font-size:12.5px;color:var(--ink-2);
  animation:mbIn 220ms var(--ease);
}
.more-bar[hidden]{display:none}
@keyframes mbIn{from{opacity:0;transform:translate(-50%,8px)}to{opacity:1;transform:translate(-50%,0)}}
.more-bar .mb-t b{font-weight:600;color:var(--ink)}
.more-bar .mb-q{color:var(--ink-3);margin-left:2px}
.more-bar .mb-btn{
  height:28px;padding:0 12px;border:1px solid var(--line);
  background:var(--paper);border-radius:var(--r-sm);
  font-family:var(--sans);font-size:12.5px;color:var(--ink-2);cursor:pointer;
}
.more-bar .mb-btn:hover{border-color:var(--accent-line);color:var(--accent)}
.more-bar .mb-close{
  height:28px;padding:0 10px;margin-left:4px;border:none;background:none;
  font-family:var(--sans);font-size:12.5px;color:var(--ink-3);cursor:pointer;
}
.more-bar .mb-close:hover{color:var(--ink)}

/* [hidden] 是 UA 样式，任何 author 的 display 规则都能盖掉它。
   .avatar 就中过这一枪：属性为 true，页面上还在。 */
.avatar[hidden]{display:none!important}


/* ===== print.css ===== */
/**
 * 谱页打印样式
 *
 * 归属开发会话。styles.css 是设计会话的，这里只放和排版强耦合的东西：
 * 纸面尺寸、分页控制、字号、页眉页脚。
 *
 * 一条硬规则：@page 的 margin 必须是 0，纸面留白全部由 .pg 的 padding 控制。
 * 否则浏览器会在 CSS 边距之外再套一层默认边距，210mm 宽的页面会被挤到第二张纸。
 */

/* ==================================================================
   纸
   ================================================================== */
@page {
  size: A4;
  margin: 0;
}

/* ==================================================================
   一页
   296.6 而不是 297：297 在部分缩放比下会因像素舍入多挤出一张空白页
   ================================================================== */
.pg {
  position: relative;
  box-sizing: border-box;
  width: 210mm;
  height: 296.6mm;
  padding: 26mm 18mm 24mm;
  background: #fff;
  color: var(--ink, #191714);
  /* 跟着「谱面字体」走：写死宋体的话，切楷体在谱面上不生效，
     而 iOS / Android 大多没有宋体/楷体，写死等于在移动端直接掉字形 */
  font-family: var(--serif, 'Songti SC', 'Noto Serif SC', 'SimSun', 'STSong', serif);
  font-size: 12pt;
  line-height: 1.9;
  overflow: hidden;
  box-shadow: 0 2px 6px rgba(25, 23, 20, .06), 0 16px 40px rgba(25, 23, 20, .10);
}

/* 正文区：174mm × 246.6mm。JS 按这个高度分页，超出的在源头就截断了 */
.pg-body {
  height: 246.6mm;
  overflow: hidden;
}

/* ==================================================================
   页眉页脚
   ================================================================== */
.pg-head,
.pg-foot {
  position: absolute;
  left: 18mm;
  right: 18mm;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  font-size: 9pt;
  line-height: 1.6;
  letter-spacing: .02em;
  color: var(--ink-3, #6F6758);
}

.pg-head {
  top: 11mm;
  padding-bottom: 2.6mm;
  border-bottom: .5pt solid var(--line, #E7E1D5);
}

.pg-foot {
  bottom: 11mm;
  padding-top: 2.6mm;
  border-top: .5pt solid var(--line, #E7E1D5);
}

.pg-head .ph-r {
  letter-spacing: .1em;
  color: var(--accent, #8A362B);
}

.pg-foot .pf-l {
  letter-spacing: .1em;
}

.pg-foot .pf-r {
  font-variant-numeric: tabular-nums;
  letter-spacing: .04em;
}

/* ==================================================================
   牒记式：一人一条
   13pt 宋体一个字 4.586mm，174mm 正好 38 字一行
   ================================================================== */
.leaf {
  break-inside: avoid;
  page-break-inside: avoid;
}

.leaf + .leaf {
  margin-top: 6.4mm;
}

.leaf-hd {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0 8pt;
}

.leaf-name {
  font-size: 14pt;
  font-weight: 600;
  letter-spacing: .06em;
  line-height: 1.3;
}

.leaf-art {
  font-size: 10.5pt;
  color: var(--ink-2, #5C564C);
  letter-spacing: .04em;
}

.leaf-gen {
  margin-left: auto;
  font-size: 9.5pt;
  letter-spacing: .1em;
  color: var(--accent, #8A362B);
}

.leaf-life {
  font-size: 10pt;
  color: var(--ink-3, #6F6758);
  font-variant-numeric: tabular-nums;
  letter-spacing: .02em;
}

.leaf-rel {
  margin: 1.5mm 0 0;
  font-size: 10.5pt;
  line-height: 1.7;
  color: var(--ink-2, #5C564C);
}

.leaf-rel .rl {
  display: inline-block;
  min-width: 2.2em;
  font-size: 9.5pt;
  color: var(--ink-3, #6F6758);
  letter-spacing: .06em;
}

.leaf-rel .rl + .rl-2 {
  margin-left: 1.2em;
}

/* 配偶的生卒，跟在名字后面小一号 */
.leaf-rel .ts-pat {
  margin-left: .6em;
  font-size: 9.5pt;
  font-style: normal;
  color: var(--ink-4, #AAA294);
  font-variant-numeric: tabular-nums;
}

.ts-sep {
  display: inline-block;
  width: 1.1em;
}

.leaf-note {
  margin: 1.6mm 0 0;
  font-size: 12pt;
  line-height: 1.9;
  color: var(--ink, #191714);
  text-indent: 2em;
  text-align: justify;
  letter-spacing: .01em;
}

/* ==================================================================
   欧式简化版：一代一块
   ================================================================== */
.gen-title {
  display: flex;
  align-items: baseline;
  gap: 0 10pt;
  margin: 7.5mm 0 3.2mm;
  padding-bottom: 2mm;
  font-size: 13pt;
  font-weight: 600;
  letter-spacing: .1em;
  color: var(--ink, #191714);
  border-bottom: .75pt solid var(--accent-line, #D6B0A8);
  break-after: avoid;
  page-break-after: avoid;
}

.gen-title:first-child {
  margin-top: 0;
}

.gen-title .gen-n {
  font-size: 9.5pt;
  font-weight: 400;
  letter-spacing: .04em;
  color: var(--ink-3, #6F6758);
}

.gen-row {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0 9pt;
  padding: 1.4mm 0;
  font-size: 11pt;
  line-height: 1.7;
  border-bottom: .25pt solid var(--line-soft, #F1ECE3);
  break-inside: avoid;
  page-break-inside: avoid;
}

.gen-row .r-name {
  font-size: 12pt;
  font-weight: 600;
  letter-spacing: .05em;
}

.gen-row .r-art,
.gen-row .r-life,
.gen-row .r-fa,
.gen-row .r-sp,
.gen-row .r-kid {
  font-size: 10.5pt;
  color: var(--ink-3, #6F6758);
  letter-spacing: .02em;
}

.gen-row .r-life,
.gen-row .r-kid {
  font-variant-numeric: tabular-nums;
}

.gen-row .r-kid {
  margin-left: auto;
  color: var(--accent, #8A362B);
}

/* ==================================================================
   苏式：世代横行，人名密排成格，由右向左
   一行一个世代，行内从右往左读。不画连线——苏式靠格线和世代行定关系，
   加了连线反而和格线打架，一页 156 个人会变成一张蜘蛛网。
   ================================================================== */
.su-row {
  display: flex;
  align-items: flex-start;
  gap: 3mm;
  padding: 2mm 0;
  border-bottom: .5pt solid var(--line, #E7E1D5);
  break-inside: avoid;
  page-break-inside: avoid;
}

.su-row:first-child {
  padding-top: 0;
}

/* 世代标签固定在左侧，不跟着人名从右往左跑——它是行的坐标，不是内容 */
.su-g {
  flex: 0 0 15mm;
  padding-top: .6mm;
  font-size: 9pt;
  line-height: 1.5;
  letter-spacing: .12em;
  color: var(--accent, #8A362B);
}

.su-cells {
  flex: 1;
  display: flex;
  flex-direction: row-reverse;   /* 由右向左：第一代的人排在最右边 */
  flex-wrap: wrap;               /* 放不下就往下折。
                                    这里不能用 wrap-reverse——它把交叉轴也翻了，
                                    折出来的行跑到上面去，第二行反而成了第一行 */
  align-content: flex-start;
  gap: 1.1mm 1.5mm;
}

.su-p {
  flex: 0 0 auto;
  min-width: 17mm;
  padding: .6mm 1.2mm;
  border: .4pt solid var(--line-soft, #EFEADF);
  border-radius: .8mm;
  text-align: center;
  line-height: 1.28;
}

.su-p .su-nm {
  display: block;
  font-size: 10pt;
  font-weight: 500;
  letter-spacing: .04em;
}

.su-p .su-art,
.su-p .su-sp,
.su-p .su-life {
  display: block;
  font-size: 7pt;
  font-style: normal;
  letter-spacing: .01em;
  color: var(--ink-3, #6F6758);
}

.su-p .su-life {
  font-variant-numeric: tabular-nums;
}

/* ==================================================================
   宝塔式：一张居中的树图
   用 SVG 而不是 HTML + 绝对定位：连线要对齐到毫米，CSS 算不准；
   SVG 缩放时线宽跟着走，打印不会变成一根粗线。
   ================================================================== */
.ta-fig {
  position: relative;
  height: 246.6mm;
}

.ta-svg {
  display: block;
  width: 174mm;
  height: 246.6mm;
}

/* 总图那一页：图在上、说明紧随其后，两块当成一个整体靠上放。
   之前说明绝对定位在页脚上方，图和字隔着一大片空白，看着像两页拼起来的。 */
.ta-fig-cap {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

/* 高度按 viewBox 比例自然撑开，图有多高就占多高，不要留一截空白在下面 */
.ta-fig-cap .ta-svg {
  flex: 0 0 auto;
  height: auto;
}

.ta-fig-cap .ta-cap {
  flex: 0 0 auto;
  margin-top: 5mm;
}

.ta-cap {
  margin: 0;
  padding-top: 3.2mm;
  border-top: .5pt solid var(--line, #E7E1D5);
  font-size: 9.5pt;
  line-height: 1.95;
  letter-spacing: .02em;
  color: var(--ink-3, #6F6758);
}

.ta-cap .cap-art {
  margin-left: .6em;
  font-size: 8.5pt;
}

/* 线先画、节点后画，连线压在框下面，交叉处不会穿出来 */
.ta-edges path {
  fill: none;
  stroke: var(--line-2, #D8D0C0);
  stroke-width: .35;
  stroke-linecap: square;
}

.ta-n rect {
  fill: #FDFBF6;
  stroke: var(--line, #E7E1D5);
  stroke-width: .3;
}

.ta-n text {
  font-family: var(--serif, 'Songti SC', 'Noto Serif SC', 'SimSun', 'STSong', serif);
  fill: var(--ink, #191714);
  letter-spacing: .02em;
}

.ta-n .ta-nm {
  font-weight: 500;
}

.ta-n .ta-life {
  font-size: 2.6px;
  fill: var(--ink-3, #6F6758);
}

/* ==================================================================
   彩插占位页
   ================================================================== */
.pg-plate .pg-body {
  display: flex;
  align-items: center;
  justify-content: center;
}

.plate-box {
  width: 100%;
  padding: 18mm 14mm;
  border: .75pt dashed var(--line, #E7E1D5);
  text-align: center;
}

.plate-t {
  font-size: 26pt;
  font-weight: 600;
  letter-spacing: .5em;
  text-indent: .5em;
  color: var(--ink-4, #AAA294);
  margin-bottom: 8mm;
}

.plate-p {
  font-size: 11pt;
  line-height: 2;
  color: var(--ink-3, #6F6758);
}

.plate-dim {
  margin-top: 4mm;
  font-size: 10pt;
  color: var(--ink-4, #AAA294);
}

/* ==================================================================
   彩插：图版页
   2×2 四张。图用 contain 不用 cover —— 老照片裁边等于裁掉人头，
   宁可左右留白。格内的浅米底是为了让留白看起来是「衬托」不是「没印上」。
   ================================================================== */
.plate-grid {
  width: 100%;
  height: 100%;
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr;
  gap: 8mm 6mm;
}

.plate-item {
  display: flex;
  flex-direction: column;
  min-height: 0;          /* 不加这句 grid 子项会被内容撑破，整页溢出 */
  margin: 0;
}

.plate-img {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #FBF9F4;    /* 极浅米色，留白处不刺眼 */
}

.plate-img img {
  display: block;
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
}

.plate-cap {
  flex: 0 0 auto;
  padding-top: 2.4mm;
  font-size: 9.5pt;
  line-height: 1.5;
  letter-spacing: .02em;
  text-align: center;
  color: var(--ink-3, #6F6758);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* 图没载进来时不要给破图标：换成一块带字的浅灰，印出来也不难看 */
.plate-item.is-bad .plate-img img { display: none; }
.plate-item.is-bad .plate-img::after {
  content: '图片未载入';
  font-size: 9pt;
  color: var(--ink-4, #AAA294);
  letter-spacing: .1em;
}

/* 空位补白，不画框，免得读者以为漏了一张 */
.plate-item.is-blank .plate-img { background: transparent; }

/* ==================================================================
   谱首扉页
   纵向居中，不带页眉页脚、不带页码。谱名 → 堂号/修次/年份 → 规模 → 右下朱印
   不加图片和纹样，印章是纯 CSS 方框
   ================================================================== */
.pg-title-body {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  position: relative;
  text-align: center;
}

/* 视觉重心略高于几何中心，和纸页上方留白取得平衡 */
.title-mid {
  margin-top: -14mm;
}

.title-name {
  font-size: 40pt;
  font-weight: 600;
  line-height: 1.32;
  letter-spacing: .3em;
  text-indent: .3em;
  color: var(--ink, #191714);
}

.title-lines {
  margin-top: 15mm;
}

.title-lines p {
  font-size: 12pt;
  line-height: 2.2;
  letter-spacing: .32em;
  text-indent: .32em;
  color: var(--ink-3, #6F6758);
}

.title-scale {
  display: inline-block;
  margin-top: 13mm;
  padding-top: 6mm;
  border-top: .5pt solid var(--line, #E7E1D5);
  font-size: 10pt;
  letter-spacing: .18em;
  text-indent: .18em;
  color: var(--ink-mute, #8C8476);
}

/* 朱印。竖排两字，阴文（描边 + 朱字），不加底色更省墨 */
.title-seal {
  position: absolute;
  right: 0;
  bottom: 2mm;
  width: 17mm;
  height: 17mm;
  display: flex;
  align-items: center;
  justify-content: center;
  writing-mode: vertical-rl;
  font-size: 10.5pt;
  line-height: 1;
  letter-spacing: .2em;
  text-indent: .2em;
  color: var(--accent, #8A362B);
  border: 1.1pt solid var(--accent, #8A362B);
  border-radius: .8mm;
}

/* ==================================================================
   空谱
   与世系页 .stage-empty 同一套语言：实底印章 → 衬线标题 → 说明 → 主按钮
   改前是描边印章 + 16px 标题，层级和世系页对不上
   ================================================================== */
.print-empty {
  width: 100%;
  max-width: 380px;
  margin: 72px auto;
  padding: 40px 32px 36px;
  background: var(--raised, #fff);
  border: 1px solid var(--line, #E7E1D5);
  border-radius: var(--r-md, 10px);
  text-align: center;
}

.print-empty .pe-seal {
  width: 44px;
  height: 44px;
  margin: 0 auto 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--serif, serif);
  font-size: 22px;
  letter-spacing: 0;
  color: #FBF8F3;
  background: var(--accent, #8A362B);
  border: none;
  border-radius: 8px;
}

.print-empty h3 {
  font-family: var(--serif, serif);
  font-size: 19px;
  font-weight: 500;
  letter-spacing: .06em;
  line-height: 1.5;
  color: var(--ink, #191714);
}

.print-empty p {
  margin: 10px auto 22px;
  max-width: 300px;
  font-size: 12.5px;
  line-height: 1.9;
  color: var(--ink-3, #6F6758);
  text-wrap: balance;
}

.print-empty .btn {
  height: 36px;
  padding: 0 18px;
}

/* ==================================================================
   顶栏
   改前「颍川陈氏  牒记式 · 22 人 · 5 页」挤在同一条基线上，
   看上去就是一个长句子，没有页面身份。这里复用 .topbar 的 60px 高、
   同样的 24px 内边距和同一套按钮，只把 .brand 内部重排成两行：
   第一行 身份 + 谱名，第二行 统计串
   ================================================================== */
.print-topbar .brand {
  display: grid;
  grid-template-columns: auto auto;
  grid-template-rows: auto auto;
  column-gap: 10px;
  row-gap: 1px;
  align-items: baseline;
}

.print-topbar .brand .back-btn {
  grid-row: 1 / span 2;
  align-self: center;
}

.print-topbar #famNamePrint {
  grid-column: 2;
  grid-row: 1;
  font-size: 17px;
  line-height: 1.3;
  letter-spacing: .09em;
}

/* 页面身份。之前用 ::before 注入，文案改不了、不进无障碍树，
   现在是 h1 里的实体 span。 */
.print-topbar .print-kicker {
  display: inline-block;
  margin-right: 9px;
  padding-right: 9px;
  border-right: 1px solid var(--accent-line, #D6B0A8);
  font-family: var(--sans, sans-serif);
  font-size: 11px;
  font-weight: 400;
  letter-spacing: .16em;
  color: var(--accent, #8A362B);
  vertical-align: 3px;
}

.print-topbar .brand .meta {
  grid-column: 2;
  grid-row: 2;
  font-size: 11.5px;
  letter-spacing: .02em;
  color: var(--ink-3, #6F6758);
  font-variant-numeric: tabular-nums;
}

/* ==================================================================
   预览外壳
   ================================================================== */
.print-body {
  flex: 1;
  display: flex;
  min-height: 0;
}

.print-side {
  flex: 0 0 272px;
  width: 272px;
  padding: 20px 20px 36px;
  border-right: 1px solid var(--line, #E7E1D5);
  background: var(--raised, #fff);
  overflow-y: auto;
}

.ps-sec {
  margin-bottom: 24px;
}

.ps-title {
  margin-bottom: 10px;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .14em;
  color: var(--ink-3, #6F6758);
}

/* ---- 体例卡 ----------------------------------------------------
   选中态四重信号：朱砂左栏 + 边框 + 暖白底 + 实心圆点。
   改前只有一层浅粉底，扫一眼分不出选了哪个
   ---------------------------------------------------------------- */
.ps-card {
  display: block;
  position: relative;
  overflow: hidden;
  padding: 12px 12px 12px 32px;
  margin-bottom: 8px;
  border: 1px solid var(--line, #E7E1D5);
  border-radius: var(--r-sm, 7px);
  background: var(--raised, #fff);
  cursor: pointer;
  transition: border-color 200ms var(--ease, ease),
              background 200ms var(--ease, ease);
}

/* 朱砂左栏：选中才出现 */
.ps-card::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 2px;
  background: transparent;
  transition: background 200ms var(--ease, ease);
}

.ps-card:hover {
  border-color: var(--ink-4, #AAA294);
}

.ps-card:has(input:checked) {
  border-color: var(--accent-line, #D6B0A8);
  background: var(--accent-soft, #F7EDEA);
}

.ps-card:has(input:checked)::before {
  background: var(--accent, #8A362B);
}

.ps-card:has(input:focus-visible) {
  outline: 2px solid var(--accent, #8A362B);
  outline-offset: 2px;
}

/* 原生圆点换成自绘：选中后是实心朱砂点 + 白圈 */
.ps-card input {
  position: absolute;
  left: 12px;
  top: 14px;
  width: 14px;
  height: 14px;
  margin: 0;
  appearance: none;
  -webkit-appearance: none;
  border: 1px solid var(--line, #E7E1D5);
  border-radius: 50%;
  background: var(--raised, #fff);
  cursor: pointer;
  transition: border-color 160ms var(--ease, ease),
              background 160ms var(--ease, ease);
}

.ps-card input:checked {
  border-color: var(--accent, #8A362B);
  background: var(--accent, #8A362B);
  box-shadow: inset 0 0 0 3px var(--raised, #fff);
}

.ps-card input:focus-visible {
  outline: 2px solid var(--accent, #8A362B);
  outline-offset: 2px;
}

.ps-card-t {
  display: block;
  font-size: 13.5px;
  font-weight: 500;
  line-height: 1.5;
  color: var(--ink, #191714);
  letter-spacing: .05em;
}

.ps-card-d {
  display: block;
  margin-top: 5px;
  font-size: 12px;
  line-height: 1.7;
  color: var(--ink-3, #6F6758);
  /* 只有两行，用 balance 均分，避免第二行只剩三四个字 */
  text-wrap: balance;
}

/* ---- 页内选项 ------------------------------------------------ */
.ps-check {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 -8px;
  padding: 8px;
  border-radius: 6px;
  font-size: 12.5px;
  line-height: 1.7;
  color: var(--ink-2, #5C564C);
  cursor: pointer;
  transition: background 160ms var(--ease, ease),
              color 160ms var(--ease, ease);
}

.ps-check:hover {
  background: var(--sunken, #F5F1E8);
  color: var(--ink, #191714);
}

/* 原生方框换成自绘：选中后朱砂底 + 白勾 */
.ps-check input {
  flex: 0 0 auto;
  width: 15px;
  height: 15px;
  margin: 0;
  appearance: none;
  -webkit-appearance: none;
  border: 1px solid var(--line, #E7E1D5);
  border-radius: 3px;
  background: var(--raised, #fff) center / 11px 11px no-repeat;
  cursor: pointer;
  transition: border-color 160ms var(--ease, ease),
              background-color 160ms var(--ease, ease);
}

.ps-check:hover input {
  border-color: var(--ink-4, #AAA294);
}

.ps-check input:checked {
  border-color: var(--accent, #8A362B);
  background-color: var(--accent, #8A362B);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2 6.4 4.7 9 10 3.2' fill='none' stroke='%23FBF8F3' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.ps-check input:focus-visible {
  outline: 2px solid var(--accent, #8A362B);
  outline-offset: 2px;
}

/* ---- 当前这本 ------------------------------------------------ */
.ps-stat {
  padding: 12px 14px;
  background: var(--sunken, #F5F1E8);
  border-radius: var(--r-sm, 7px);
}

/* 两列：标签定宽在左，数值右对齐并锁等宽数字 */
.ps-row {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: baseline;
  column-gap: 12px;
  font-size: 12px;
  line-height: 1.95;
}

.ps-row span {
  color: var(--ink-3, #6F6758);
}

.ps-row b {
  font-weight: 500;
  color: var(--ink, #191714);
  letter-spacing: .02em;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.ps-row.ps-warn b {
  color: var(--accent, #8A362B);
}

/* ---- 底部说明 ------------------------------------------------ */
.ps-note {
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--line-soft, #F1ECE3);
  font-size: 11.5px;
  line-height: 1.95;
  color: var(--ink-3, #6F6758);
  text-wrap: pretty;
}

.print-stage {
  flex: 1;
  min-width: 0;
  padding: 26px 24px 64px;
  /* 台面从 --sunken 压深一档到 --line：白纸才浮得出来。
     改前台面 F5F1E8 与纸面 #fff 只差 6%，看不出这是一张纸 */
  background: var(--line, #E7E1D5);
  overflow: auto;
}

.print-paper {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
}

/* ==================================================================
   刷新预览：按钮态 + 纸页过渡
   参数没变时也要有反馈。所以不靠「内容变了」来提示，
   而是每次重排都让纸页重播一次入场，加上按钮底边跑进度。
   JS 只需在重排前后切 .is-busy，完成后挂 1.2 秒 .is-done。
   ================================================================== */
.print-topbar #btnPrintRefresh {
  position: relative;
  overflow: hidden;
}

/* 忙碌：不可点，底边一条 2px 朱砂进度（沿用导航栏阅读进度条的语言） */
.print-topbar #btnPrintRefresh.is-busy {
  color: var(--ink-3, #6F6758);
  border-color: var(--line, #E7E1D5);
  background: var(--raised, #fff);
  cursor: progress;
  pointer-events: none;
  transform: none;
  box-shadow: none;
}

.print-topbar #btnPrintRefresh.is-busy::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  height: 2px;
  width: 38%;
  background: var(--accent, #8A362B);
  border-radius: 0 1px 1px 0;
  animation: refSweep 900ms cubic-bezier(.45, 0, .55, 1) infinite;
}

@keyframes refSweep {
  from { transform: translateX(-105%); }
  to   { transform: translateX(310%); }
}

@keyframes pgIn {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* 完成：朱砂描边闪一下，约 1.2 秒后由 JS 摘掉 */
.print-topbar #btnPrintRefresh.is-done {
  color: var(--accent, #8A362B);
  border-color: var(--accent-line, #D6B0A8);
  background: var(--accent-soft, #F7EDEA);
}

/* ==================================================================
   纸页在屏幕上的呈现（只作用于 screen）
   @media print 里 .pg 仍然是 margin:0 / box-shadow:none，
   这里只加临边阴影、发丝边和入场动画，不改尺寸、不改字、不进打印
   ================================================================== */
@media screen {
  .print-paper {
    transition: opacity 160ms var(--ease, ease);
  }

  /* 重排期间整叠纸压暗，避免旧内容硬切 */
  .print-paper.is-busy {
    opacity: .35;
    pointer-events: none;
  }

  .print-paper > .pg {
    outline: 1px solid var(--line, #E7E1D5);
    box-shadow: 0 1px 2px rgba(25, 23, 20, .07),
                0 18px 46px rgba(25, 23, 20, .16);
    animation: pgIn 260ms var(--ease, ease) both;
  }

  /* 逐页错峰 40ms，第 6 页封顶；再多的页按同一节奏排下去没有意义 */
  .print-paper > .pg:nth-child(2) { animation-delay: 40ms; }
  .print-paper > .pg:nth-child(3) { animation-delay: 80ms; }
  .print-paper > .pg:nth-child(4) { animation-delay: 120ms; }
  .print-paper > .pg:nth-child(5) { animation-delay: 160ms; }
  .print-paper > .pg:nth-child(6) { animation-delay: 200ms; }

  /* 舞台窄于一张 A4 时等比缩小，避免纸页右侧被裁。
     1180 以上不需要缩放（1280 / 1920 走原尺寸） */
  @media (max-width: 1120px) {
    .print-paper { zoom: .85; }
  }

  @media (max-width: 1000px) {
    .print-paper { zoom: .72; }
  }

  @media (max-width: 880px) {
    .print-paper { zoom: .60; }
  }

  @media (max-width: 760px) {
    .print-paper { zoom: .50; }
  }
}

/* ==================================================================
   目录页
   不编入正文页码：data-page 是 0，页脚只印「目录」二字。
   插在扉页之后、正文之前，所以它一占号，正文所有页码都要 +1 —— 不划算。
   ================================================================== */
.pg-toc-body {
  padding-top: 4mm;
}

.toc-title {
  margin: 0 0 16mm;
  font-size: 20pt;
  font-weight: 500;
  letter-spacing: .42em;
  text-indent: .42em;
  text-align: center;
  color: var(--ink, #191714);
}

.toc-list {
  max-width: 118mm;
  margin: 0 auto;
}

/* 三列：条目名 / 引导线 / 页码。引导线用 1fr 的虚线底边，不用一堆点号 */
.toc-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: baseline;
  font-size: 12pt;
  line-height: 2.5;
}

.toc-n {
  color: var(--ink, #191714);
  letter-spacing: .04em;
}

.toc-d {
  margin: 0 5mm;
  border-bottom: 1px dotted var(--ink-4, #AAA294);
  transform: translateY(-3px);
}

.toc-p {
  color: var(--ink-2, #5C564C);
  font-variant-numeric: tabular-nums;
  letter-spacing: .04em;
}

/* ==================================================================
   人名索引
   一条一行、四段对齐。行高要压得比正文紧——一页要塞四十来条，
   按正文的 1.9 倍行高排，一页只装得下二十几条。
   ================================================================== */
.idx-title {
  margin: 0 0 7mm;
  font-size: 16pt;
  font-weight: 500;
  letter-spacing: .4em;
  text-indent: .4em;
  text-align: center;
  color: var(--ink, #191714);
}

/* 索引不必铺满版心：名字一栏撑到 120mm，世次和房系会被推到页面另一头，
   眼睛要在两点之间来回找。收窄到 122mm 居中，四段就成了一簇。 */
.idx-list {
  max-width: 122mm;
  margin: 0 auto;
}

.idx-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 5.6em 5.2em 2.4em;
  column-gap: 8px;
  align-items: baseline;
  font-size: 10.5pt;
  line-height: 1.58;
}

.idx-row .ix-name {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  letter-spacing: .04em;
  color: var(--ink, #191714);
}

.idx-row .ix-gen,
.idx-row .ix-br {
  color: var(--ink-3, #6F6758);
  letter-spacing: .02em;
}

.idx-row .ix-br {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.idx-row .ix-pg {
  text-align: right;
  color: var(--ink-2, #5C564C);
  font-variant-numeric: tabular-nums;
}

/* ==================================================================
   测量用的离屏页
   必须和 .pg 完全同宽同字，否则量出来的高度没有意义
   ================================================================== */
.pg-measure {
  position: absolute !important;
  left: -20000px !important;
  top: 0 !important;
  height: auto !important;
  margin: 0 !important;
  box-shadow: none !important;
  visibility: hidden;
  pointer-events: none;
  z-index: -1;
}

.pg-body-measure {
  height: auto !important;
  overflow: visible !important;
}

/* ==================================================================
   打印
   ================================================================== */
@media print {
  html,
  body {
    background: #fff !important;
    margin: 0 !important;
    padding: 0 !important;
    height: auto !important;
    overflow: visible !important;
  }

  body > *:not(#viewPrint) {
    display: none !important;
  }

  #viewPrint[hidden] {
    display: none !important;
  }

  #viewPrint:not([hidden]) {
    display: block !important;
    height: auto !important;
    overflow: visible !important;
  }

  .print-topbar,
  .print-side,
  .pg-measure {
    display: none !important;
  }

  /* 空谱时别印白纸：把提示卡留在纸上 */
  .print-empty {
    margin: 40mm auto 0 !important;
    box-shadow: none !important;
    break-inside: avoid;
  }

  .print-body {
    display: block !important;
    height: auto !important;
    min-height: 0 !important;
  }

  .print-stage {
    display: block !important;
    padding: 0 !important;
    margin: 0 !important;
    background: #fff !important;
    overflow: visible !important;
  }

  .print-paper {
    display: block !important;
    gap: 0 !important;
  }

  .pg {
    margin: 0 !important;
    box-shadow: none !important;
    break-after: page;
    page-break-after: always;
    break-inside: avoid;
  }

  .pg:last-child {
    break-after: auto;
    page-break-after: auto;
  }

  .leaf,
  .gen-row {
    break-inside: avoid;
    page-break-inside: avoid;
  }

  .gen-title {
    break-after: avoid;
    page-break-after: avoid;
  }
}

/* ==================================================================
   卷首文字页（谱序 / 凡例 / 后记）
   ------------------------------------------------------------------
   .essay-* 一律写成 `.pg .essay-*`，不能嵌进 .pg-essay：
   分页是「先量后切」，测量容器是 .pg.pg-measure > .pg-body.pg-body-measure，
   它没有 .pg-essay 这个父类。写成 .pg-essay .essay-p 的话，
   真页上有样式、测量容器里没有，量出来的高度偏小，页页溢出。
   ================================================================== */

/* 序文比正文松一点，像书，不像表格 */
.pg-essay-body {
  font-size: 12pt;
  line-height: 2.1;
}

/* letter-spacing 会把最后一个字往右推半个字距，标题看着就不在正中。
   配一个同值 text-indent 抵掉——这不是可选项。 */
.pg .essay-title {
  margin: 0 0 10mm;
  font-size: 17pt;
  font-weight: 500;
  letter-spacing: .3em;
  text-indent: .3em;
  text-align: center;
  color: var(--ink, #191714);
}

.pg .essay-p {
  margin: 0 0 4mm;
  text-indent: 2em;
  text-align: justify;
}

/* 署名与落款只上最后一页 */
.pg .essay-sign {
  margin-top: 12mm;
  text-align: right;
  line-height: 2;
}

.pg .essay-sign .essay-by {
  display: block;
  font-size: 11.5pt;
  letter-spacing: .05em;
}

.pg .essay-sign .essay-date {
  display: block;
  font-size: 10pt;
  color: var(--ink-3, #6F6758);
}

/* 一段长到整页都放不下、被按字切开时，在断口那一页标一句 */
.pg .essay-cont {
  margin-top: 2mm;
  text-align: right;
  font-size: 9pt;
  color: var(--ink-mute, #8C8476);
  letter-spacing: .04em;
}

/* ---------- 排版页侧栏：卷首入口 ---------- */
.ps-wide {
  width: 100%;
  height: 34px;
  font-size: 12.5px;
}

.ps-hint {
  margin-top: 7px;
  font-size: 11.5px;
  color: var(--ink-3, #6F6758);
  line-height: 1.6;
}

/* 不是族长的，整块不渲染。hidden 必须能压过任何 display 规则 */
.ps-sec[hidden] {
  display: none !important;
}
