/* ============================================================
   VANSHI · 编辑式商办门户  ed.css
   一套版式，三件事：字够大、格够准、留白够狠。
   - 纸 / 墨 / 一个品牌红
   - 不用投影堆层次，用粗细、字号、留白和 1px 线
   - 圆角 2px（只在按钮与卡片出现）
   ============================================================ */

/* 令牌（颜色 / 字体 / 容器宽度 / 字号阶梯）已抽到 assets/tokens.css，
   由每个页面在 ed.css 之前引入。这里不再重复定义 —— 两处写同一张表必然分叉。 */

*{ box-sizing:border-box; }
/* scrollbar-gutter：Windows 经典滚动条会吃掉 15px，过滤结果变少/变多时整页会横跳；
   Mac 是覆盖式滚动条，这行等于没写。 */
html{ -webkit-text-size-adjust:100%; scroll-behavior:smooth; scrollbar-gutter:stable; }
body{
  margin:0; background:var(--paper); color:var(--ink);
  font-family:var(--sans); font-size:var(--fs-base); line-height:1.75;
  /* 中文没有词间空格，浏览器只能按字硬断，长公司名/地址的末行经常只剩一个字。
     pretty 在整段里重新分配断点，把孤字消掉（Chrome 117+ 生效，旧浏览器无副作用）。 */
  text-wrap:pretty;
  text-rendering:optimizeLegibility;
}
/* 只在展示级大字上做“细”渲染：macOS 上 antialiased 会让 11–13px 的中文发虚，
   Windows 不吃这个属性，所以小字交回系统默认。 */
.hero h1,.hero .sub,.sec-h h2,.est-intro h2,.est-out b,.db-lead{
  -webkit-font-smoothing:antialiased;
}
img{ display:block; max-width:100%; height:auto; }
/* <picture> 只为格式协商存在（有 webp 走 webp，没有走 <img src> 的 JPEG），
   它不该在版面上占任何位置。display:contents 让这个盒子从布局里彻底消失，
   里面的 <img> 等于直接挂在原来的父元素下面 —— 所有针对 img 的规则、
   网格轨道、比例计算都跟没有 <picture> 时一模一样。
   不这么写的话，<picture> 是 display:inline 的，img 的百分比宽度会以它为准，
   图集在窄屏上会缩成一条。 */
picture{ display:contents; }
/* height:auto 不是装饰：<img width height> 的 height 会作为「表现性提示」变成真实高度，
   把 CSS 的 aspect-ratio 与 object-fit 全压住 —— 详情页图集因此从 3:2 变成 0.5 的竖条。 */
/* 顶栏吸顶 77px，任何 id 锚点滚过来都会正好停在 top:0，被导航压住一整个头。
   首页三条「问顾问」指向 #brief，滚到位时表单第一行就在导航底下。
   给所有带 id 的元素统一留 --anchor（头高 76 + 13）—— 以后新加的锚点自动生效，
   不用记着逐个补。 */
:target,[id]{ scroll-margin-top:var(--anchor); }
a{ color:inherit; text-decoration:none; }
button{ font:inherit; color:inherit; background:none; border:0; cursor:pointer; }
ul,ol{ margin:0; padding:0; list-style:none; }
h1,h2,h3,h4,p,figure{ margin:0; }
[hidden]{ display:none; }
::selection{ background:var(--ink); color:var(--white); }
/* 只给读屏看的标题：视觉上不占位，但让「h1 之后直接 h3」的章节有归属 */
.sr{ position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0; }
/* 跳到正文：默认移出视口上方，第一个 Tab 聚焦时落回左上角。
   不用 .sr 那套 clip —— 聚焦时也看不见，键盘用户不知道跳到了哪；
   也不用 left:-9999px —— 那个负偏移会被横向溢出闸门判成「元素跑出视口左侧」，
   而且在部分浏览器里 fixed 元素仍然会撑出横向滚动条。translateY 只动视觉层。
   ⚠ 2026-10-23：z-index 必须比 .hd 高一级。
   原来两边都是 var(--z-header)=60，而 .skip 在 DOM 里排在 .hd 前面 ——
   同 z-index 时后者压前者，于是「聚焦后落回 top:12」的那个位置正好是页头，
   卡片被页头的白底整个盖住了：键盘用户按第一个 Tab，屏幕上什么都没变。
   这不是理论问题，新装的 check_focus.mjs 把 28 个页面的同一个元素全判红了。 */
.skip{ position:fixed; top:12px; left:12px; z-index:calc(var(--z-header) + 1);
  display:inline-flex; align-items:center; min-height:44px; padding:0 20px;
  background:var(--ink); color:var(--paper); font-size:var(--fs-bs);
  transform:translateY(calc(-100% - 24px)); transition:transform .18s cubic-bezier(.4,0,.2,1); }
.skip:focus{ transform:none; outline:2px solid var(--brand); outline-offset:2px; }

.wrap{ width:100%; max-width:var(--w); margin:0 auto; padding:0 32px; }

/* 数字与英文：等宽数字，字距略松 */
.n{ font-variant-numeric:tabular-nums; }
/* 英文小标签（"Map" "By area" "Received"）：保留英文，但**不全大写、不拉大字距**。
   全大写 + .16em 字距是「AI 生成感」最典型的一条 —— 老板明确禁过，
   而这里原文案本来就是小写词，改成大写只是为了「看起来设计过」，没必要。
   注：页脚的 VANSHI 字标（.logo .wm / .ft-brand .wm）属于品牌锁定字标，
   保留大写，那是标识的一部分，不是眉标。 */
.lat{ font-family:var(--en); letter-spacing:.02em; font-size:var(--fs-sm); color:var(--ink3); }

/* ---------------- 主导航 ----------------
   原来顶栏上方还有一条 36px 的细条（「只服务企业客户 佣金由业主支付 / 营业时间 /
   电话」）。这三样在首屏、费用一节、页脚里各有一遍 —— 同一屏把同一句话说三四次，
   而且细条只有 12px 字、右侧两段等宽数字挤在一起，看着像后台系统的一条状态栏。
   整条删掉，页面从 logo 直接开始。 */

/* ---------------- 主导航 ---------------- */
.hd{
  /* 原来是 rgba(250,250,249,.96)：粘顶滚过首屏时，底下的「400 000000」
     和那句副标题会以 4% 的灰穿上来，压在导航与按钮之间，看着像页面串行。
     实面是这套设计语言的前提（全站已无毛玻璃），这里必须是纯色。 */
  position:sticky; top:0; z-index: var(--z-header); background:var(--paper);
  border-bottom:1px solid var(--line); backdrop-filter:none;
}
.hd .wrap{ height:76px; display:flex; align-items:center; gap:28px; }
.logo{ display:flex; align-items:center; gap:12px; flex:0 0 auto; min-height:44px; }

/* 手机菜单开关：detail/summary 要 JS，select 要 JS，这里用 checkbox —— 
   纯 HTML/CSS 就能开合，静态页不用挂脚本，键盘也能用。
   ⚠ 原来写的是 width:0;height:0;opacity:0 且带 tabindex="-1"：手机上键盘用户
   连一个能打开导航的控件都摸不到（Tab 直接跳过整个顶栏区）。
   现在改成「1px + clip」的视觉隐藏：仍然进 Tab 序列、仍然能被 Space 切换，
   焦点环画在可见的 44×44 汉堡上（见下方 :focus-visible 规则）。
   桌面（≥981）没有汉堡，display:none 把它从 Tab 序列里摘掉，不留隐形停靠点。 */
.mnav-ck{ position:absolute; width:1px; height:1px; margin:-1px; padding:0; border:0;
  opacity:0; overflow:hidden; clip-path:inset(50%); white-space:nowrap; pointer-events:none; }
.mnav-ck:focus-visible + .mnav-bt{ outline:2px solid var(--brand); outline-offset:3px; }
.mnav-bt{ display:none; }
.mnav-mask{ display:none; }
@media (min-width:981px){ .mnav-ck{ display:none; } }
.logo img{ height:32px; width:auto; }
.logo .wm{ font-size:var(--fs-md); font-weight:700; letter-spacing:.2em; text-transform:uppercase; }
/* 2026-10-27：导航从 11 项收到 9 项后，整排短了约 100px。
   那 100px 不拿回去加项，用来把每一项撑开 —— 9 项 × 4px 两侧 = 72，
   再把左边距从 8 加到 24，整排回到原来的长度，但每一项之间更透气。
   （原来 8px 是因为 11 项刚好填满，紧了才塞得下；项少了还紧着就只是挤。） */
.nav{ display:flex; align-items:center; gap:0; margin-left:8px; }
/* 城市位收在导航末尾（「联系」之后）。原来夹在 logo 与导航之间：
   一是把「品牌 → 这家公司做哪几件事」这条视线切成两段；
   二是一个带下拉箭头的控件摆在 logo 右侧，第一眼会被读成语言切换器，
   但它只是「只做上海」的陈述。现在它作为导航最后一项，用发丝线与「联系」分开。
   2026-10-20：箭头撤掉。注释早就写着「会被读成切换器」，却把箭头留着 ——
   一个没有任何点击行为的▼，是明摆着的假控件。只做上海，就写成一句陈述。 */
/* ⚠ 2026-11-02 老板：「首页和每一页联系后面的上海变成横着写的」。
   竖排那版是把「上海」做成一枚印章式的印记，理由是「横排会跟导航项长得一样」。
   老板不认这个理由 —— 他的原话是「变成横着写的」，那就横排，理由再充分也服从。
   改横排要付的代价只有一条：宽度。竖排 32.4px、横排约 55px，多 22px。
   实测（_dev/_hd_probe.mjs）导航右端到「联系顾问」尚有 68.3px 余量（1360 最紧、
   1280 有 108.3），22px 进去还剩 46px，不会把右侧电话挤成两行 —— 这一条是量过的，
   不是估的。竖排原本省下的 19px 也一并还回去了。

   保留两样东西，因为它们承担的是「这不是菜单项」的信号，不是排向本身：
     · 左侧那根发丝线 —— 与「联系」隔开，仍是一句陈述而不是第 12 个入口；
     · 上方那道朱文短线 —— 印章语义靠颜色和衬线承担，横排照样成立。
   字距从 .3em（竖排时字间呼吸）收回 .06em：横排下 .3em 会变成 4.2px 空洞。 */
.city{ display:block; position:relative; white-space:nowrap;
  margin:0 0 0 8px; padding:10px 0 0 16px;
  border-left:1px solid var(--line);
  /* ⚠ 写 500 不是笔误：Noto Serif SC 只发布了 300 / 500 两档，
     写 400 会被就近匹配成 500 —— 声明与实际渲染不符，字号阶梯检查会判红。
     全站的衬线标题本来就都是 500，这里跟随同一档。 */
  font-family:var(--serif); font-weight:500; font-size:14px; letter-spacing:.06em; line-height:1.1;
  color:var(--ink2); }
/* 印首一道朱文：14×2 的品牌红短线压在两个字上方。
   没有它，两字在横排导航里容易被读成「这里排版断了」；
   有了它，读者认出这是一枚印章式的标记，而不是坏掉的菜单项。
   红只占 28px² —— 全站最小的品牌红面积，恰好够"点睛"，不够"抢注意力"。
   横排后 left 从 18 收到 17：padding-left 16 + border 1，让线左端与「上」字左缘齐；
   top 从 0 抬到 2：padding-top 10 之后字顶在 10px，线压 2px 处留 8px 呼吸。 */
.city::before{
  content:""; position:absolute; left:17px; top:2px;
  width:14px; height:2px; background:var(--brand);
}
/* ⚠ 2026-10-26 DEEP-1026：加 min-height:44px。
   实测页头导航 60×41 —— 差 3px 到 Apple HIG 的「Create controls that measure
   at least 44 points x 44 points」。41px 在鼠标下能用，但在 13" 触屏笔电和
   手机横屏上是真的会点偏。
   **只抬导航，不抬页脚**：页脚链接 52×32 保持原样 —— 页脚是密集信息区，
   每条都撑到 44 会让整块长 96px；而 WCAG AA 对指针输入只要求 24×24（已满足），
   44 是触摸屏 App 的建议值，桌面页脚不该为它付出版面代价。
   ⚠ 不用 padding 抬：padding 从 8 → 11 会把 ::after 下划线一起推下去；
     min-height + inline-flex 居中只动盒子高度，下划线仍在盒子底边。 */
.nav a{ font-size:var(--fs-md); color:var(--ink2); padding:8px 16px; position:relative; transition:color .25s var(--ease);
  display:inline-flex; align-items:center; min-height:44px;
  /* ── 不许换行（2026-10-27 补）────────────────────────────────
     11 项在 16px 内边距下整排 821px，可用 793–846px —— 本来就只剩
     25px 余量。我那一轮把内边距加到 20px、左距加到 24px（多 104px），
     浏览器**没有报错也没有溢出**，而是把每个字拆成两行（首/页、找/楼、
     开放/数据）挤进去，整排看着还挺"整齐"。
     而当时的判据是「每条链接顶边是否齐平」→ 换行后顶边依然齐平，
     判据全绿。这条 nowrap 让同类挤压以后变成肉眼可见的溢出，不再静默变形。 */
  white-space:nowrap; }
.nav a:hover{ color:var(--ink); }
.nav a.on{ color:var(--ink); }
.nav a.on::after{ content:""; position:absolute; left:14px; right:14px; bottom:0; height:1px; background:var(--ink); }
/* ── 1261–1359：导航挤不进一行（2026-10-25 实测）
   导航在 1260 以下收进汉堡菜单，1261 起展开。但 1270/1280/1300/1320/1340
   五个宽度实测**全部折成两行**（nav 高 65 而不是 41），1360 才恢复。
   1280 是笔记本最常见宽度，这里折行最刺眼。
   原因：整排 821px，可用 793–846px，差一点。
   把横向内边距 16 收到 10，整排收成 698px，最窄的 1270 也有 95px 余量；
   下划线的左右内缩同步从 14 改成 8，否则线会顶到相邻文字。
   2026-10-27：项数从 11 收到 9，整排余量多出约 100px，这一档
   从 10 放到 14（比默认 20 略紧，为 1270 留底），下划线内缩 12。
   2026-10-27 晚：**11 项已恢复**（首页 / 联系回到导航），9 项时的
   「余量多出 100px」不再成立 —— 这一档回到最初的 padding 10 / 内缩 8，
   否则 1270 那一段又会静默换行。 */
@media (max-width:1359px){
  .nav a{ padding:8px 10px; }
  .nav a.on::after{ left:8px; right:8px; }
  .nav{ margin-left:8px; }
}
/* ── 开放数据 · AI（2026-10-27 改外观，位置与目标不动）──────────────
   2026-10-22 老板要「整个 api 独立做个按钮，这样看起来我们网站有 ai」，
   当时做成黑框 + 黑底白字角标。意图（让人看见 AI）不变，但那个做法放进
   一排 14px 灰字里是一块**补丁**：黑框把一行文字的节奏打断，视线会在中途
   被拽住一次才继续往右 —— 而导航本来就该被一眼扫完。
   现在它回到这排字里，只把「AI」两个字母染成品牌红。
   红字比黑框更跳（品牌红在纸底 6.8:1，是全站唯一的高饱和色），
   整排又回到同一个节奏。位置、顺序、链接、无障碍名全不变。
   ⚠ 不做实心的理由仍然成立：右侧「联系顾问」是唯一的实心，
     一屏两个实心等于没有主次。 */
.nav a.nav-ai{
  display:inline-flex; align-items:center; gap:4px;
  margin:0; padding:8px 16px;
  border:0; border-radius:0;
  font-size:var(--fs-md); color:var(--ink2);
}
.nav a.nav-ai em{
  font-style:normal; font-family:var(--en); font-size:var(--fs-sm); line-height:1;
  padding:0; background:none; color:var(--brand); letter-spacing:.06em; font-weight:700;
}
/* 这一项原来永远不出下划线（它是个按钮，按钮用底色表示激活）。
   现在是普通链接了，激活时必须有下划线 —— 否则 /api/ 页整排没有当前项。 */
.nav a.nav-ai::after{ content:none; }
.nav a.nav-ai.on::after{ content:""; }
.nav a.nav-ai:hover{ color:var(--ink); }
.hd-r{ margin-left:auto; display:flex; align-items:center; gap:24px; }
/* 页头电话（2026-10-20 恢复）。导火索是 NN/g 的眼动结论：用户找联系方式
   只往三个地方看 —— 顶栏右上、主导航、页脚。原来只有页脚一个入口，
   而 B2B 服务型网站的电话本来就是最短的转化路径（不用填表、不用等回信）。
   桌面常驻、980 以下收起：那档开始出汉堡，顶栏塞不下「号码 + 按钮 + 汉堡」三项。 */
.hd-tel{
  display:inline-flex; align-items:center; gap:8px;
  /* 25px 高的电话链接：鼠标能点，手指点不准 —— 顶栏整条 60px，
     给它 40px 的可点高度（上下各留 7px 内边距），不影响其他元素的位置。 */
  min-height:40px; padding:0 4px;
  font-size:var(--fs-md); color:var(--ink); letter-spacing:.03em;
  font-variant-numeric:tabular-nums;
  transition:color .25s var(--ease);
}
.hd-tel svg{ flex:0 0 auto; color:var(--ink2); transition:color .25s var(--ease); }
.hd-tel:hover{ color:var(--brand); }
.hd-tel:hover svg{ color:var(--brand); }
.hd-tel:focus-visible{ outline:2px solid var(--ink); outline-offset:4px; }
@media (max-width:980px){ .hd-tel{ display:none; } }

.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:8px;
  /* ⚠ 2026-10-26 DEEP-1026：height 40 → 44。
     实测主 CTA「联系顾问」98×40、电话链接 131×40，都差 4px 到 Apple HIG 的 44。
     这是全站唯一的转化按钮，点不中直接丢线索，4px 的代价值得付。
     （WCAG 2.5.8 AA 只要 24×24，已满足；44 是 Apple HIG / WCAG 2.5.5 AAA 的量级。） */
  height:44px; padding:0 20px; font-size:var(--fs-md); letter-spacing:.04em;
  /* 按钮文字禁止折行。上面加了 overflow:hidden（为了让 ::after 光扫被裁在圆角内），
     一旦文字折行会被**静默裁掉半行** —— 比溢出更糟，因为不报错也看不全。
     实测「联系顾问」在 98px 宽里内容只有 56px，余量不到 2px，属于随时会翻的那种。 */
  white-space:nowrap;
  background:var(--ink); color:var(--white); border-radius:var(--r-btn);
  /* 2026-10-27：圆角从 --r-1 改成 --r-btn。
     实测量出同一颗「联系顾问」按钮：首页 2px、内页 3px —— 因为首页只引
     tokens + ed 两层，吃不到 premium.css 的 .btn 覆盖。同一个按钮在全站
     出现两种倒角，是那种「说不上哪里不对但就是不齐」的典型。
     顺手把 --el-1 贴地影也补到这里：premium 的悬停会 -1px 抬起，若首页
     没有基础影，抬起的一瞬间按钮底下是空的，看着像在抖而不是在浮。
     ⚠ 这两条 premium.css 里也有同值规则，重复但不冲突；留在 ed.css 是为了
       让「不引 premium 的页面」（手写首页）也拿到同一套手感。 */
  box-shadow:var(--el-1);
  transition:background .25s var(--ease), color .25s var(--ease), border-color .25s var(--ease),
             box-shadow .28s var(--ease-soft), transform .28s var(--ease-expo);
}
.btn:hover{ background:var(--ink-press); transform:translateY(-1px); box-shadow:var(--el-2); }
.btn.ghost{ background:transparent; color:var(--ink); border:1px solid var(--ink4); }
.btn.ghost:hover{ border-color:var(--ink); background:transparent; }
.btn.line{ background:transparent; color:var(--white); border:1px solid rgba(var(--white-rgb), .5); }
.btn.line:hover{ background:var(--white); color:var(--ink); border-color:var(--white); }
/* 主按钮（实心）给一道顶边高光：一块纯色矩形和一个「有倒角的实体」的差别
   就在这 1px —— 它让按钮看起来是被光照到的，而不是被油漆刷上去的。
   与 premium.css 同值，写在 ed.css 是为了让手写首页也拿到。 */
.btn:not(.ghost):not(.line){
  box-shadow:var(--el-1), inset 0 1px 0 rgba(var(--white-rgb),.14);
}
/* 按下回弹。必须写在 :hover 之后，否则悬停时点下去仍显示悬停态。 */
.btn:active{ transform:translateY(1px); box-shadow:var(--el-1); }
/* 悬停时一道 28% 宽的高光从左掠到右。
   用 ::after 而不是换背景图：背景图会和实心底色打架，在 ghost 上还会把
   底下的纸色带出来。::after 只叠一条半透明，三种按钮都能用。 */
.btn{ position:relative; overflow:hidden; isolation:isolate; }
.btn::after{
  content:""; position:absolute; inset:-1px; z-index:2; pointer-events:none;
  background:linear-gradient(100deg,
    rgba(var(--white-rgb),0) 28%, rgba(var(--white-rgb),.20) 46%, rgba(var(--white-rgb),0) 64%);
  transform:translateX(-130%);
  transition:transform .52s var(--ease-expo);
}
.btn:hover::after{ transform:translateX(130%); }
/* 白底/描边按钮上白光看不见，改用极淡墨光 —— 否则「有的按钮有动效、有的没有」。 */
.btn.ghost::after,
.btn.line::after{
  background:linear-gradient(100deg,
    rgba(var(--ink-rgb),0) 28%, rgba(var(--ink-rgb),.05) 46%, rgba(var(--ink-rgb),0) 64%);
}

/* ============================================================
   首屏：一张图压满宽度，一块纸压在图的下沿
   ============================================================ */
.hero{
  position:relative; background:var(--paper); border-bottom:1px solid var(--line);
  /* 左内边距用 100%（父级宽度）算，不用 100vw：
     100vw 在 Windows 上把 15px 经典滚动条也算进去，首屏文字会比下面各段偏右 7.5px。 */
  padding-left:max(32px, calc((100% - var(--w)) / 2 + 32px));
}
.hero-grid{ display:grid; grid-template-columns:minmax(0,1fr) 54%; min-height:clamp(520px,66vh,calc(650px*var(--k))); }
.hero-left{
  display:flex; flex-direction:column; justify-content:center;
  padding:56px 44px 32px 0;
}
/* 右栏现在只有一张图，就让它把整栏填满。
   原来是「16:9 的图 + 下面三行事实」的竖排：图按自己比例完整出现，
   下方的空白由三行内容接住。三行撤掉以后如果图还按 16:9 出，右栏底部会空出一片
   死白（1440 宽下约 190px），首屏右边像少了块东西。所以改成图撑满右栏高度，
   object-fit:cover 裁两侧 —— 这是同一张照片的取景裁切，不是拉伸变形。 */
/* overflow:hidden 是 heroDrift 的配套：图片放大 4.5% 后会顶出右栏，
   不裁就会压到旁边的首屏文字上。 */
.hero-right{ display:flex; flex-direction:column; background:var(--paper2); overflow:hidden; }
.hero-fig{ margin:0; position:relative; background:var(--paper4); flex:1 1 auto; min-height:0; }
/* 2026-10-27：换成楼栋实拍之后，滤色器重调一次。
   原来这组是给「黄昏天际线」配的（降饱和 + 微提对比，让紫红的天压回中性）；
   实拍外景本身色彩就淡，再降饱和就发灰成「证件照」。
   现在改为「略提饱和 + 提对比」：玻璃幕墙的青灰与天空拉开，
   树与街道不至于糊成一片。数值都很小 —— 这是校正，不是调色。 */
.hero-right img{
  display:block; width:100%; height:100%; object-fit:cover; object-position:50% 46%;
  filter:saturate(1.06) contrast(1.07);
}
/* 首屏照片的「活气」—— 第三版（2026-10-27）
   第一版是 Ken Burns：img 上 transform:scale(1→1.045)，30 秒一周期。
   **删掉的原因不是审美，是它必然违反横向溢出尺子**：
   照片右缘与视口同边，任何 >1 的缩放都会把 img 的盒子顶出视口；
   .hero-right 的 overflow:hidden 裁得掉画面，裁不掉盒子的 rect。
   实测「动画走到终点」那一帧，13 档宽度里 8 档溢出：
     2560 +27px / 1920 +21 / 1680 +19 / 1600 +18 / 980 -22（左侧）/ 768 -17 / 560 -12 / 390 -8
   而 qa2 是在页面加载 350ms 后采样，只读到 0.6% 的进度，恰好全绿 ——
   时红时绿的判据比一直红更糟，它会把下一次真红也一起瞒过去。
   现在把「动」交给伪元素的 transform：伪元素没有 rect，又被 .hero-right
   真实裁切，位移不进溢出统计。光带 26 秒扫过一道，峰值透明度 6%，
   只在玻璃幕墙上掠过，读者感到的是「图在呼吸」而不是「有东西在动」。 */
.hero-fig::after{
  content:""; position:absolute; top:0; bottom:0; left:-60%; width:60%;
  pointer-events:none; z-index:0;
  background:linear-gradient(100deg,
    rgba(255,255,255,0) 0%, rgba(255,255,255,.06) 50%, rgba(255,255,255,0) 100%);
  animation:heroSheen 26s linear infinite;
}
@keyframes heroSheen{
  0%   { transform:translateX(0); }
  100% { transform:translateX(280%); }
}
/* 系统开了「减少动态」就完全静止 —— 前庭功能敏感的人对缓慢推镜也会晕。 */
@media (prefers-reduced-motion:reduce){
  .hero-fig::after{ animation:none; opacity:0; }
}

.eyebrow{
  display:flex; align-items:center; gap:8px;
  font-size:var(--fs-sm); letter-spacing:.04em; color:var(--ink3);
}
.eyebrow::before{ content:""; width:22px; height:1px; background:var(--ink3); }

.hero h1{
  /* 宋体只有 300 与 500 两档真字体。写 400 浏览器会就近取 500（实测两者
     逐像素完全相同），于是「400 的大标题」和「500 的小标题」看着一样重，
     靠字重做层级这条路就断了。展示级大标题走 300，轻而有骨，才是编辑式的贵。 */
  font-family:var(--serif); font-weight:300;
  font-size:calc(var(--fs-display)*var(--k)); line-height:var(--lh-h1); letter-spacing:.01em;
  margin-top:16px; text-wrap:balance;
}
.hero h1 em{ font-style:normal; color:var(--brand); }
.hero .sub{
  font-family:var(--serif); font-weight:300; font-size:calc(var(--fs-num)*var(--k));
  line-height:1.75; color:var(--ink2); margin-top:16px; letter-spacing:.02em;
}

/* 搜索：输入 + 找房；下面四组「按 X 找楼」收在同一张纸里 */
.sform{ margin-top:32px; max-width:760px; }
.sform-r1{
  display:flex; align-items:stretch; height:62px;
  border:1px solid var(--ink); background:var(--white);
}
.sform-r1 .ic{ display:flex; align-items:center; padding-left:20px; color:var(--ink3); flex:0 0 auto; }
.sform-r1 input{
  flex:1 1 auto; min-width:0; border:0; outline:none; background:transparent;
  font:inherit; font-size:var(--fs-base); padding:0 16px; color:var(--ink);
}
.sform-r1 input::placeholder{ color:var(--ink3); font-size:var(--fs-md); }
/* 首屏唯一的实色块用品牌红：整页黑白灰，只有这一小块是红的，
   视线自然被带到"找房"上 —— 红是点睛，不是主题色。 */
.sb-go{
  flex:0 0 auto; width:104px; padding:0 8px; background:var(--brand); color:var(--white);
  font-size:var(--fs-md); letter-spacing:.06em; transition:background .25s var(--ease);
}
.sb-go:hover{ background:var(--brand-d); }
.sb-go:focus-visible{ outline:2px solid var(--ink); outline-offset:3px; }

/* 联想：输入框下浮一层，直接给结果，不跳页 */
.sug{
  position:absolute; left:46px; right:46px; top:100%;
  background:var(--white); border:1px solid var(--ink); border-top:0;
  z-index: var(--z-pop); display:none; max-height:330px; overflow:auto;
}
.sug.on{ display:block; }
.sug a{ display:grid; grid-template-columns:1fr auto; gap:12px; align-items:baseline; padding:12px 16px; border-bottom:1px solid var(--line2); }
.sug a:last-child{ border-bottom:0; }
.sug a:hover{ background:var(--paper); }
.sug .sn{ font-size:var(--fs-md); }
.sug .sm{ font-size:var(--fs-sm); color:var(--ink3); margin-top:2px; }
.sug .sa{ font-size:var(--fs-sm); color:var(--ink2); font-variant-numeric:tabular-nums; white-space:nowrap; }
.sug .empty{ padding:16px 16px; font-size:var(--fs-bs); color:var(--ink3); }

/* 四个「按 X」小组：同一张纸里，点一下等于选好并提交 */
.sb-tabs{ display:flex; align-items:center; gap:24px; margin-top:16px; border-bottom:1px solid var(--line); }
.sb-tabs button{
  /* 之前只有 31px 高（13px 字 + 8px padding）—— 鼠标勉强，手指点不准。
     抬到 34 且用 flex 垂直居中，下划线仍然贴在 .sb-tabs 的 border 上。 */
  display:inline-flex; align-items:center; min-height:34px;
  font-size:var(--fs-bs); color:var(--ink3); padding:0 0 4px; position:relative;
  transition:color .2s var(--ease);
}
.sb-tabs button.on{ color:var(--ink); }
.sb-tabs button.on::after{ content:""; position:absolute; left:0; right:0; bottom:-1px; height:1px; background:var(--ink); }
.sb-tabs .all{ margin-left:auto; display:inline-flex; align-items:center; min-height:34px; font-size:var(--fs-sm); color:var(--ink3); padding-bottom:4px; }
.sb-panel{ display:none; flex-wrap:wrap; gap:2px 0; padding-top:12px; }
.sb-panel.on{ display:flex; }
/* 14 个区域链路排成一行，每个只有 26px 高。整行抬到 32，
   手指点「浦东」不会点到「静安」—— 竖着加 6px，横着的间距不变。 */
.sb-panel a{ display:inline-flex; align-items:center; min-height:32px; font-size:var(--fs-bs); color:var(--ink2); padding:0; }
.sb-panel a:hover{ color:var(--brand); }
/* 分隔点挂在上一项的后面，不挂在下一项的前面：挂在前面时，
   一行装不下换行，点会跑到新行开头，看着像一个孤立的小圆点。 */
.sb-panel a:not(:last-child)::after{ content:"·"; color:var(--ink4); margin:0 8px; }
/* 首屏「按标准层」面板七项（2026-10-27 面积分档 4→7）：
   flex 在 582px 宽里折成 6+1 —— 第二行只剩「3,000㎡ 以上」孤零零一项，
   第一行末尾还悬着一个分隔点。挂在后面的点解决不了「折行时行尾拖点」，
   只能换排版。四列网格后是 4+3，左边缘对齐、行距一致。
   这一行全是数字，去掉中点也不会误读（区域 14 个、商圈 152 个那些面板
   仍是 flex + 中点，不动）。980 以下复位成 flex —— 手机上四列每列只有
   82px，装不下「2,000–3,000㎡」。 */
.sb-panel[data-panel="a"].on{ display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:2px 12px; }
.sb-panel[data-panel="a"] a:not(:last-child)::after{ content:none; }

/* 联系顾问从文字链改成实心红按钮，并钉在左栏底部：
   flex 列里 margin-top:auto 会吃掉剩余空间（优先级高于 justify-content:center），
   按钮下沿就贴着首屏底边，和右边那张图的底边只差一个 32px 内边距。
   尺寸对着搜索框里的「找房」做：56 高、同一档字号；红底白字实测 6.3:1。 */
.hero-foot{ display:flex; flex-wrap:wrap; align-items:center; justify-content:flex-start; gap:12px 20px; margin-top:32px; padding-top:0; max-width:760px; }
.hero-call{
  display:inline-flex; align-items:center; justify-content:center; gap:8px;
  height:56px; padding:0 32px; border-radius:var(--r-1);
  border:1px solid var(--line);
  background:transparent; color:var(--ink);
  font-size:var(--fs-md); letter-spacing:.06em;
  transition:background .25s var(--ease), color .25s var(--ease), border-color .25s var(--ease);
}
.hero-call svg{ flex:0 0 auto; transition:transform .25s var(--ease); }
/* 2026-10-20：原来这里是红底。首屏同时出现三块红（logo、找房、联系顾问），
   而「找房」才是这一步的主线动作 —— 联系顾问退成描边，红只留给搜索按钮。 */
.hero-call:hover{ background:var(--ink); color:var(--white); border-color:var(--ink); }
.hero-call:hover svg{ transform:translateX(4px); }
.hero-call:focus-visible{ outline:2px solid var(--ink); outline-offset:3px; }
/* 首屏的备选联系方式。桌面在「联系顾问」右侧作弱化文字链接，
   980 以下顶栏电话收起，这一条就是手机端唯一的拨号入口 —— 不能省。
   号码本身加粗、tabular-nums：11 位号在细体小字里容易串行。 */
.hero-tel{
  display:inline-flex; align-items:center; gap:8px; min-height:44px;
  font-size:var(--fs-md); color:var(--ink2); letter-spacing:.02em;
  transition:color .25s var(--ease);
}
.hero-tel b{ font-weight:700; color:var(--ink); font-variant-numeric:tabular-nums; letter-spacing:.03em; }
.hero-tel:hover{ color:var(--ink); }
.hero-tel:hover b{ color:var(--brand); }
.hero-tel:focus-visible{ outline:2px solid var(--ink); outline-offset:3px; }
/* 首屏信任行（2026-10-20 补）。Stanford Web Credibility Project 的结论是：
   约 75% 的用户主要凭站点的设计与表述判断一家公司是否可信；
   而「标明资料的来源与依据」被 68% 的受访者列为影响判断的因素。
   首屏此前只有一句成本承诺（佣金由业主支付），没有一句交代「这些资料凭什么可信」，
   于是后半程只能靠关于页补 —— 而 NN/g 的实测是读者只看页面 20–28% 的文字。
   放在搜索框之后：读者刚看完表单，视线还在这里，不必再往下找。 */
.hero-fact{
  margin:0; padding-top:24px; max-width:560px;
  font-size:var(--fs-md); line-height:1.75; color:var(--ink3); letter-spacing:.01em;
}
.hero-fact b{ font-weight:700; color:var(--ink2); }
/* ============================================================
   第二种入口：按人数估面积（首屏下方独立一带）
   ============================================================ */
.est-band{ background:var(--paper2); border-bottom:1px solid var(--line); padding:40px 0; }
.est-grid{ display:grid; grid-template-columns:360px minmax(0,1fr) 300px; gap:48px; align-items:center; }
.est-intro h2{ font-family:var(--serif); font-size:calc(var(--fs-h3)*var(--k)); font-weight:500; letter-spacing:.04em; line-height:1.5; text-wrap:balance; }
.est-intro p{ font-size:var(--fs-bs); color:var(--ink3); line-height:1.9; margin-top:8px; max-width:330px; }
.est-row{ display:grid; grid-template-columns:1fr 1fr; gap:0 24px; }
.est-f{ border-bottom:1px solid var(--line3); padding-bottom:8px; }
.est-f label{ display:block; font-size:var(--fs-sm); color:var(--ink3); }
.est-f:focus-within{ border-bottom-color:var(--ink); }
/* 估算输入框原来聚焦时什么变化都没有：下划线不动、外框没有，键盘用户不知道焦点在哪。 */
.est-f input{
  width:100%; border:0; background:transparent; outline:none; font:inherit;
  font-size:var(--fs-h3); font-variant-numeric:tabular-nums; padding:4px 0 0; color:var(--ink);
}
.est-dens{ display:flex; gap:8px; margin-top:16px; }
.est-dens button{
  flex:1; height:32px; border:1px solid var(--line3); font-size:var(--fs-sm); color:var(--ink3);
  transition:background-color .2s var(--ease), border-color .2s var(--ease), color .2s var(--ease);
}
.est-dens button.on{ background:var(--ink); border-color:var(--ink); color:var(--white); }
.est-out b{ font-family:var(--serif); font-size:calc(var(--fs-h1)*var(--k)); font-weight:300; line-height:1; letter-spacing:-.01em; font-variant-numeric:tabular-nums; display:block; }
.est-out b i{ font-style:normal; font-size:var(--fs-lg); margin-left:4px; letter-spacing:0; }
.est-range{ font-size:var(--fs-sm); color:var(--ink3); margin-top:8px; display:block; }
/* 右栏只有 300 宽，两个链接横排时第二个一定被挤到下一行、还和第一个下划线错位。
   改成竖排：一条主动作、一条弱动作，各自一行，右边缘不错位。 */
.est-acts{ display:flex; flex-direction:column; align-items:flex-start; gap:8px; margin-top:16px; }
.est-acts .go{ display:inline-flex; align-items:center; min-height:32px; font-size:var(--fs-bs); color:var(--ink); border-bottom:1px solid var(--ink); }
.est-acts .go:hover{ color:var(--brand); border-color:var(--brand); }
.est-acts .lite{ display:inline-flex; align-items:center; min-height:32px; font-size:var(--fs-bs); color:var(--ink3); }
.est-acts .lite:hover{ color:var(--ink); }

/* ============================================================
   通用区块
   ============================================================ */
.sec{ padding:96px 0; }
.sec.tight{ padding:64px 0; }
.sec.alt{ background:var(--paper2); }
.sec.white{ background:var(--white); }

.sec-h{ display:grid; grid-template-columns:1fr auto; align-items:end; gap:28px; margin-bottom:32px; }
.sec-k{ display:flex; align-items:baseline; gap:16px; }
/* 区块起首的短墨线（v3.1）：28px、1px、贴着标题左上角。
   这是编辑设计的「章节起头」记号 —— 作用不是装饰，是让眼睛在长页面上
   认出「新的一个区块从这里开始」。首屏那条 eyebrow 横线用的是同一语汇，
   所以整页读下来是一致的，不会显得多贴了一个东西。
   padding-top 撑出的 16px 同时把标题推离上一条分割线，密度更从容。 */
.sec-h .sec-k{ position:relative; padding-top:16px; }
.sec-h .sec-k::before{
  content:""; position:absolute; top:0; left:0; width:28px; height:1px; background:var(--ink);
}
/* .sec-k 是「编号 + 标题」这个组合件，通常包在 .sec-h 里；
   但工具版块是两栏排的，外面没有 .sec-h —— 只写 .sec-h h2 的话，
   那个 h2 会掉回浏览器默认的 1.5em（量出来 22.5px，不在字号令牌上）。
   把 .sec-k h2 一并纳入，字级仍是同一档，不是新增字号。 */
.sec-h h2,.sec-k h2{
  font-family:var(--serif); font-size:calc(var(--fs-h2)*var(--k)); font-weight:500;
  letter-spacing:.03em; line-height:1.5;
}
/* 行宽按字数定，不按像素：CJK 一行 32–40 字最省眼睛，用 em 写就跟着字号走 */
.sec-sub{ font-size:var(--fs-md); color:var(--ink3); line-height:1.9; margin-top:8px; max-width:38em; }
.sec-h .more{
  display:inline-flex; align-items:center; min-height:32px;
  font-size:var(--fs-bs); color:var(--ink2); white-space:nowrap; padding-bottom:4px;
  border-bottom:1px solid var(--ink4); transition:border-color .25s var(--ease), color .25s var(--ease);
}
.sec-h .more:hover{ color:var(--brand); border-color:var(--brand); }

/* 业务入口条：四格，细线，轻 */
.pa{ display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); border-top:1px solid var(--ink); border-bottom:1px solid var(--line); }
.pa a{ padding:24px 24px 24px 0; border-right:1px solid var(--line2); position:relative; }
.pa a:last-child{ border-right:0; padding-right:0; }
.pa a + a{ padding-left:24px; }
.pa h3{ font-family:var(--serif); font-size:var(--fs-lg); font-weight:500; letter-spacing:.04em; display:flex; align-items:baseline; gap:8px; }
.pa h3 em{ font-style:normal; font-family:var(--en); font-size:var(--fs-xs); letter-spacing:.16em; color:var(--ink3); }
.pa p{ font-size:var(--fs-bs); color:var(--ink3); line-height:1.75; margin-top:8px; max-width:260px; }
.pa a::after{ content:""; position:absolute; left:26px; bottom:0; width:0; height:1px; background:var(--ink); transition:width .4s var(--ease); }
.pa a:first-child::after{ left:0; }
.pa a:hover::after{ width:40px; }
.pa a:hover h3{ color:var(--ink); }

/* ============================================================
   楼盘卡（精选）
   ============================================================ */
.pgrid{ display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:36px 24px; }
.pcard{ display:flex; flex-direction:column; background:transparent; }
.pc-ph{ position:relative; overflow:hidden; background:var(--paper3); aspect-ratio:4/3; }
/* 无封面占位：与首页 portal.js 里那句一致 */
/* 「暂无实拍」这四个字是给读者看的：--ink4 压在 --paper3 上只有 1.6:1，
   截图里就是一整块空白，等于告诉客户"图裂了"。抬到 --ink3。 */
.pc-no{ position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
  color:var(--ink3); font-size:var(--fs-xs); letter-spacing:.06em; }
/* 竖构图放进 4:3 框必然要裁。默认从正中裁，最先没的就是楼顶那截天线；
   竖图统一把焦点上移，裁掉的是天空与地面。class=p 由 portal.js 按源图比例打上。 */
/* ⚠ 裁切只能落在左边（2026-10-24）：
   卡片图框是 4:3（1.333），而库里横图 P50 是 1.5、P95 到 1.6 ——
   默认 50% 居中裁，左右各切掉 6%～9% 的图宽。水印的 slogan logo
   正好压在右下角、右边距 ≈ 0，于是被切掉一半（实测截图里只剩「VAN」）。
   老板的要求是「除首屏外所有图都要有水印」，裁掉等于这张图没水印。
   所以横图改成右侧对齐：所有裁切都发生在左边，右下角永远完整。 */
.pc-ph img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; object-position:100% 100%; transition:opacity .6s var(--ease), transform 1s var(--ease); }
/* 竖构图（portal.js 按源图比例打 .p）放 4:3 框里要纵向裁掉 40% 以上。
   ⚠ 2026-10-24 纠正上一版：这里原来写 32%（焦点上移保楼顶天线），
     注释说的是「竖图裁不到左右，右侧 logo 不受影响」—— 只算了横向。
     竖图的溢出**发生在纵向**，取景 32% 等于把下沿切掉 68% 的溢出轨，
     水印 logo 正压在右下角，等于这张图没水印。实测探针在
     390/820/1024/1280/1440/1920 六档都报「下沿被裁 12.5%」。
     全库只有 1.5%（2,188/146,964）是竖图，P50 宽高比 1.60 ——
     按底部对齐对 95% 的图没有任何代价（横图纵向不溢出），
     换来的是「所有图都带水印」这条硬口径。楼顶天线让位给右下角 logo。 */
.pc-ph img.p{ object-position:100% 100%; }
.pc-ph .ph-b{ opacity:0; }
.pcard:hover .pc-ph .ph-a{ opacity:0; }
.pcard:hover .pc-ph .ph-b{ opacity:1; }
.pc-ph::after{ content:""; position:absolute; inset:0; box-shadow:inset 0 0 0 1px rgba(var(--ink-rgb), .06); pointer-events:none; }
.pc-ph .cert{
  position:absolute; right:0; bottom:0; z-index:2; background:var(--ink); color:var(--white);
  font-size:var(--fs-xs); letter-spacing:.06em; padding:4px 8px; max-width:62%;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.pc-b{ padding:16px 0 0; display:flex; flex-direction:column; flex:1; position:relative; }
.pc-t{ display:flex; align-items:baseline; gap:8px; }
.pc-n{
  font-family:var(--serif); font-size:calc(var(--fs-lg)*var(--k)); font-weight:500; line-height:1.5; letter-spacing:.01em;
  min-width:0; padding-right:72px;
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;
}
/* 租金独占一行（2026-10-21）：老板给的层级是「租金 > 面积 > 楼层 > 商圈 > 地铁 > 交付」。
   19px 是令牌里的「数字」级（--fs-num），和电话、估算值同一档 ——
   比楼名（17px）大，但比不过栏目标题，正好是"卡片里最重的一条数据"。
   min-height 让「租金面议」与「3.3–4.3」占同样高度，一页 18 张卡才有一致的节奏。 */
.pc-p{
  display:flex; align-items:center; gap:4px;
  font-size:calc(var(--fs-num)*var(--k)); color:var(--ink); font-weight:700;
  font-variant-numeric:tabular-nums; letter-spacing:.01em; line-height:1.5;
  margin-top:8px; min-height:calc(26px*var(--k));
}
.pc-p em{ font-style:normal; font-size:var(--fs-xs); font-weight:400; color:var(--ink3); letter-spacing:.04em; }
/* 面议的楼：同一行、同一高度（min-height 兜住），但降回 13px 灰 ——
   60 栋里 25 栋没有公开报价，它们不该和有价的楼抢同一个视觉位置。
   这是信息，不是缺省。 */
.pc-p.na{ font-size:var(--fs-bs); color:var(--ink3); font-weight:400; }
/* 在租套数与可租面积段（2026-10-22）——
   搜楼卡片上是「166-2500m² · 10套可租房源」，我们压在价格下面一行。
   客户扫列表的判断顺序是「多少钱 → 有没有我要的面积 → 楼怎么样」，
   这一行把第二步补上；没有房源的楼整行不出现，不留空行。 */
.pc-u{
  margin-top:4px; font-size:var(--fs-xs); color:var(--ink3);
  font-variant-numeric:tabular-nums; letter-spacing:.02em; line-height:1.5;
}
/* 2026-10-27：地址行不再单行截断。
   原来是 nowrap + ellipsis，卡片窄到 166px 时地址被砍掉 86px —— 砍掉的正是
   「哪个片区、哪条路」，而这两段是这一行唯一的用处（楼名在上方已经有了）。
   排版取证在 6 档宽度里报 54 次 `div.pc-sub 差 N px`。改成允许折行：
   地址最多占两行，卡片靠 grid 自动等高，不会错位。
   ⚠ 保留 overflow:hidden —— 折行后不该再有横向溢出，留着只是防止
   `｜` 前后的长数字串在极端宽度下顶出去。 */
.pc-sub{ font-size:var(--fs-sm); color:var(--ink3); margin-top:8px; overflow:hidden; overflow-wrap:anywhere; }
.pc-d{ display:grid; grid-template-columns:minmax(0,1.25fr) minmax(0,1fr) minmax(0,1fr); gap:0; border-top:1px solid var(--line2); margin-top:12px; padding-top:8px; }
.pc-d div{ min-width:0; }
.pc-d div + div{ padding-left:8px; border-left:1px solid var(--line2); }
.pc-d .v{ font-size:var(--fs-md); color:var(--ink); font-variant-numeric:tabular-nums; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pc-d .k{ font-size:var(--fs-xs); color:var(--ink3); margin-top:4px; }
.pc-m{ font-size:var(--fs-sm); color:var(--ink2); margin-top:12px; display:flex; align-items:center; gap:8px; }
.pc-m svg{ flex:0 0 auto; opacity:.45; }
/* min-width:0 是 flex 子项能收缩到内容以下的前提 —— 少了它，
   底行「地铁 + 右端小字」两个 nowrap 的 span 会一起把卡片撑宽（R82 实测 768 溢出 19px）。
   flex-wrap 再兜一层：窄卡片放不下时右端小字整块落到第二行右端，
   而不是把这个 pgrid 的 1fr 轨道（min 是 auto）顶宽。 */
.pc-m span{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pc-m{ flex-wrap:wrap; row-gap:4px; }
/* 卡片底行右端的交付标准（2026-10-21）。价格上移到 .pc-p 之后，
   这一格从"报价"换成"交付"，仍然压在 11px 灰 —— 它用来排除，不用来比较。
   padding-left:10px 是为了 390 宽时地铁那一句占满整行后，
   「步行 20 分钟标准交付」不会连读成一句。 */
.pc-m .pc-dl{
  margin-left:auto; flex:0 0 auto; color:var(--ink3);
  font-size:var(--fs-xs); letter-spacing:.04em; padding-left:8px;
}
/* 900 以下卡片只有两列（约 340px），底行长地铁 + 右端小字放不下一行：
   不强制的话，短地铁的卡小字在右端、长地铁的卡小字掉到第二行，
   同一屏里两种排法。统一让窄屏一律第二行右对齐。 */
@media (max-width:900px){
  .pc-m .pc-dl{ width:100%; text-align:right; padding-left:0; }
}

/* ============================================================
   实拍图墙：满幅联系印样
   ============================================================ */
.wall-sec{ background:var(--paper); padding:0 0 8px; }
.wall-hd{ display:flex; align-items:baseline; justify-content:space-between; gap:20px; padding:0 32px 16px; max-width:var(--w); margin:0 auto; }
.wall-t{ font-family:var(--serif); font-size:var(--fs-lg); font-weight:500; letter-spacing:.06em; }

.wall{ display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:1px; background:var(--line); border-top:1px solid var(--line); border-bottom:1px solid var(--line); }
.wall a{ display:block; background:var(--paper); overflow:hidden; }
.wall img{ display:block; width:100%; aspect-ratio:4/3; object-fit:cover; object-position:100% 100%; transition:transform 1.2s var(--ease); }
.wall a:hover img{ transform:scale(1.03); }
.wall .cap{ display:flex; align-items:baseline; justify-content:space-between; gap:12px; padding:12px 12px 12px; font-size:var(--fs-bs); color:var(--ink); letter-spacing:.02em; }
.wall .cap b{ font-weight:400; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.wall .cap em{ font-style:normal; font-size:var(--fs-xs); color:var(--ink3); white-space:nowrap; flex:0 0 auto; }

/* ============================================================
   全部房源
   ============================================================ */
/* 面板浮在 paper2 底上：白纸 + 1px 描边。原来是五行无边的灰字，与下面的列表
   同色同底，整页读下来像一张打印出来的表格 —— 客户第一眼落在"一堆灰字"上，
   而不是"我要筛什么"。白纸 + 描边是这套设计语言里唯一的"块"，不加圆角不加投影。 */
.fpanel{ position:relative; background:var(--white); border:1px solid var(--line3); padding:0 32px; }
/* 抬头高 44：「清空全部」是可点元素，字号只有 12 时它自己的行盒只有 23 高，
   手指点不准（内页热区闸门实测 fp-clear:23）。给按钮 44 的实体高度，
   抬头随之变成 44+12，仍然比一行正文矮。 */
.fp-hd{ display:flex; align-items:center; justify-content:space-between; gap:20px; padding:8px 0; border-bottom:1px solid var(--ink); }
.fp-t{ font-size:var(--fs-sm); letter-spacing:.18em; color:var(--ink3); }
.fp-clear{ display:inline-flex; align-items:center; min-height:44px; font-size:var(--fs-sm); color:var(--ink3); letter-spacing:.04em; transition:color .2s var(--ease); }
.fp-clear:hover{ color:var(--brand); }
/* 手机筛选抽屉开关。桌面不出现：桌面五行筛选条一共 303px，一屏内看得完，
   折叠反而多一次点击。只在 ≤760 显示（规则写在文件下方的断点里）。
   基础规则必须在这里、断点之前 —— 同一个选择器后者胜出，写在断点之后
   会把 760 以下的规则整块反超掉（这个坑本轮之前已经踩过 5 次）。 */
/* R14 遗留：这个 checkbox 原来带 aria-hidden="true" 却在 Tab 序列里 ——
   读屏看不见它、键盘又停得住，属于「两头都不对」。改成带名字（aria-label 在生成器里）
   + 视觉隐藏但可聚焦 + 焦点环画在可见的 44px 折叠条上。≥761 没有折叠条，display:none。 */
.ffx{ position:absolute; width:1px; height:1px; margin:-1px; padding:0; border:0;
  opacity:0; overflow:hidden; clip-path:inset(50%); white-space:nowrap; pointer-events:none; }
.ffx:focus-visible + .fsum{ outline:2px solid var(--brand); outline-offset:-2px; }
.fsum{ display:none; }
@media (min-width:761px){ .ffx{ display:none; } }
.fsum-i{ font-style:normal; }
/* 标签列 120px（原 104）。5 个汉字的标签（标准层面积 / 步行到地铁）
   在 12px + .12em 字距下要 67px，加上 14px 图标与 7px 间距共 88，
   再减右内边距 16 —— 104 正好差 4px 放不下，「标准层面积」被折成两行，
   两个 5 字标签一起折，六行里有两行比别的高一倍。
   加宽到 120 之后右侧选项区少 16px，实测不会触发换行。 */
.frow{ display:grid; grid-template-columns:120px minmax(0,1fr); border-bottom:1px solid var(--line2); }
.frow:last-child{ border-bottom:0; }
/* 标签列 12px + .12em 字距：与选项、正文拉开一档"索引"的质感，
   而不是和选项同字号同颜色挤成一片。 */
/* 筛选行左标签前挂图标（v3.1）：六行标签一字排开时，「区域 / 商圈 / 地铁」
   都是两个汉字、同色同号，扫读时要一行一行读字才能定位。挂上图之后，
   眼睛先认图形再认字 —— 这是全站唯一一处「图标真的在干活」而不是装饰。
   14px 略大于标签本身的 12px：11–12px 的描边在纸上会缩成一团灰。
   颜色用 --ink2，标签用 --ink3 —— 图标深一档，才不会读成标签的一部分。 */
.fl{ padding:16px 16px 16px 0; font-size:var(--fs-sm); color:var(--ink3); letter-spacing:.14em; display:flex; align-items:center; gap:8px; }
.fl .ic-i{ width:14px; height:14px; color:var(--ink2); }
/* 选项组的负左距：让第一项（不限）的底色块与「区域」标签列左边界对齐，
   而不是悬在文字里缩进 13px。手机断点里重置为 0 —— 那时面板已经贴边。 */
/* 2026-10-27：选项间距 2 → 7、行内上下 8 → 12。原来的 2px 间距让十几个选项
   连成一片灰字，客户的原话是「只有黑白文字和背景，密密麻麻」。选项本身
   不加边框 —— 五列汉字外面套 14 个方框，一排就是一张表格，比灰字更吵；
   靠间距与行高把每一组分开，是这套设计语言里更安静的做法。 */
.fv{ padding:12px 0; margin-left:-12px; display:flex; flex-wrap:wrap; align-items:center; gap:8px; }
.fv button{
  display:inline-flex; align-items:center;
  height:34px; padding:0 12px;
  font-size:var(--fs-md); color:var(--ink2); line-height:1; letter-spacing:.01em;
  border-radius:var(--r-1);
  transition:color .2s var(--ease), background-color .2s var(--ease), border-color .2s var(--ease);
}
.fv button:hover{ color:var(--ink); background:var(--paper2); }
/* 选中 = 墨黑实底白字。全站"被选中"只有这一种表达（排序条同款）。
   原来用浅底 + 1px 内描边，一排十几个浅灰小框，看不出到底选中了哪一项。 */
.fv button.on{ background:var(--ink); color:var(--white); }
/* 「不限」不是"被选中"，它表达"这一维没有条件"。
   五行各一块黑会让黑变成底纹 —— 弱化成浅描边小框，真选了具体项才变黑块。 */
.fv button.on[data-v=""]{ background:transparent; color:var(--ink2); box-shadow:inset 0 0 0 1px var(--line3); font-weight:400; }

/* ── 地铁：线路方格 + 站点（2026-10-27）────────────────────────────
   线路这一排从「1 号线 2 号线 … 18 号线」改成 1–18 的等宽方格：
   汉字后缀每个多占 34px，18 项要占两行；方格只用数字，一行放得下，
   而且数字是等宽的，眼睛能直接跳到「7」而不是一行一行读。
   站点区藏在 wrap 里，选线后才展开（理由见 portal-app.js renderMetro）。 */
.fv-wrap{ margin-left:-12px; padding:4px 0; }
.fv-wrap > .fv{ margin-left:0; padding:8px 0; }
.fv button.ml{
  width:38px; min-width:38px; height:34px; padding:0;
  display:inline-flex; align-items:center; justify-content:center;
  font-family:var(--en); font-size:var(--fs-bs); letter-spacing:0;
  font-variant-numeric:tabular-nums;
  border:1px solid var(--line2); background:var(--white); color:var(--ink2);
}
.fv button.ml:hover{ border-color:var(--ink4); color:var(--ink); background:var(--white); }
.fv button.ml.on{ background:var(--ink); border-color:var(--ink); color:var(--white); }
/* 站点是第二级条件：一条虚线把它和线路分开，字号与内边距各收一档 ——
   视觉上从属于上面那条线，不是与线路平级的另一组。 */
.fv-st{ border-top:1px dashed var(--line2); margin-top:4px; padding-top:12px; margin-left:0; }
.fv-st button{ font-size:var(--fs-bs); padding:8px 12px; color:var(--ink2); }
.fv-st .fv-sub{ font-size:var(--fs-xs); color:var(--ink4); letter-spacing:.1em; margin:0 8px 0 4px; }
.fv-st .fv-note{ font-size:var(--fs-bs); color:var(--ink4); }
/* .fv 的 display:flex 会压掉 [hidden] 的默认 display:none —— 这条不是保险，
   是「没选线路时站点区必须真的消失」的唯一保障。 */
.fv[hidden]{ display:none; }
.fv .sep{ width:1px; height:12px; background:var(--line); margin:0 12px; }
.fv input{ border:1px solid var(--line); height:32px; padding:0 8px; font:inherit; font-size:var(--fs-bs); width:64px; outline:none; }
.fv input:focus{ border-color:var(--ink4); }
.fv .unit{ font-size:var(--fs-sm); color:var(--ink3); margin-left:4px; }

/* ── 商圈分层：「全部 N 个」与就地搜索（2026-10-27）──────────────────
   152 个商圈全量平铺占 19 行，打开「找楼」第一屏看不到一栋楼
   （规则与理由写在 portal-app.js 的 renderBd 上）。这两个控件是折叠的把手，
   不是筛选条件，所以要比 chip 弱一档：虚框 + 灰字，不实心、不描边实线。
   ⚠ .fv button 设了 padding/transition，hidden 属性会被它们的 display
     规则压掉 —— 下面那条 [hidden] 是必须的，不是保险。 */
.fv button.fv-more{
  height:32px; padding:0 12px; border:1px dashed var(--line3); border-radius:var(--r-1);
  color:var(--ink3); background:transparent; font-size:var(--fs-bs);
}
.fv button.fv-more:hover{ color:var(--ink); border-color:var(--ink4); background:transparent; }
.fv .fv-q{ display:inline-flex; align-items:center; gap:8px; margin-left:4px; }
.fv input.fv-qin{
  width:180px; height:32px; padding:0 10px;
  border:1px solid var(--line3); border-radius:var(--r-1);
  font:inherit; font-size:var(--fs-bs); color:var(--ink); background:var(--white); outline:none;
}
.fv input.fv-qin::placeholder{ color:var(--ink4); }
.fv input.fv-qin:focus{ border-color:var(--ink); }
.fv .fv-nohit{ font-size:var(--fs-sm); color:var(--ink4); font-weight:400; }
.fv button.fv-less{
  height:32px; padding:0 8px; border:0; background:transparent;
  color:var(--ink3); font-size:var(--fs-bs);
}
.fv button.fv-less:hover{ color:var(--ink); background:transparent; }
.fv button[hidden]{ display:none; }


/* 结果条：一行说"现在是什么条件"，一行说"点开能看什么"，右边是排序。
   原来上下各一道 1px 墨线，整条像被两道粗线夹住的表格行；现在只在顶上留墨线
   承接面板底边，下边退成发丝线 —— 与列表第一行分开，但不抢视线。 */
.resbar{
  display:grid; grid-template-columns:minmax(0,1fr) auto; gap:20px; align-items:center;
  padding:20px 0 16px; border-bottom:1px solid var(--line3);
}
.resbar-l{ min-width:0; }
.rh{ display:flex; align-items:center; gap:16px; flex-wrap:wrap; }
/* 条件标签：前面一条 15px 品牌红短线，是这一页唯一的红。
   类名不能叫 .cur —— 面包屑的当前页就是 .cur，会一起吃到这条红线和 500 字重。 */
.cond{
  display:inline-flex; align-items:center; gap:8px;
  font-size:var(--fs-md); color:var(--ink); font-weight:700; letter-spacing:.02em;
}
.cond::before{ content:''; width:15px; height:2px; background:var(--brand); flex:0 0 auto; }
.resbar .cnt{ margin-top:8px; font-size:var(--fs-bs); color:var(--ink3); line-height:1.75; }
/* 翻页之后焦点落到这里（见 portal-app.js 的 focusResults）。
   只给键盘画环：鼠标翻页时 :focus-visible 不匹配，视觉与原来一模一样。 */
#count:focus-visible{ outline:2px solid var(--brand); outline-offset:3px; border-radius:var(--r-1); }
/* 「租金面议」从九张卡上收下来，放到列表工具条上说一次 */
.resbar .pnote{
  font-size:var(--fs-xs); color:var(--ink3); letter-spacing:.04em;
  padding-left:16px; border-left:1px solid var(--line3);
}
/* 排序做成一条密排的分段控件：五个词并排各自加下划线，读起来像一份目录；
   收进一个 1px 框、选中项压成黑块，才是"当前按哪个排"。 */
.sort{ display:flex; align-items:stretch; border:1px solid var(--line3); }
.sort button{ font-size:var(--fs-bs); color:var(--ink2); padding:8px 12px; white-space:nowrap; transition:color .2s var(--ease), background-color .2s var(--ease); }
.sort button + button{ border-left:1px solid var(--line2); }
.sort button:hover{ color:var(--ink); background:var(--paper2); }
.sort button.on{ background:var(--ink); color:var(--white); }

.listwrap{ display:grid; grid-template-columns:1fr 320px; gap:40px; align-items:start; margin-top:8px; }

/* 横向列表行（R3）：一屏十行，行高定生死。
   原来 223px —— 236 图 + 楼名（中文名 + 「写字楼」 + 英文名）+ 地址/地铁 + 三个标签
   + 五格数据 + 右侧一整列「租金面议」。现在 ~148：图贴满行高，楼名旁只留认证，
   区域/地址/地铁并成一行（不换行，换行行高就失控），五格数据一行、面积首格加重。
   右侧只留「查看详情」；「租金面议」在工具条上说一次，逐行印十遍是噪音。 */
.lcard{
  position:relative;
  /* 第三列 112 → 150：整栋报价「3.3–4.3 / 元/㎡/天」竖排两行要放得下老板给的口径，
     112 只能塞下「查看详情」。中间那列 1fr，150 之后 1440 下仍余 940+。 */
  display:grid; grid-template-columns:206px minmax(0,1fr) 150px; gap:0;
  border-bottom:1px solid var(--line); background:transparent;
  transition:background .25s var(--ease);
}
/* hover 原来是 --paper2 —— 而这一节整块的底色本来就是 --paper2（.sec.alt），
   等于没有 hover。改成白纸：在浅灰底上浮起一行，与筛选面板同一种"实面"。 */
.lcard:hover{ background:var(--white); }
.lc-ph{ position:relative; overflow:hidden; background:var(--paper3); align-self:stretch; }
/* 同 .pc-ph 的道理（见那边注释）：框比图窄，居中裁会切掉右下角的 logo。
   榜单卡在 390 下框是 1:1（.lc-ph{aspect-ratio:1/1}），横图要横向裁 33% ——
   不右对齐的话，手机上这一栏的图**全部**没有水印。 */
.lc-ph img.p{ object-position:100% 100%; }
.lc-ph img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; object-position:100% 100%; transition:opacity .6s var(--ease), transform 1s var(--ease); }
.lc-ph img.ph-b{ opacity:0; }
.lcard:hover .lc-ph img.ph-a{ opacity:0; }
.lcard:hover .lc-ph img.ph-b{ opacity:1; }

.lc-b{ padding:16px 24px; min-width:0; display:flex; flex-direction:column; justify-content:center; }
.lc-t{ display:flex; align-items:baseline; gap:8px; flex-wrap:wrap; }
.lc-n{ font-family:var(--serif); font-size:calc(var(--fs-num)*var(--k)); font-weight:500; line-height:1.25; }
.lc-cert{ font-size:var(--fs-sm); color:var(--ink2); border:1px solid var(--line); padding:2px 8px; line-height:1.5; white-space:nowrap; }
/* .chip 是详情页「周边与楼内配套」在用的标签，别跟着列表行一起删 */
.chip{ font-size:var(--fs-sm); color:var(--ink2); border:1px solid var(--line); padding:4px 8px; line-height:1.75; white-space:nowrap; }
/* 区域·商圈 / 地址 / 地铁：一行走完，超了省略号。让它们换行 = 行高失控。 */
.lc-loc{ display:flex; align-items:center; gap:0 8px; margin-top:8px; font-size:var(--fs-bs); color:var(--ink2); white-space:nowrap; overflow:hidden; }
.lc-loc > span{ overflow:hidden; text-overflow:ellipsis; }
.lc-loc > span + span::before{ content:'·'; color:var(--ink4); margin-right:8px; }
.lc-metro{ display:flex; align-items:center; gap:0 8px; color:var(--ink3); flex:0 0 auto; white-space:nowrap; }
.lc-metro svg{ flex:0 0 auto; }
.lc-walk::before{ content:'·'; color:var(--ink4); margin-right:8px; }
.lc-d{ display:grid; grid-template-columns:1.4fr .9fr .9fr 1.15fr .8fr; gap:0; margin-top:8px; padding-top:8px; border-top:1px solid var(--line2); }
.lc-d > div{ min-width:0; }
.lc-d > div + div{ padding-left:12px; border-left:1px solid var(--line2); }
.lc-d b{ display:block; font-size:var(--fs-md); font-weight:400; font-variant-numeric:tabular-nums; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.lc-d span{ display:block; margin-top:4px; font-size:var(--fs-xs); color:var(--ink3); letter-spacing:.04em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
/* 面积是客户第一个要核的字段：唯一加重的一格 */
.lc-key b{ font-size:var(--fs-num); font-weight:700; }
/* 右侧原来是一个 1px 描边的「查看详情」小方块 —— 十行十个框，是这一节最像
   表格的地方。改成"文字 + 箭头"：默认安静，hover 时箭头右移 4px 并变墨色。
   整行本来就是 <a>，可点面积没有变小。 */
.lc-r{ padding:16px 20px 16px 16px; border-left:1px solid var(--line);
  display:flex; flex-direction:column; align-items:flex-end; justify-content:center; gap:8px; }
/* 整栋报价（2026-10-21）：数字一行、单位一行、查看详情一行。
   原来这一列只有一个「查看详情」，是最没信息量的一列 —— 价格才是客户扫列表时
   第一眼要找的东西，把它放在视线终点，查看详情退成第二行。 */
.lc-pr{ font-family:var(--serif); font-size:var(--fs-md); color:var(--ink);
  font-variant-numeric:tabular-nums; white-space:nowrap; letter-spacing:.01em; }
.lc-pr em{ display:block; font-style:normal; font-family:var(--sans);
  font-size:var(--fs-xs); color:var(--ink3); margin-top:4px; text-align:right; letter-spacing:.04em; }
.lc-pr.na{ color:var(--ink3); font-size:var(--fs-bs); }
/* 交付标准（2026-10-21）：卡片把它放在底行右端，列表行没有那一行，就落在价格
   与「查看详情」之间 —— 同一列、同一种 11px 灰。三种口径：标准交付 / 遗留装修 / 精装修。 */
.lc-dl{ font-size:var(--fs-xs); color:var(--ink3); letter-spacing:.04em; white-space:nowrap; }
/* 手机上没有第三列可站（见 760 断点里 .lc-r 整列撤掉），价格改挂楼名行右端。 */
.lc-prm{ display:none; }
.lc-go{
  display:inline-flex; align-items:center; gap:8px;
  font-size:var(--fs-bs); color:var(--ink3); white-space:nowrap;
  transition:color .25s var(--ease);
}
.lc-go svg{ flex:0 0 auto; transition:transform .25s var(--ease); }
.lcard:hover .lc-go{ color:var(--ink); }
.lcard:hover .lc-go svg{ transform:translateX(4px); }

/* ── 列表行的两处「宽度不够就切开」的收敛（2026-10-27）──────────────
   第 3 次全站检查的第 25 步只剩 search.html 一页还在判红（4 档宽度、4 行），
   原因不是「某条规则写错了」，而是**这个卡片在中间几档宽度里被挤成了半张**。
   `_probe_search_w.mjs` 实测（卡片宽 / 五格分到的宽度）：

     @1920 中间列 900px  → 五格 132–232，够
     @1440 中间列 580px  → 五格 83–145，够（面积那一格 145 装 134）
     @1280 中间列 523px  → 四格 148–129，够
     @1180 中间列 423px  → 四格 117/78/78/102，**面积差 17px**
     @1024 中间列 267px  → 五格 34–60，**面积差 74px、位置整块折成 0 宽**
     @ 900 中间列 525px  → 五格 66–117，面积差 17px
     @ 768 中间列 393px  → 五格 54–94，面积差 40px
     @ 700 中间列 349px  → 五格 47–82，**面积差 52px、物业费差 34px**
     @ 560 中间列 401px  → 五格 54–108，够
     @ 390 中间列 231px  → 两格 119/88，**面积差 15px**

   1024 之所以比 768 还窄，是因为 `.listwrap` 在这一档仍是「列表 + 360 侧栏」两栏，
   列表那一列只剩 623，而 768 已经落成单栏。所以这几档不能共用一套列数：

     ≥1440      五格（面积 1.4fr 起，够 134px）
     1200–1439  四格（砍「竣工」—— 它是五个字段里唯一不影响「这栋能不能用」的）
     561–1199   两格两行（面积 + 层高 / 物业费 + 竣工，砍「总层数」）
     ≤560       两格两行（同上，另有手机专档的缩排，见文件末尾）

   ⚠ 档位必须首尾相接，不能有缝：
     · 561–760 原来**两头不靠** —— 手机专档是 `max-width:560`，桌面五格一直顶到 561
       才让位，中间这 200px 全是五格硬挤（@700 面积差 52px）。
     · 1081–1199 原来塞给四格也装不下：这一档 `.listwrap` 仍留着 360 侧栏，
       卡片只有 324–433（比 @1024 单栏时的 267 宽不了多少），
       四格里「面积」只剩 98–141、装不下 134。所以两格档的上界一路顶到 1199。
   ⚠ 「面积」这一格的自然宽 134px（`.lc-key b` 19px，「2,500–2,700㎡」12 个字符，
   tabular-nums 下每个数字等宽），「物业费 元/㎡·月」要 88px。列宽只按 fr 分配时
   这两格是最先被切的 —— 所以凡是装得下 1.95fr 的档位都给到 1.95fr，留出余量。

   位置行（「虹口 · 北外滩/提篮桥」+ 地址）同理：`.lc-loc` 原本 nowrap + ellipsis，
   在 1024 上把地段名压成 0 宽、在 1280 上切掉 18px。改成允许折行 ——
   地段是这一行里最不能丢的字段（同名楼靠它区分）。 */
@media (min-width:1200px) and (max-width:1439px){
  /* 物业费那一格在 1.3fr 下只有 96px，减去 12px padding 剩 84，装不下 88px 的
     「物业费 元/㎡·月」—— 尾巴被切成「物业费 元/㎡·…」。1.45fr 后 104px，够。
     面积从 1.5fr 加到 1.95fr：@1200 时这一格 141px，装 134 只剩 7px 余量，太悬。 */
  .lc-d{ grid-template-columns:1.95fr 1fr 1fr 1.45fr; }
  .lc-d > div:nth-child(5){ display:none; }
  .lc-loc{ flex-wrap:wrap; white-space:normal; }
  .lc-loc > span{ overflow:visible; text-overflow:clip; }
  .lc-metro{ min-width:0; flex:1 1 auto; white-space:normal; flex-wrap:wrap; }
  .lc-metro > span{ white-space:normal; }
}
/* 下界是 561 不是 761：561–760 这一档原来两头不靠（手机专档 560 才开始），
   五格被压在 349–409px 的卡片里，「面积」差 52px、「物业费 元/㎡·月」差 34px。 */
@media (min-width:561px) and (max-width:1199px){
  .lc-loc{ flex-wrap:wrap; white-space:normal; }
  .lc-loc > span{ overflow:visible; text-overflow:clip; }
  .lc-metro{ min-width:0; flex:1 1 auto; white-space:normal; flex-wrap:wrap; }
  .lc-metro > span{ white-space:normal; }
  .lc-d{ grid-template-columns:1.9fr 1fr; row-gap:8px; }
  .lc-d > div:nth-child(2){ display:none; }
  .lc-d > div{ padding-left:0; border-left:0; }
  .lc-d > div:nth-child(even){ padding-left:8px; border-left:1px solid var(--line2); }
}

/* 空结果：给下一步，不给道歉 */
.empty{ padding:64px 0 72px; max-width:440px; }
.empty .et{ font-family:var(--serif); font-size:var(--fs-h3); font-weight:500; letter-spacing:.04em; }
.empty .es{ font-size:var(--fs-bs); color:var(--ink3); line-height:1.9; margin-top:8px; }
.empty .ea{ display:flex; flex-wrap:wrap; gap:8px; margin-top:20px; }
.empty .ea button,.empty .ea a{ display:inline-flex; align-items:center; height:36px; padding:0 16px; border:1px solid var(--line); font-size:var(--fs-bs); color:var(--ink2); transition:background-color .2s var(--ease), border-color .2s var(--ease), color .2s var(--ease); }
.empty .ea button:hover,.empty .ea a:hover{ background:var(--ink); border-color:var(--ink); color:var(--white); }
/* 筛不出结果这一刻，客户的条件已经很清楚，只差一个人接住它。
   四个按钮都在帮他改条件，没有一个是「把条件交给我们」—— 补上这一格，
   用品牌红描边把它和「再试一次」区分开。 */
.empty .ea .go{ border-color:var(--brand); color:var(--brand); }
.empty .ea .go:hover{ background:var(--brand); border-color:var(--brand); color:var(--white); }

/* 侧栏 */
.side{ display:flex; flex-direction:column; gap:32px; position:sticky; top:96px; }
.sbox{ border-top:1px solid var(--ink); }
.sbox-h{ padding:16px 0 12px; display:flex; align-items:baseline; justify-content:space-between; border-bottom:1px solid var(--line2); }
/* 侧栏三块的标题是 h2（<h1>找办公室</h1> 的直接下级），不是 h3 ——
   原来写 h3 会跳级，读屏用户听到的层级是断的。选择器两个都留着，
   是因为这套类名在别处还有 h3 用法，删掉会连带改掉那些地方的字号。 */
.sbox-h h3,.sbox-h h2{ font-family:var(--serif); font-size:var(--fs-lg); font-weight:500; letter-spacing:.06em; }
.sbox-h .lat{ font-size:var(--fs-xs); letter-spacing:.16em; color:var(--ink3); }
.sbox-b{ padding:16px 0; }
.sbox-b.compact{ padding:12px 0 0; }
.sbox-b.flush{ padding:8px 0 0; }
.sbox .btn.full{ width:100%; margin-top:20px; }

/* 地图盒：白纸 + --line3 描边、加高到 252。原来底是 --paper3 的灰块，
   和整页的浅灰底连成一片，看不出这是一张"图"。 */
.mapbox{ position:relative; height:252px; background:var(--white); overflow:hidden; border:1px solid var(--line3); }
/* 底图换高德瓦片（2026-10-20）：原来 .grid（网格）+ .river（斜带）是自绘 SVG 简图，
   只能看个大概。换成 Leaflet + 高德栅格瓦片后点位与真实地理严格对齐
   （GCJ-02 同源投影），楼名气泡、聚簇、筛选联动全部不变。
   瓦片无 Key、不占「Web 服务」5000 次/天限额；点位来自本地 VB 数据，零 API 调用。 */
.map-leaflet{ position:absolute; inset:0; z-index:0; background:var(--paper2); overflow:hidden; }
/* 瓦片连续失败 8 块判底图不可用：楼点与聚簇照常（只依赖投影），
   这里给一句 11px 的降级说明 —— 底线是小字不小于 11px。 */
.map-leaflet.maperr::after{
  content:'底图加载失败，点位显示正常'; position:absolute; left:50%; bottom:10px; transform:translateX(-50%);
  background:rgba(var(--white-rgb), .9); color:var(--ink3); font-size:var(--fs-xs); line-height:1;
  padding:4px 8px; border:1px solid var(--line3); white-space:nowrap; z-index: var(--z-tip);
}
.map-leaflet .leaflet-container{ font-family:var(--sans); background:var(--paper2); }
/* 高德出处必须保留（合规），但默认蓝链接在纸色体系里太跳：压成 11px 灰字。 */
.map-leaflet .leaflet-control-attribution{
  background:rgba(var(--white-rgb), .86); color:var(--ink3);
  font-size:var(--fs-xs); line-height:1.5; padding:1px 8px; border-radius:var(--r-1) 0 0 0;
}
.map-leaflet .leaflet-control-attribution a{ color:var(--ink3); text-decoration:none; display:inline-block; padding:4px 0; }
/* 点位（R16 重写）。改前实测：320×252 的框里 60 个点，**35 组互相压着**
   （中心距 < 11px），其中漕河泾中心与漕河泾商贸区坐标完全重合 —— 60 个点
   实际只点得到 58 个，密的地方一片黑。而且点本身只有 7px，闸门一直挂着
   「热区不足」的软项。
   现在两层处理：① 元素框 24×24（≥24 触控底线）、视觉仍是 7px 的圆画在 ::before 上；
   ② 中心距小于阈值的先并成一个带数字的圆点，点开是一列真实链接（.mpop）。
   白环让点从网格线里"浮"出来 —— 灰晕在浅灰底上等于没有边界。 */
/* 点的外框就是它的热区。原来 24×24，手机上按偏两三个像素就滑到旁边的楼。
   现在 32×32（桌面已够用），触屏档再加到 40 —— 圆点本身没变，
   单栋的点画在 ::before 里、7px 居中，外框放大只是把能按的面积撑开。 */
.mapbox .pin{
  position:absolute; width:32px; height:32px; margin:-16px 0 0 -16px;
  border:0; padding:0; background:none; border-radius:50%;
  display:flex; align-items:center; justify-content:center;
}
.mapbox .pin::before{
  content:''; position:absolute; left:50%; top:50%; width:7px; height:7px;
  margin:-3.5px 0 0 -3.5px; border-radius:50%; background:var(--ink);
  box-shadow:0 0 0 2px var(--white), 0 0 0 3.5px rgba(var(--ink-rgb), .07);
  transition:background-color .2s var(--ease), box-shadow .2s var(--ease);
}
/* 认证楼原来用品牌红点：一屏 12 个红点，红就不再是强调而是底纹。
   改成「大一圈 + 外环」——同一套墨色，靠尺寸与环区分，颜色留给真正要引人看的地方。 */
.mapbox .pin-dark::before{ width:9px; height:9px; margin:-4.5px 0 0 -4.5px; box-shadow:0 0 0 2px var(--white), 0 0 0 4px rgba(var(--ink-rgb), .13); }
/* 悬停/键盘聚焦时弹楼名：图上几十个点，光看点的疏密看不出"这是哪栋"。
   不用缩放（设计语言 v6.2 禁缩放回弹），靠换色 + 一点外扩环表达焦点。 */
.mapbox .pin::after{
  content:attr(data-n); position:absolute; left:50%; bottom:calc(50% + 12px);
  transform:translateX(-50%); white-space:nowrap; z-index:5;
  background:var(--ink); color:var(--white); font-size:var(--fs-xs); line-height:1.5;
  padding:4px 8px; opacity:0; pointer-events:none; transition:opacity .18s var(--ease);
}
.mapbox .pin:hover::before,.mapbox .pin:focus-visible::before{ background:var(--brand); box-shadow:0 0 0 5px rgba(var(--brand-rgb), .14); }
.mapbox .pin:hover,.mapbox .pin:focus-visible{ z-index:6; }
.mapbox .pin:hover::after,.mapbox .pin:focus-visible::after{ opacity:1; }
/* 靠近上沿 / 左右边沿的点，气泡翻到另一侧，否则会被图框边切掉 */
.mapbox .pin.lb-down::after{ bottom:auto; top:calc(50% + 12px); }
.mapbox .pin.lb-left::after{ left:-2px; transform:none; }
.mapbox .pin.lb-right::after{ left:auto; right:-2px; transform:none; }
/* 聚簇点：一个 26px 的实心墨圆 + 白字数字。它不解释"全站有多少栋"，
   只回答"这一处叠了几栋"—— 随筛选变、随窗口变，点开就是这几栋的列表。
   圆底必须画在**元素自己**身上，不能画在 ::before 上：闸门的对比度算法沿祖先找底色，
   ::before 里的圆它看不见，会把白字判成「白底白字 1:1」—— 第一次跑全量就红在这里。 */
.mapbox .pin-c{
  width:32px; height:32px; margin:-16px 0 0 -16px;
  background:var(--ink); border-radius:50%;
  box-shadow:0 0 0 2px var(--white), 0 0 0 4px rgba(var(--ink-rgb), .10);
  transition:background-color .2s var(--ease);
}
.mapbox .pin-c::before{ content:none; }
.mapbox .pin-c:hover,.mapbox .pin-c:focus-visible{ background:var(--brand); }
.mapbox .pin-c b{
  position:relative; z-index:1; color:var(--white);
  font-family:var(--en); font-size:var(--fs-xs); font-weight:700; line-height:1; letter-spacing:.02em;
}
.mapbox .pin-c::after{ content:none; }
/* 点开一堆楼：面板在图下方按正常文档流展开（一出场就把下面推开，不盖住地图）。
   一颗 24px 的点直接进详情，一个数字点开这一列 —— 链接一个不少，只是不叠着。 */
.mpop{ margin-top:8px; background:var(--white); border:1px solid var(--line3); }
.mpop[hidden]{ display:none; }
.mpop-h{ display:flex; align-items:center; justify-content:space-between; gap:8px; padding-left:12px; border-bottom:1px solid var(--line2); }
.mpop-h b{ font-size:var(--fs-sm); font-weight:700; color:var(--ink); }
.mpop-x{
  min-width:44px; min-height:44px; border:0; background:none; cursor:pointer;
  font-family:inherit; font-size:var(--fs-xs); color:var(--ink3); letter-spacing:.04em;
  transition:color .2s var(--ease);
}
.mpop-x:hover{ color:var(--ink); }
.mpop-l{ max-height:264px; overflow:auto; }
.mpop-l a{
  display:flex; align-items:baseline; justify-content:space-between; gap:8px;
  min-height:44px; padding:8px 12px; text-decoration:none;
}
.mpop-l li + li a{ border-top:1px solid var(--line2); }
.mpop-l a:hover{ background:var(--paper2); }
.mpop-l span{ font-size:var(--fs-sm); color:var(--ink); min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.mpop-l em{ font-size:var(--fs-xs); color:var(--ink3); font-style:normal; white-space:nowrap; flex:0 0 auto; }
/* 点位层与图例：原来这两块是 HTML 里的 style="..."，改不动也进不了设计系统。
   .dots 是 JS 往里塞 .pin 的容器，必须是绝对定位铺满。 */
/* .dots 是 JS 往里塞 .pin 的容器，必须是绝对定位铺满。
   z-index:1 压住 Leaflet 底图（瓦片 pane 内部 z-index 再高也跳不出 .map-leaflet 的层）。 */
.mapbox .dots{ position:absolute; inset:0; z-index:1; }
.map-legend{ display:flex; gap:20px; font-size:var(--fs-sm); color:var(--ink3); }
.map-legend span{ display:flex; align-items:center; gap:8px; }
.map-legend i{ width:7px; height:7px; border-radius:50%; background:var(--ink); flex:0 0 auto; }
.map-legend i.brand{ width:9px; height:9px; background:var(--ink); box-shadow:0 0 0 2px var(--white), 0 0 0 4px rgba(var(--ink-rgb), .13); }

/* 口径说明原来是压在图上的一小块白底，正好盖住左下角那几个点 ——
   说明文字不该占数据的位置，挪到图下面当注脚。 */

.agent{ display:flex; gap:16px; align-items:flex-start; }
/* 顾问：灰方块里一个灰字「顾」既不像人也不像标识。改成墨黑实底白字 ——
   与筛选选中态、排序选中态同一套"实面语言"，也是这一栏唯一的深色块，视线会先落在这里。 */
.agent .av{ width:48px; height:48px; background:var(--ink); border:1px solid var(--ink); display:flex; align-items:center; justify-content:center; font-family:var(--serif); font-size:var(--fs-lg); font-weight:500; color:var(--white); flex:0 0 auto; }
.agent .nm{ font-size:var(--fs-md); font-weight:700; }
.agent .rl{ font-size:var(--fs-sm); color:var(--ink3); margin-top:4px; line-height:1.75; }
.agent .tel{ font-size:var(--fs-lg); letter-spacing:.03em; margin-top:8px; font-variant-numeric:tabular-nums; }
.agent .tel a{ display:inline-flex; align-items:center; min-height:44px; color:inherit; text-decoration:underline; text-decoration-thickness:1px; text-underline-offset:4px; text-decoration-color:var(--line3); transition:color .2s var(--ease), text-decoration-color .2s var(--ease); }
.agent .tel a:hover{ color:var(--brand); text-decoration-color:currentColor; }

.linklist li{ border-bottom:1px solid var(--line2); }
.linklist li:last-child{ border-bottom:0; }
.linklist a{ display:flex; align-items:center; justify-content:space-between; padding:12px 0; font-size:var(--fs-bs); color:var(--ink2); transition:color .2s var(--ease); }
.linklist a:hover{ color:var(--ink); }

/* 分页 */
.page{ display:flex; align-items:center; justify-content:center; gap:4px; padding:40px 0 0; }
.page a,.page span{ min-width:34px; height:34px; display:inline-flex; align-items:center; justify-content:center; font-size:var(--fs-bs); border:1px solid var(--line); color:var(--ink2); padding:0 8px; }
.page a:hover{ border-color:var(--ink); color:var(--ink); }
.page .on{ background:var(--ink); color:var(--white); border-color:var(--ink); }
.page .gap{ border:0; }
/* 移动端页码指示：只在窄屏露出来（宽屏有完整的数字条） */
.pg-now{ display:none; }

/* ============================================================
   空镜 · 引文
   ============================================================ */
/* 2026-10-20：日落全景（2048×370，5.535:1）满宽显示，一个字都不压 ——
   之前把引文烘焙进图左侧纸色面板，等于把长图盖掉一半，观感就是「图只显示一半」。
   现在图归图、字归字：图满宽（封顶 2048 = 源宽，不放大），
   引文是图下一段普通宋体，排版从简，也不可能被任何东西挡。
   980 以下退 3.2:1 居中裁：裁切 42%（img_audit 的 CROP 线是 45%），
   留住东方明珠到上海中心那一段主体。 */
.interlude{ padding:0; }
.il-fig{ margin:0; }
.il-fig img{
  display:block; width:100%; max-width:2048px; margin:0 auto;
  aspect-ratio:var(--ar); object-fit:cover; object-position:50% 50%;
}
.il-q{
  margin:28px 0 0; max-width:560px;
  font-family:var(--serif); font-size:var(--fs-num); font-weight:300;
  line-height:1.9; letter-spacing:.03em;
}
.il-q b{
  font-weight:500;
  text-decoration:underline; text-decoration-color:var(--brand);
  text-decoration-thickness:1px; text-underline-offset:7px;
}

/* ============================================================
   设计与施工
   ============================================================ */
/* 四列基准栅格（2026-10-21 重排）
   原来左右两栏（.94/1.06）配一张主图 + 两张小图：左边越堆越高，右边只有
   两段字，图底下留出一大片空白。老板的要求是「5 张图尺寸对好、别不齐，
   文字下面别空着」—— 于是改成一条四列的栅格，五张图都落在同一条网格上：
     第 1 行：主图占 2 列（4:3），文字占 2 列，垂直居中；
     第 2 行：四张实拍各占 1 列（同为 4:3），横跨整幅。
   主图宽 = 两列 + 间距，正好等于它下面两张小图的合宽，左边三张的左边线、
   右边线与中间的分缝都在一条线上；四张小图又与主图同比例，高度一致。
   .db-sub 内部仍是四列、gap 与父级相同，所以它和外层逐列对齐，不需要 subgrid。 */
.db{ display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:16px; align-items:start; }
.db-fig{ grid-column:1 / span 2; margin:0; }
/* 2026-10-27：去掉灰底与降饱和。原来容器垫了一层 --paper3，
   图片又压了 saturate(.9) —— 两层叠起来，一张采光很好的空置标准层
   被读成「贴在灰卡纸上的图」，老板的原话是「加了个背景好奇怪」。
   照片本身没有透明区域，容器底色只在图片没加载时露一秒，留着只会误导。 */
.db-main{ overflow:hidden; background:none; }
/* 2026-11-02：主图必须撑满自己的那一格（2 列 + 间距），不能按像素宽居中。
   10-27 那版写的是 width:750px; margin-inline:auto —— 为的是不让一张 750 的老图
   被插值放大。但这条「居中」在 2 列宽 > 750 的屏上（1920 下 2 列 = 800、
   2560 下 940）会在图两侧各留一道白边：**图的左边线和下面四张实拍的左边线对不上**，
   老板原话「标准层图片和下面装修完的图没有对齐」。
   几何上没得绕：下面四张各占 1 列，主图占 2 列，主图宽必须等于「前两张 + 中间那道缝」，
   槽位宽度由行宽决定 —— 想对上就只能让它撑满，想不放大就只能把整块收窄（1920 以上
   两侧要空 58–198px，比 7% 的放大更扎眼）。取撑满。
   ⚠ 代价写在这里：这张图源文件只有 750×563，1920 下 1.07 倍、2560 下 1.25 倍插值。
     audit_look 的 H09 因此对这一个文件登记了例外（见 audit_look.mjs 的 NATIVE_SMALL），
     换成 1200 宽的同款实拍之后把那条例外删掉。 */
.db-main img{ display:block; width:100%; height:auto; aspect-ratio:4/3; object-fit:cover; object-position:50% 58%; }
.db-fig figcaption{ display:flex; justify-content:space-between; gap:16px; font-size:var(--fs-xs); color:var(--ink3); letter-spacing:.04em; padding-top:8px; margin-top:8px; border-top:1px solid var(--line); }
/* 文字栏只比主图矮一截，居中之后上下各留一点，不会全堆在顶上。
   左内缩 40：栅格间距只有 16，正文直接贴着主图右边会挤；
   缩进来以后右边缘仍与第 4 张实拍对齐，左边留出一道稳定气口。 */
.db-r{ grid-column:3 / span 2; align-self:center; padding-left:40px; }
.db-sub{ grid-column:1 / -1; margin:0; display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:16px; }
.db-sub picture{ display:block; }
.db-sub img{ display:block; width:100%; height:auto; aspect-ratio:4/3; object-fit:cover; }
.db-sub figcaption{ grid-column:1 / -1; display:flex; justify-content:space-between; gap:16px; font-size:var(--fs-xs); color:var(--ink3); letter-spacing:.04em; padding-top:8px; border-top:1px solid var(--line); }
.db-lead{ font-family:var(--serif); font-size:calc(var(--fs-h3)*var(--k)); font-weight:300; line-height:1.75; letter-spacing:.03em; text-wrap:balance; }
.db-lead b{ font-weight:500; }
.db-acts{ display:flex; align-items:center; gap:20px; flex-wrap:wrap; margin-top:28px; }
.db-acts .more{ display:inline-flex; align-items:center; min-height:32px; font-size:var(--fs-bs); border-bottom:1px solid var(--ink); padding-bottom:4px; }
.db-acts .more:hover{ color:var(--brand); border-color:var(--brand); }

/* ── 承接方与交付项目 ────────────────────────────────────────
   上面四步说的是「装修分几段」，这一段说的是「谁做、做过什么」。
   不放案例大图：品牌手册里的作品照只有 400px 宽，放大就是糊的，
   与其铺一墙糊图，不如把项目档案按账本排 —— 面积和工期本来就是客户最先问的两个数。 */

/* 四个事实横排。数字用宋体 300：和标题同一副字，比无衬线数字更像"资料"而不是"指标"。 */
/* 四个事实挪到右栏：它们和表格同高，本来被挤到 900px 之外，
   说明和数字之间空出半屏，读起来像两块不相干的东西。 */
.deco-facts{ display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:16px; }
.deco-facts li{ display:flex; flex-direction:column; gap:4px; }
.deco-facts b{ font-family:var(--serif); font-size:var(--fs-num); font-weight:300; line-height:1.1; font-variant-numeric:tabular-nums; letter-spacing:.01em; white-space:nowrap; }
.deco-facts em{ font-style:normal; font-size:var(--fs-sm); color:var(--ink3); margin-left:2px; }
.deco-facts span{ font-size:var(--fs-xs); color:var(--ink3); letter-spacing:.04em; }


.deco-cases{ margin-top:36px; }
.deco-ch{ margin-bottom:16px; }
.deco-ch h4{ font-family:var(--serif); font-size:var(--fs-lg); font-weight:500; letter-spacing:.04em; }
.deco-ch p{ font-size:var(--fs-sm); color:var(--ink3); line-height:1.75; margin-top:8px; }
/* 表 720 + 注释 1fr：两条都从同一根顶线上起，注释跟着表一起走 */
.dcgrid{ display:grid; grid-template-columns:minmax(0,720px) minmax(0,1fr); gap:88px; align-items:stretch; }

/* 乐企装九类服务：名字左、一句话右，行线跟台账同一族。
   行不可点，所以不加 hover 底色 —— 会让人以为能点进去看案例，点下去什么也没有。 */
.deco-scope{ border-top:1px solid var(--line3); }
.deco-scope li{ display:grid; grid-template-columns:112px minmax(0,1fr); gap:24px; align-items:baseline; padding:12px 0; border-bottom:1px solid var(--line2); }
.deco-scope b{ font-family:var(--serif); font-size:var(--fs-md); font-weight:500; letter-spacing:.02em; }
.deco-scope span{ font-size:var(--fs-bs); color:var(--ink2); }

/* 右栏撑到与左栏同高：注释比服务列表短一截时，底边一高一低，
   整块收尾像"话没说完"。落款推到最底部，正好压在列表最后一条线下。

   ⚠ 2026-10-21：这一条原来写的是全局 `.dside{height:100%}`，于是 60 个楼盘详情页
   的右栏（.dbody 里的 .dside）也被撑成整栏高度 —— 它的内容只有 650px，
   却被撑到 5780px，`position:sticky` 因此没有任何可滑动的余量，
   侧栏"钉死"在顶部、一滚就消失，右边连续 3.8 屏全白。
   撑高这件事只有装修页的 .dcgrid 需要（它要压住落款），所以只给它。 */
.dside{ display:flex; flex-direction:column; gap:24px; }
.dcgrid > .dside{ height:100%; }
/* 这四条数字下面的分隔线跟表格的行线差 12px，并排看就是两根对不上的线。
   右栏靠留白分段就够了，不需要再加一条。 */
.dside .deco-facts{ padding-bottom:0; }
.dnote{ max-width:32em; display:flex; flex-direction:column; flex:1; }
.dnote h5,.dnote h3{ font-family:var(--serif); font-size:var(--fs-base); font-weight:500; letter-spacing:.04em; }
.dnote p{ font-size:var(--fs-bs); color:var(--ink3); line-height:1.9; margin-top:8px; text-wrap:balance; }


/* ============================================================
   承诺（唯一深色带）
   ============================================================ */





/* 深底上的白字减一档会显断，这里要的就是 500。原来写 400 —— 浏览器映射到 500，
   看着一样，但代码在说谎，下一个人会以为这里比小标题轻。 */




/* ============================================================
   流程
   ============================================================ */
/* 六步原来是 3×2 的卡片网格：每格 30px 大编号 + 标题 + 正文竖排，一格 186px，
   六格 374px，整块 675px。问题是六块等大并列，读起来像"六段内容"，
   而这一段讲的恰恰是"先做什么、后做什么"。
   改成两列六行的编号条目：编号 | 标题 | 正文 在同一行，一步一行，
   顺序自上而下走得通，整块 675 → 445px（首页高度预算）。
   正文不另起一行、直接接在标题后面，是因为三列并排时正文列只剩 400 出头，
   34 字会被折成两行 —— 折了反而比一行更难扫。 */






/* ============================================================
   委托
   ============================================================ */
.cm{ display:grid; grid-template-columns:minmax(0,.82fr) minmax(0,1.18fr); gap:64px; align-items:start; }
.advg-h{ display:flex; align-items:baseline; justify-content:space-between; padding-bottom:8px; border-bottom:1px solid var(--ink); }
.advg-h h3{ font-family:var(--serif); font-size:var(--fs-base); font-weight:500; letter-spacing:.05em; }
.advg a{ display:grid; grid-template-columns:1fr auto; gap:8px; align-items:center; padding:12px 0; border-bottom:1px solid var(--line2); }
.advg b{ font-size:var(--fs-md); font-weight:700; letter-spacing:.03em; }
.advg .m{ display:block; font-size:var(--fs-sm); color:var(--ink3); margin-top:4px; line-height:1.75; }
.advg em{ font-style:normal; font-size:var(--fs-sm); color:var(--ink3); transition:color .25s var(--ease), transform .25s var(--ease); }
.advg a:hover em{ color:var(--ink); transform:translateX(3px); }

.faq{ margin-top:32px; }
.faq-h{ font-size:var(--fs-sm); color:var(--ink3); letter-spacing:.06em; padding-bottom:8px; border-bottom:1px solid var(--line); }
.faq dt{ font-size:var(--fs-md); margin-top:12px; display:flex; gap:8px; }
.faq dt::before{ content:"—"; color:var(--ink4); flex:0 0 auto; }
.faq dd{ margin:8px 0 0 24px; font-size:var(--fs-bs); color:var(--ink3); line-height:1.75; max-width:40em; }

.cf{ background:var(--white); border:1px solid var(--line); padding:32px 40px 24px; }
.cf-h{ display:flex; align-items:baseline; justify-content:space-between; gap:16px; padding-bottom:16px; border-bottom:1px solid var(--ink); }
.cf-h b{ font-family:var(--serif); font-size:var(--fs-num); font-weight:500; letter-spacing:.06em; }
.cf-h span{ font-size:var(--fs-sm); color:var(--ink3); }
.cf-grid{ display:grid; grid-template-columns:1fr 1fr; gap:0 32px; }
.cf-f{ position:relative; padding:12px 0 8px; border-bottom:1px solid var(--line); min-width:0; }
.cf-f.full{ grid-column:1/-1; }
/* 「补充说明」折叠区：它是这一栏的最后一行，下面不再需要分隔线 */
.cf-f.last{ border-bottom:0; padding-bottom:0; }
.cf-grid.tight{ margin-top:4px; }
.cf-f > label{ display:block; font-size:var(--fs-sm); color:var(--ink3); letter-spacing:.04em; }
.cf-f > label i{ font-style:normal; color:var(--brand); margin-left:4px; }
/* 选填提示跟着标签走：它是给「不敢填」的人看的退路，
   不能抢过字段名，但必须紧贴在同一个目光范围里 —— 放进 placeholder
   一敲字就消失，放进说明里没人读。颜色不用更浅一档的 ink4：
   11px 的灰字在纸上白底只有 2.8:1，等于看不见，用 ink3 靠字号收层次。 */
.cf-f > label span{
  margin-left:2px; font-size:var(--fs-xs); color:var(--ink3);
  letter-spacing:.03em; white-space:nowrap;
}
.cf-f input,.cf-f select,.cf-f textarea{
  width:100%; border:0; background:transparent; outline:none; font:inherit;
  font-size:var(--fs-base); color:var(--ink); padding:8px 0 4px; border-radius:0;
}
.cf-f select{ appearance:none; cursor:pointer; }
.cf-f.sel::after{
  content:""; position:absolute; right:4px; bottom:20px; width:5px; height:5px;
  border-right:1px solid var(--ink3); border-bottom:1px solid var(--ink3);
  transform:rotate(45deg); pointer-events:none;
}
.cf-f input::placeholder,.cf-f textarea::placeholder{ color:var(--ink3); font-size:var(--fs-md); }
.cf-f textarea{ resize:none; line-height:1.75; }
.cf-f:focus-within{ border-color:var(--ink); }
.cf-chips{ display:flex; flex-wrap:wrap; gap:8px; padding-top:12px; }
.ck{ display:inline-flex; }
.ck input{ position:absolute; opacity:0; width:0; height:0; }
.ck span{
  display:inline-flex; align-items:center; height:32px; padding:0 16px;
  border:1px solid var(--line); font-size:var(--fs-bs); color:var(--ink2); cursor:pointer;
  transition:background-color .2s var(--ease), border-color .2s var(--ease), color .2s var(--ease);
}
.ck input:checked + span{ background:var(--ink); border-color:var(--ink); color:var(--white); }
.cf-more{ padding:8px 0 0; }
.cf-more button{ min-height:32px; display:inline-flex; align-items:center; font-size:var(--fs-bs); color:var(--ink3); border-bottom:1px solid var(--line); padding-bottom:2px; }
.cf-more button:hover{ color:var(--ink); border-color:var(--ink); }
.cf-sub{ display:flex; align-items:center; justify-content:space-between; gap:20px; margin-top:16px; flex-wrap:wrap; }
.cf-sub button[type=submit]{
  /* 圆角跟着按钮令牌走（2026-11-02 上线前核查）：这里原本写 --r-1(2px)，
     而全站 .btn 都是 --r-btn(3px)。同一站两种按钮圆角，单看哪一个都正常，
     并排看就像两套组件库拼的。高度 48 保留 —— 表单提交是这一页的主操作，
     比列表页的 44 高一档是有意的，圆角不是。 */
  height:48px; padding:0 36px; background:var(--ink); color:var(--white); border-radius:var(--r-btn);
  font-size:var(--fs-md); letter-spacing:.06em; transition:background-color .25s var(--ease);
}
/* 悬停拉字距（原来 .12em → .16em）会让按钮文字整体右移、左边的字被挤出去，
   而且和「按下」这件事没有任何关系。悬停只变底色。 */
.cf-sub button[type=submit]:hover{ background:var(--ink-press); }
.cf-note{ font-size:var(--fs-sm); color:var(--ink3); line-height:1.75; max-width:280px; }
.cf-err{ font-size:var(--fs-sm); color:var(--brand); margin-top:8px; }
.cf-done{ padding:20px 0 8px; }
/* 回执标题里嵌着客户称呼：<b> 走的是浏览器默认 700，而宋体最重只有 500，
   于是「已记下，张总的需求」里的名字是算法硬加粗的，笔画会糊在一起。
   跟 .db-lead 一样：正文退 300，名字用真 500，强调才立得住。 */
.cf-done h3{ font-family:var(--serif); font-size:var(--fs-h3); font-weight:300; letter-spacing:.04em; margin-top:8px; }
.cf-done h3 b{ font-weight:500; }
.cf-done p{ font-size:var(--fs-md); color:var(--ink2); line-height:1.9; margin-top:12px; }
.cf-done .again{ margin-top:24px; font-size:var(--fs-bs); color:var(--ink2); border-bottom:1px solid var(--ink4); padding-bottom:2px; }
.cf-done .again:hover{ color:var(--ink); border-color:var(--ink); }
/* 失败回执：与成功回执同版式，只把标签换成品牌红。
   不弹窗、不抖屏 —— 客户刚填完一屏字，最怕的是「失败了，重新填」。
   这一版只是把实情写清楚，并把电话做成可点。 */
.cf-fail .lat{ color:var(--brand); }
.cf-fail p a{ display:inline-flex; align-items:center; min-height:44px;
  color:var(--brand); text-decoration:underline; text-underline-offset:4px; }

.adv{ display:grid; grid-template-columns:1fr 1fr; margin-top:36px; border-top:1px solid var(--ink); }
.adv li{ padding:20px 24px 20px 0; border-bottom:1px solid var(--line2); }
.adv li:nth-child(2n){ padding-left:24px; padding-right:0; border-left:1px solid var(--line2); }
/* 2026-10-23：这两行原来是 14 / 12，标题与正文只差 2px，层级几乎读不出来，
   正文 12px 又是全页最小的字——它可是这一节唯一的说明文字。
   抬到 17 / 14，并把正文从 --ink3 提到 --ink2：12px 的浅灰在 1440 上发虚。 */
.adv h3{ font-size:var(--fs-lg); font-weight:700; letter-spacing:.03em; }
.adv p{ font-size:var(--fs-md); color:var(--ink2); line-height:1.75; margin-top:8px; }
/* 2026-11-02：条目为奇数时（关于页「核心优势」按品牌手册列五条），
   最后一条会独占左列、右边空出一格 —— 两列的竖线在最后一行断掉，
   看起来像漏了一条。让它跨满两列，底线照样收口。
   只在「最后一条又是奇数位」时生效，四条时不动。 */
.adv li:last-child:nth-child(odd){ grid-column:1 / -1; }


/* ============================================================
   内链矩阵 + 页脚
   ============================================================ */
.matrix{ display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:48px; }


.mx{ display:flex; flex-wrap:wrap; gap:0 24px; }
.mx a{ font-size:var(--fs-bs); color:var(--ink2); padding:4px 0; }
.mx a:hover{ color:var(--brand); }

/* 页脚顶边改成双线（v3.1）：2px 墨线 + 1px 细线，中间留 6px。
   全站只有这一处用双线 —— 年鉴与报纸用它在「正文结束、索引开始」的位置做断句，
   一条 1px 的灰线做不到这件事：它和页面里十几次分段线长得一样，
   客户滑到底不知道自己在看索引。

   实现用 border-top + 多重背景，不用伪元素：两条线一层画完，
   没有盒模型参与，也不会和页脚自己的 background 抢层叠顺序。
   （伪元素那版其实也是对的 —— 一度以为它没渲染，后来 2x 裁剪截图证明
     线在，只是 element screenshot 从 border-box 顶部起、又被缩放压缩了。
     但「两层边框 + 一层背景」这种写法出问题时要查三件事，
     而多重背景只查一件，所以留下这版。） */
.ft{
  --ft-line:linear-gradient(var(--line3),var(--line3));
  background:var(--ft-line) 0 6px / 100% 1px no-repeat, var(--paper2);
  border-top:2px solid var(--ink); padding:56px 0 28px;
}
/* ── 页脚第三版（2026-10-27）─────────────────────────────────
   前三版走过的弯路：
     v1 六列 37 条纯罗列 —— 无列标题、无合规区，太密；
     v2 砍成「品牌 + 一个下拉」—— 太薄，缺了中文网站页脚最要紧的
        合规资质区，看着像个人站。
   形态是按 20 个真实门户量出来的（京东 61 条 / 5 列 / 546px，
   携程 43 / 5 / 453，58 同城 50 / 5 / 462，房天下 56 / 4 / 461，
   迈点 16 / 3 / 504，界面新闻 8 / 1 / 50）：主流是 5 列导航矩阵，
   每列都有标题、每列 4–7 条，下面是合规区与版权行。
   对应到本站：品牌 + 按区域 + 按地铁 + 服务 + 租赁知识 + 联系。
   14 个区只放 7 个（余下走「全部」），18 条线整条放不下 ——
   所以那一列用线路 / 站点两级下拉，这正是「放不下的做下拉」。
   列模板仍由生成器按实际栏数写进 --ftc（空库时只有三列）。 */
/* 2026-10-28：六列改成「品牌列 + 五等分」。
   原来按内容给每列配了比例（1.3 / .82 / 1.05 / .86 / .86 / 1），
   实测列宽是 153 / 195 / 160 / 160 / 186 —— 五列五个宽度，
   右边缘一条一条参差，"按区域找楼"最窄、"按地铁"最宽，
   看着像五张随手摆的清单。改成品牌列 1.35fr、其余五列各 1fr：
   实测 237 / 176×5，五个链接列的左右边缘落在同一组栅格上。
   175 够不够住内容：联系列的 21 字邮箱约 145px、地址约 155px，
   地铁列的下拉 100% 宽、按钮文案「查看在租楼盘 →」约 112px —— 都留有余量。 */
.ft-top{
  display:grid;
  /* 2026-11-02 五列（原六列，删掉「按地铁找楼」整列 —— 见 gen_site.js footer()
     的第五版注释）。默认值的兜底写法必须与产物里的 inline --ftc 一致，
     否则任何忘记写 inline 的页面会长成另一套列宽。 */
  grid-template-columns:var(--ftc, 1.1fr 1fr 1fr 1fr 1.1fr);
  /* 2026-11-02：start → stretch。
     老板这次的验收是「列底对齐」。四列的条目数已经都是 5，但内容长度不一样：
     「联系」列有 21 字的邮箱和 17 字的营业时间，320–375 下必然折行，
     于是它比旁边三列高出一行（9.5px）甚至三行（28.5px）。
     光靠删项对不齐 —— 只能让**同一行的列等高**，再把多出来的空白均分到条目之间
     （见下方 .ft-col > ul 的 space-between）。桌面四列本来就等高，这一条在桌面无效果。 */
  gap:32px 40px; align-items:stretch;
}
/* 列内不加分隔线：京东、携程、58 同城的页脚都没有横线，
   靠列标题的字重与 28px 行距分隔就够。 */
.ft-col{ position:relative; }
/* 2026-11-02：等高列 + 均分留白。
   .ft-col 变成纵向 flex，ul 吃掉剩余高度后在条目之间均分多出来的空白，
   于是**每一列的末项都落在同一条线上**，不管那一列的文字折了几行。
   320 下「联系」比别的列高 28.5px，均分到 5 个间隙是每个 5.7px —— 看不出来；
   而列底不再参差。桌面四列本来就一样高，flex 没有多余空间可分配，等于没改。 */
.ft-col{ display:flex; flex-direction:column; }
.ft-col > ul{ display:flex; flex-direction:column; justify-content:space-between; flex:1 1 auto; }
/* 列底的「全部 →」出口提到列标题行右端（2026-10-28）。
   它原来挂在清单最后一项下面，于是五列的下沿变成这样：
   区域列 8 项、服务 6 项、知识 5 项、联系 5 项 —— 列底差 115px，
   最左一列整整比旁边多出两行，整块像被斜着切了一刀。
   出口是「这一列还有更多」的补语，本来就该跟列标题同一行，
   不该在列尾给自己占一行。绝对定位不占列高，列高就只由条目数决定；
   列宽 176 下「按区域找楼」(60px) + 出口(81px) = 141，不重叠。
   ⚠ 760 断点里出口要 40px 高（触摸目标），那时靠 .ft-h 的 min-height:40px
   把它托住，否则会压到第一项上。 */
.ft-col .ft-more{ position:absolute; right:0; top:0; }
.ft-brand .wm{ font-size:var(--fs-bs); font-weight:700; letter-spacing:.2em; text-transform:uppercase; }
/* 2026-10-24：公司名与简介从「一段 + <br>」改成两个段落。
   原因（实测，见 _dev/_probe_ft2.mjs）：<br> 会让 text-wrap:balance **整块失效** ——
   220 / 190 / 350 三档列宽下，balance 打开与关闭的断行一位都没动，
   于是 1440 下每页页脚的第二句永远是「…2019 年成立于上」/「海。」，
   把「上海」这两个字拆在行尾，全站 3,676 个页面每页一条孤字。
   拆成两个段落（第二句里没有强制换行）之后 balance 恢复工作：
   220px 下 59% / 69%，190px 下 68% / 80%，都不再有 30% 的尾巴。
   `p + p` 的间距收到 2px —— 两句本是一段话，16px 会把它们拆成两条信息。 */
.ft-brand p{ text-wrap:balance; }
.ft-brand p + p{ margin-top:4px; }
.ft-brand p{ font-size:var(--fs-bs); color:var(--ink3); margin-top:8px; line-height:1.9; max-width:280px; }
/* 2026-10-28：品牌列的第一行文字原来比五列的第一项低 27px。
   底盘是 `.logo` 的 min-height:44（那是给全站导航栏留的触摸盒），
   页脚把它一起继承了：44 + 16px 外边距 = 60，而其它列是「21px 标题 + 12px」= 33。
   页脚里 logo 只是块标识，不是主导航，32px 的图本身就够 24 的触摸底线；
   去掉 min-height（图上下的 6+6 留白）并把外边距收到 8，
   文字起点落到 8257，与各列首项 8250 只差 7px —— 13px 字号下是半个字，
   看上去就是同一条线了。 */
.ft-brand .logo{ min-height:0; padding:6px 0; margin:-6px 0; }
/* ── 品牌标语（2026-11-02 老板定稿：中文主张 + 英文同句）──────────────
   这位置原来放「上海写字楼招商代理 / 2019 年成立于上海」，两行都是资料；
   换成一句主张之后，它是页脚唯一一句「我们想做成什么样」，因此给它
   比原来的 13px 高一档、比 --ink3 深一档，英文小一档做辅注 —— 两句话
   说的是同一件事，中文字号更大只是因为中文更短，不是因为中文更重要。
   排版三条约束，缺一条就会难看：
     ① 左缘与 logo 图形左缘同一条线（都在 .ft-brand 的内容盒里，不额外缩进）
     ② 中文 19 字 / 英文 79 字符，两档列宽下都必然折行 → 都开 text-wrap:balance，
        否则第一行顶满、第二行只剩两三个字（2026-10-24 那次每页一条孤字）
     ③ 中英之间 5px，不再用 4px 的 `p + p` —— 那是原来「两句资料」的间距，
        换成语种不同的两句之后要稍微松开一点
   英文那句是品牌主张的对外版，按原样排（不缩写成 all-caps，也不加引号）。 */
.ft-brand .ft-slog{ margin-top:10px; max-width:290px; }
.ft-brand .ft-slog-cn{
  font-size:var(--fs-md); line-height:1.65; color:var(--ink2);
  letter-spacing:.01em;
}
/* 中文这句在品牌列（1440 下约 240px）里放不下一行，折行是必然的。
   交给浏览器的 balance 会断在「最受 / 信赖」中间 —— 一个词被拆开，
   读起来像排错了。所以按逗号切成两段，每段 nowrap：
   容器够宽时仍然一行（手机 328px 放得下 322px 的整句），
   不够时只在逗号后面断，两行各自完整。 */
.ft-brand .ft-slog-cn span{ white-space:nowrap; }
.ft-brand .ft-slog-en{
  margin-top:5px; font-size:var(--fs-xs); line-height:1.55; color:var(--ink3);
  letter-spacing:.005em; text-wrap:balance;
}
/* 页脚分组标题：2026-10-23 从 h3 改成 h2（.ft-h）。
   原因是页面结构是 h1 → （无 h2）→ 页脚 h3，标题数组跳了一级；
   页脚这几列本来就是与正文并列的一级分组，不是正文的子节。
   选择器保留 .ft h3 是为了兼容尚未重新生成的旧产物。
   2026-10-27：颜色从 --ink3 提到 --ink。原来标题 12px 浅灰、条目 13px 中灰，
   标题比它管着的条目还浅 —— 层级是反的，远看五列各有六七个浅色小字，
   分不出哪是组名。中文门户（京东 / 携程 / 58 同城）的列标题都比条目重。 */
.ft h3, .ft h2.ft-h{ font-size:var(--fs-sm); font-weight:700; letter-spacing:.04em; color:var(--ink); margin-bottom:12px; }
/* ── 页脚行距（2026-10-26 收紧）────────────────────────────────
   原来每项是 32px 可点高度 + 8px 下边距 = 40px 一行，区域列 10 项就是 400px，
   页脚整块 656 高：字号只有 13px，行距却有 40px，远看是一列列松散的词。
   更麻烦的是五列条目数 10 / 8 / 7 / 8 / 5 各不相同，各列长度差最多五行，
   而且「全部 N 个区 →」这种出口链接挂在每列最后一项上，落点参差 ——
   整块看起来像五张没对齐的清单。
   改法：行距收到 30px（28 可点 + 2 下边距），并把四条「全部 →」从列表末尾
   提到列标题右端（.ft-more）。列里只剩纯条目，列与列的第一行、行距、字重
   全部一致，剩下的长度差落在底部，不再把出口链接顶得到处都是。 */
.ft li{ margin-bottom:4px; }
/* 页脚分组标题右侧的「全部」出口：与标题同一基线，不抢标题的字重 */
.ft h2.ft-h{ display:flex; align-items:baseline; justify-content:space-between; gap:8px; }
.ft-more{
  flex:none; font-size:var(--fs-sm); letter-spacing:0; font-weight:400;
  color:var(--ink3); text-decoration:none; white-space:nowrap;
  /* WCAG 2.2 SC 2.5.8 触摸目标 ≥24×24 CSS px（2026-10-26 DEEP-1026 补）。
     12px 字号下这里只有 21px 高，首页 15 档适配闸门在**全部 15 个宽度**上报
     「热区<24 6 个（ft-more:21）」——六个「全部」出口链接全都差 3px。
     用 min-height 而不是 padding：父级 .ft-h 是 align-items:baseline，
     加 padding 会把「全部」往下推、与分组标题错开基线。
     inline-flex + center 让它自己居中，outer 高度就是 24。 */
  display:inline-flex; align-items:center; min-height:24px;
}
.ft-more:hover{ color:var(--brand); }
/* 2026-10-27：手机上把「全部」出口抬到 40 高。
   桌面 24 是 WCAG 2.2 SC 2.5.8 的 AA 底线，但移动端的实际手指落点是 40+；
   排版取证在 6 档宽度里每次都把它记成「点击区过小」（42×24 / 24×24，共 149 条）。
   同时必须把 .ft-h 的基线对齐改成居中 —— min-height 撑高后，baseline 会把
   分组标题和「全部」错开 8px（这正是 10-26 用 min-height 而不是 padding 的原因，
   那条约束在移动档要换个解法：两边都居中）。 */
@media (max-width:760px){
  /* min-height:40 是给绝对定位的出口托底的：出口在 760 以下要 40 高才按得准，
     而它现在贴在列标题行右端，标题行只有 21 高就会压到第一项（实测差 19px）。
     把标题行撑到 40，出口正好落在里面；顺带五列标题行统一定高，
     手机上各列的第一项也就落在同一条线上了。 */
  .ft h2.ft-h{ align-items:center; min-height:40px; }
  .ft-more{ min-height:40px; }
}
/* 360–400px：两列并排时每列只有 148–158 宽，「按区域找楼」(60) 与
   「全部 14 个区 →」(81) 加起来正好顶满，实测 360 下两个字咬在一起 1px。
   箭头是 aria-hidden 的纯装饰（`.ft-more span`），窄屏去掉它省 13px，
   链接文字与目标都不变 —— 比缩小字号好：11px 会跌破全站 11.5px 的字号底线。 */
@media (max-width:400px){
  .ft-more span{ display:none; }
}

/* ⚠ 2026-10-26 DEEP-1026：移动端底部转化条 `.mcta` 必须在这里先隐藏。

   beauty.css:613 写着 `.mcta{display:none}`，然后 @media (max-width:760px)
   里才 display:grid + position:fixed。问题在于**首页根本不加载 beauty.css**
   （只引 fonts/tokens/ed 三层），于是那条隐藏规则在首页从未生效：
   两个子链接「致电顾问」「填写需求单」以无样式 inline `<a>` 裸露在页面底部，
   `.ic-i` 图标 17px、行高 20px。
   实测：adapt.js 在 15 个宽度上全报「热区<24 2 个（A:20·75w·「致电顾问」,
   A:20·90w·「填写需求单」）」，而 className 为空让报错只显示 `A:20`，
   查了半天不知道是谁。

   顺带暴露一个设计缺口：首页在手机上也从来没有这条转化条，因为它整套样式
   都在 beauty.css 里。这里只补「该隐藏就隐藏」，不把移动端样式搬过来
   （那属于版式改造，不该混在闸门修复里）。 */
.mcta{ display:none; }
/* overflow-wrap：页脚「联系」一栏现在有三串长内容（手机、邮箱、地址），
   两栏布局下每栏只有一百多像素，21 字的邮箱在 13px 下正好卡在边缘。
   不加会在窄屏撑出横向滚动条 —— 那是整站最容易被忽略的一处破版。 */
.ft li a{ display:inline-block; padding:4px 0; font-size:var(--fs-bs); color:var(--ink2); overflow-wrap:anywhere; }
/* 2026-11-02：「联系」列比其余四列矮 9px，肉眼能看出下沿不齐。
   原因是这一列最后两项（地址、营业时间）是裸 <span>，不走 `a` 的规则 ——
   桌面差 9px，手机差 26px。四列都改成 5 项之后这个差值才露出来
   （原来区域/服务 6 项正好把差值盖住）。
   这里把 span 设成与 `.ft li a`（1691 行那条 inline-flex + min-height:28）
   完全同构，五列下沿就落在同一条线上。只选直系 span —— `.ft-more` 里的
   `<span aria-hidden>` 箭头在标题行、不在 li 里，不受影响。 */
.ft li > span{ display:inline-flex; align-items:center; min-height:28px; padding:4px 0; font-size:var(--fs-bs); color:var(--ink2); overflow-wrap:anywhere; }
.ft li a:hover{ color:var(--ink); }
/* 2026-11-02：邮箱只在 <wbr> 处断。
   上面 `.ft li a` 的 `overflow-wrap:anywhere` 会在任意两个字符之间造断点，
   而换行算法取的是「能放下的最后一个断点」—— 于是 360 手机（列宽 142.5）上
   21 字的邮箱断成「Randyfan@vanshidc.c」+「om」，尾巴两个字母单独一行。
   生成器已在 @ 前插了 `<wbr>`，但任何处可断会直接盖过它；
   这里只对 mailto 关掉 anywhere，断点就只剩 @ 那一个：
   「Randyfan」/「@vanshidc.com」，两段都放得下（320 的 122.5 也放得下）。
   桌面列宽 218 不触发，等于没改。 */
.ft li a[href^="mailto:"]{ overflow-wrap:normal; }
/* 页脚那一列里，链接默认比正文浅（a 用 ink2、纯文本继承 ink）——
   于是手机号看着比地址还弱。号码是这一栏唯一能当场接通的东西，
   拉回 ink 并给 tabular-nums，11 位数字才不会在细体里串行。 */
.ft li a.ft-tel{ color:var(--ink); font-weight:700; font-variant-numeric:tabular-nums; letter-spacing:.02em; }
.ft li a.ft-tel:hover{ color:var(--brand); }
/* ── 页脚：按地铁找楼（2026-10-27 第三版，列内竖排）──────────────
   ⚠ 2026-11-02 起这一段没有使用者了：整个「按地铁找楼」列已从页脚删除，
     理由见 gen_site.js footer() 的第五版注释。留着不删是为了回滚时
     不用重写样式；新代码不要引用 .ft-metro / .ft-go / .ft-sel-b。
   ── 以下为当初的设计记录 ──
   v2 把这一块横铺成页脚下方的一条通栏（标题 + 两个下拉 + 按钮），
   结果是页脚被切成「上面几列 / 下面一条表格」，不像一份导航。
   v3 把它收回「按地铁找楼」这一列内部：18 条线本来就放不进一列，
   两个下拉竖排、整列等宽，读起来就是一列导航的延伸。
   线路与站点是全站唯一的两级联动入口，给它一整列不算浪费。 */
.ft-metro{ display:flex; flex-direction:column; gap:8px; }
.ft-metro .ft-sel-b{ display:block; }
.ft-metro select{
  appearance:none; -webkit-appearance:none;
  width:100%; height:40px; padding:0 32px 0 12px;
  border:1px solid var(--line3); border-radius:var(--r-1);
  background:var(--white); color:var(--ink);
  font:inherit; font-size:var(--fs-bs); cursor:pointer;
  transition:border-color .2s var(--ease);
}
.ft-metro select:hover:not(:disabled){ border-color:var(--ink4); }
.ft-metro select:focus-visible{ outline:2px solid var(--brand); outline-offset:1px; border-color:var(--ink); }
/* 站点未解锁时是「先选择线路」的灰条：disabled 的 select 在 Chrome 里
   仍然可点但打不开，光靠这一点用户看不出来，得把颜色压下去。 */
.ft-metro select:disabled{ color:var(--ink4); background:var(--paper2); cursor:not-allowed; }
/* 箭头用两条边框画（而不是背景 SVG）：颜色跟 --ink3 走，
   不必在 url() 里写死一个十六进制值 —— 换令牌时这里不会掉队。 */
.ft-sel-b{ position:relative; display:inline-flex; }
.ft-sel-b::after{
  content:""; position:absolute; right:13px; top:50%; width:6px; height:6px;
  border-right:1px solid var(--ink3); border-bottom:1px solid var(--ink3);
  transform:translateY(-72%) rotate(45deg); pointer-events:none;
}
.ft-metro .ft-sel-b:has(select:disabled)::after{ opacity:.45; }
.ft-go{
  display:flex; align-items:center; justify-content:center; gap:8px;
  width:100%; height:40px; padding:0 8px;
  background:var(--ink); color:var(--white);
  font:inherit; font-size:var(--fs-bs); font-weight:700;
  border:0; border-radius:var(--r-1); cursor:pointer;
  transition:background-color .2s var(--ease);
}
.ft-go:hover{ background:var(--brand); }
.ft-go span{ font-family:var(--en); }

/* ── 页脚合规区（2026-10-27）────────────────────────────────────
   中文网站的页脚不能只有版权行。京东、携程、58 同城都把营业执照、
   ICP 备案、经纪机构备案、举报入口放在版权行同一带 —— 这是「一家
   正规公司」在页面上的唯一凭据，也是 v2 被判定「改坏了」的主因：
   那一版整块页脚只剩品牌与联系，看着像个人主页。
   备案号没下来之前只留生成器里的注释位，页面上不出现假号 ——
   印一串查不到的号码，比留空更伤可信度。 */
.ft-legal{
  display:flex; flex-wrap:wrap; align-items:center;
  /* 2026-10-28：三组从「版权贴左 + 合规紧跟着 + 导航贴右」改成两端对齐。
     原来是 .links 挂 margin-left:auto，实测版权占 65–364、合规占 387–713、
     导航占 1055–1361 —— 合规和导航之间空出 342px，而前面只隔 23px。
     一行里两组挤在一起、中间一大段白，是页脚最显眼的"没排版"。
     space-between 让三段的间隙相等（各约 170px）。 */
  justify-content:space-between;
  gap:8px 24px;
  margin-top:44px; padding-top:20px; border-top:1px solid var(--line);
  font-size:var(--fs-sm); color:var(--ink3);
}
/* 三组盒子原来各是各的高度：版权 21（纯文本行盒）、合规 24（inline-flex 撑的）、
   导航 32（min-height 撑的）。垂直居中排在一行时，文字基线看着齐、
   鼠标划过却各自抖一下，量出来是三组不同的中线。
   统一成 32 并把内容居中：三组的文字落在同一条基线上。 */
/* 2026-11-02：版权行里加了备案号之后，`.ft-copy` 的 `display:flex` 就撑不住了。
   flex 会把「© 」「<span data-year>」「公司名…保留所有权利」「<i class="sep">」
   「<a class="ft-icp">」拆成五个独立的 flex item，窄屏一放不下就各自换行、
   各占一段，实测 390 下变成：
       ©2026    上海万仕行房地产经纪有限公司    沪ICP备
                保留所有权利                   2021010785号-1
   四块错位。改回普通块级：文字按正常行流排，换行自然发生在词间；
   垂直居中由父级 .ft-legal 的 align-items:center 负责，不需要自己 flex。 */
.ft-copy{ flex:none; display:block; min-height:32px; }
.ft-copy .sep{ font-style:normal; color:var(--line3); margin:0 8px; }
.ft-copy .ft-icp{ display:inline-flex; align-items:center; min-height:24px; color:var(--ink3); white-space:nowrap; }
.ft-copy .ft-icp:hover{ color:var(--ink); }
/* 手机上版权行放不下一行：实测 390 下「…保留所有权利 ·」占满第一行，
   分隔点正好悬在行尾，备案号被挤到第二行开头 —— 那个孤零零的点看着像
   标点用错了。这里让备案号自己独占一行（block），同时把分隔点收掉，
   两行各归各的，比挂一个点在行尾干净。 */
@media (max-width:760px){
  .ft-copy .sep{ display:none; }
  .ft-copy .ft-icp{ display:flex; }
}
/* `.ft-rec` 现已无元素使用，样式留着供回滚（第四版有那一行）。 */
.ft-rec{ display:flex; flex-wrap:wrap; align-items:center; gap:4px 8px; min-height:32px; }
.ft-rec i{ font-style:normal; color:var(--line3); }
/* 24 是 WCAG 2.2 SC 2.5.8 的 AA 底线。这三个是 <p> 里的 <a>，
   不走 `.ft li a` 那条 28px，默认只有 21px —— adapt.js 在 15 档里
   每一档都报「热区<24 3 个（营业执照公示 / 房地产经纪机构备案 /
   违法与不良信息举报）」。inline-flex + min-height 而不是 padding：
   行盒居中，加了 padding 会把这一行撑高、与版权行错开。 */
.ft-rec a{ display:inline-flex; align-items:center; min-height:24px; color:var(--ink2); }
.ft-rec a:hover{ color:var(--ink); }
.ft-legal .links{
  display:flex; flex-wrap:wrap; align-items:center; gap:2px 18px; min-height:32px;
}
.ft-legal .links a{ display:inline-flex; align-items:center; min-height:32px; padding:4px 0; }

/* 页脚每个链接都是从属入口，桌面端也要有 28px 的可点高度（行距收紧后：
   28 + 2 = 30px 一行）。低于 28 时鼠标在字缝里点会落空。
   带图标的 li（.ico-li）在 beauty.css 里另有 display:flex 的规则，这里不覆盖它。
   ── 页脚的触控高度阶梯只有这一份（2026-11-02 统一）──────────────
   基准 28（桌面，盒子实际 32）/ ≤760 抬到 44（手指）。`a` 与裸 `span` 必须同档，
   因为「联系」列里地址、营业时间是 span，电话、邮箱、需求表是 a ——
   一列里两种行距混排，列底就差出来（实测 761–980 差 24px、手机差 26px）。
   注意 28 只是下限：内容 24 + padding 8 已经 32，所以桌面实测都是 32。

   ⚠ 这条**必须写在下面的断点之前**。2026-11-02 第一次修时它留在断点之后，
   于是 `@media (max-width:760px){ .ft li a{min-height:44px} }` 被同一份文件里
   更靠后的这条（同特异性）压回 28 —— 其它页由 beauty.css 的 760 断点兜住，
   首页不引 beauty，实测 320–400 全是 30.8px，判据一眼就红。 */
.ft li a{ display:inline-flex; align-items:center; min-height:28px; }

/* ── 页脚断点（必须写在这里，不能写 beauty.css）──────────────────
   首页只引 tokens + ed 两层。把列模板写在 beauty.css 里时，
   首页的 `.ft-top` 拿不到任何断点，390 下六列被 1fr 压成每列 13px，
   整页 scrollWidth 492（视口 390）—— 横向溢出。
   2026-10-27 实测踩过，别再挪走。 */
@media (max-width:1240px){
  /* 2026-11-02：六列 → 五列之后，这里也必须从 3 列改成 4 列。
     改之前是「品牌横条 + 5 个链接列」在 3 列栅格里排成 3+2；
     删掉地铁列后剩 4 个链接列，仍用 3 列就会排成 3+1 —— 第二行只有一列
     贴左墙、右边空两格，比原来的 3+2 更不平衡。4 列栅格里品牌横条占满
     首行，四个链接列正好一行排完，行数从两行降到一行。
     品牌改成横条占满首行：留在格子里时它只有 138 高，
     而右边「按区域找楼」有 6 项，把整行撑高 —— 品牌底下空出一大块白，
     看着像漏了一块。 */
  .ft-top{ grid-template-columns:repeat(4,minmax(0,1fr)); gap:28px 24px; }
  .ft-brand{ grid-column:1/-1; display:flex; align-items:center; flex-wrap:wrap; gap:8px 32px; }
  .ft-brand .logo{ flex:none; }
  .ft-brand p{ margin-top:0; max-width:none; }
  /* 1160 以下品牌列变成横条（logo 在左、文字在右），标语块要作为**一整块**
     参与这条 flex：两句之间仍上下排，不许被拆到 logo 两侧。
     margin-top 归零 —— 横条里是 align-items:center 居中的，留 10px 会让
     中文比 logo 中心低半行，看上去像没对齐。
     flex-basis 260 + min-width:0：390 屏版心 350，减 logo 42 与 32 间隙
     还剩 276，正好让中文 19 字落在同一行、英文折两行。 */
  .ft-brand .ft-slog{ flex:1 1 260px; min-width:0; max-width:none; margin-top:0; }
  /* 底部合规行在 1240 以下改成竖排三行、左对齐（2026-10-28）。
     实测 1024 下三组横排要 292 + 326 + 306 + 两个 24 间隙 = 972，
     而版心只有 960 —— 差 12px 挤不进一行，flex-wrap 就把「关于万仕行 /
     联系我们 / 工具 / 站点地图 / 回到顶部」整组甩到第二行最左边，
     于是第一行两组分在两端、第二行一组贴着左墙，右边空出半屏。
     三行各自左对齐，行距 2px，读起来是一条清单，比"两行且第二行孤零零靠左"干净。
     1440 下三组仍是一行 space-between（那里的版心放得下，间隙各约 186px）。 */
  .ft-legal{ flex-direction:column; align-items:flex-start; gap:2px; }
}
/* 2026-11-02：900 以下收成两列（2×2）。
   4 列在 761–900 这段每列只有 160–190px：实测 768 下「联系」列整块折行，
   高 258.5，而旁边三列都是 213 —— 差 45.5px，正是老板最在意的「不对齐」。
   两列之后每列 340 上下，邮箱和营业时间都放得下，四列重新等高。
   1240 断点的 4 列保持不变：1024 实测四列各 218，只差 2.5px。 */
@media (max-width:900px){
  .ft-top{ grid-template-columns:repeat(2,minmax(0,1fr)); gap:26px 20px; }
}
@media (max-width:760px){
  /* 手机两列：一栏到底会让二十来条链接各占一行，页脚 1200px 起。
     2026-11-02 删掉「按地铁找楼」列后，四个链接列在两列栅格里正好 2×2，
     不再有原来那个跨两列、必须 order 到最后的 .ft-col-wide。 */
  .ft-top{ grid-template-columns:repeat(2,minmax(0,1fr)); gap:26px 20px; }
  /* 2026-11-02：`<span>` 的 44px 只给手机，不给平板。
     页脚 5 项里「地址」「营业时间」是裸 span，「电话/邮箱/需求表」是 a。
     两者的触控高度阶梯必须**同一条**，否则同一列里两种行距混排，列底就差出来：
       · >760  → a 由 beauty.css 的 `.ft li a{min-height:32px}` 定在 32
                 （那条是无条件规则、后加载，把 ed 980 断点里的 44 压掉了）
       · ≤760  → a 由 beauty.css 的 760 断点抬到 44
     所以 span 也照这个来：默认与 a 同为 32，≤760 抬到 44。
     踩过的错：一开始把 span 补进了 ed 的 `@media (max-width:980px)` 那条 44 规则里，
     于是 761–980 这段变成 a=32 / span=44 —— 768 下「联系」列比旁边三列高 24px
     （每列 5 项 × 2 个 span × 12px）。980 那条对 a 本来就是死的，不能拿它当基准。 */
  .ft li > span{ min-height:44px; }
  /* a 的 44 也必须写在这里：其它页由 beauty.css 的 760 断点给，但首页不引 beauty，
     漏了这一条首页在手机上就只有 32（桌面档），比 span 矮 12 —— 同一列里两种行距。 */
  .ft li a{ min-height:44px; }
  .ft-brand{ grid-column:1/-1; }  /* 横条在 335px 下只剩三句话挤一行，会断成「…2019 年成」这种半句，退回竖排 */
  .ft-brand{ display:block; }
  .ft-brand p{ margin-top:16px; }
  .ft-brand p + p{ margin-top:4px; }
}
.ft-bot .links{ display:flex; flex-wrap:wrap; gap:4px 20px; }
.ft-bot .links a{ display:inline-flex; align-items:center; min-height:32px; padding:4px 0; }

/* ---------------- 首页：五项业务目录 .sv5 ----------------
   2026-10-27 重做。原来是五等分的格子（每格 288px），说明文字折成 2–3 行不等，
   五格底边参差，读起来像一张没对齐的表格；五项全部带「业主侧 / 带看时」这类
   口头语，也就没有一条能写满。
   改成五行目录：名称 / 一句说明 / 箭头，三列固定，逐行对齐。
   商务文书里的目录写法，比五张并排的卡片安静，也让每项都能写完整。 */
.sv5-h{ display:flex; align-items:baseline; justify-content:space-between; gap:16px 32px; flex-wrap:wrap; padding-bottom:16px; border-bottom:1px solid var(--ink); }
.sv5-h h2{ font-family:var(--serif); font-size:calc(var(--fs-h3) * var(--k)); font-weight:500; letter-spacing:.03em; }
.sv5-h .more{ display:inline-flex; align-items:center; min-height:32px; font-size:var(--fs-bs); color:var(--ink2); white-space:nowrap; padding-bottom:4px; border-bottom:1px solid var(--ink4); transition:border-color .25s var(--ease), color .25s var(--ease); }
.sv5-h .more:hover{ color:var(--brand); border-color:var(--brand); }
.sv5{ display:block; border-top:1px solid var(--line2); }
.sv5 li{ border-bottom:1px solid var(--line2); }
.sv5 li:last-child{ border-bottom:0; }
/* 负 margin 让 hover 底色铺到容器边线之外，整行读起来像被翻出来的一行，
   而不是中间浮着一块灰。 */
/* 列宽写死而不是用 fr 分：名称最长「企业资产管理」6 字（6×20 ≈ 120px），
   用比例分会在 1316 的容器里凭空拉到 260px —— 编号与名称之间、名称与说明
   之间各空出一大片，五行读下来像五张没填满的表。 */
.sv5 a{
  display:grid; grid-template-columns:196px minmax(0,1fr) 18px;
  align-items:center; gap:0 16px;
  padding:20px 12px; margin:0 -12px; text-decoration:none;
  transition:background-color .25s var(--ease), box-shadow .25s var(--ease);
}
.sv5 a:hover{ background:var(--paper2); box-shadow:inset 2px 0 0 var(--brand); }
.sv5 b{ font-family:var(--serif); font-size:calc(var(--fs-lg) * var(--k)); font-weight:500; letter-spacing:.03em; transition:color .2s var(--ease); }
.sv5 em{ font-style:normal; font-size:var(--fs-bs); color:var(--ink3); line-height:1.75; text-wrap:pretty; }
/* 箭头常驻但只有三成不透明度：五行的右端空着 700px 说明文字填不满，
   一个淡箭头是三列之外唯一的视觉锚点；hover 时才升到实色。
   完全隐藏的话，整块右边是一道空墙。 */
.sv5 i{ font-style:normal; font-family:var(--en); font-size:var(--fs-md); color:var(--ink3); justify-self:end; opacity:.3; transform:translateX(-3px); transition:opacity .25s var(--ease), transform .25s var(--ease), color .25s var(--ease); }
.sv5 a:hover b{ color:var(--brand); }
.sv5 a:hover i{ opacity:1; transform:none; color:var(--brand); }

/* ---------------- 首页：房源索引带 .idx ----------------
   首页原来自己背着 60 栋楼的全量列表（五组筛选 + 排序 + 分页 + 地图），
   页面因此 12,768px 高，滚过 2,400px 之后就不再像首页。
   现在全量列表独立成 search.html，首页只留四个入口：
   与 .sv5 同一套语言 —— 顶部一根墨线、等分格、hover 只让标题变红。 */
.idx{ display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); margin-top:40px; border-top:1px solid var(--ink); }
.idx-i{ display:block; padding:20px 20px 24px; border-right:1px solid var(--line2); }
.idx-i:first-child{ padding-left:0; }
.idx-i:last-child{ border-right:0; }
.idx-k{ display:inline-flex; align-items:center; gap:8px; font-size:var(--fs-sm); color:var(--ink3); letter-spacing:.04em; }
/* 图标用 --ink2 而不是 --ink4：描边图形同样受 3:1 约束，
   --ink4 在纸底上只有 2.78:1（tokens.css 里写明了它只能做分隔线）。
   尺寸 15px 不走 1em —— 12px 的「按区域」旁边挂一个 12px 图标会显得发虚。 */
.idx-k .ic-i{ width:15px; height:15px; color:var(--ink2); transition:color .2s var(--ease); }
.idx-i:hover .idx-k .ic-i{ color:var(--brand); }
.idx-i b{ display:block; margin-top:8px; font-family:var(--serif); font-size:calc(var(--fs-lg) * var(--k)); font-weight:500; letter-spacing:.02em; transition:color .2s var(--ease); }
.idx-s{ display:block; margin-top:8px; font-size:var(--fs-sm); color:var(--ink3); line-height:1.75; }
.idx-i:hover b{ color:var(--brand); }

/* ---------------- 14 格的「按区域看写字楼 / 产业园」（2026-11-02）----------------
   .idx 被两处复用了两种规模：首页 4 项（一行）、分类页 14 项（四行）。
   上面那三条（:first-child 去左内边距、:last-child 去列线）是给**首页单行**写的，
   套到 14 格上就只命中第 1 格和第 14 格：
     · 第 5、9、13 格同在第 1 列，却仍留着 20px 内边距 ——
       实测第 1 列左缘：第 1 行 65px、其余三行 85px，整张表左边那条竖线是歪的；
     · 第 4、8、12 格在最后一列，右边却还画着列线；
     · 第 14 格在第 2 列，它本该有的列线反被 :last-child 去掉了。
   所以 14 格这种规模按 4n / 4n+1 自己定位，base 只管「有列线」，
   最后一列的例外放进 min-width 分支，免得和下面两条响应式互相打架。

   序号那一行同时补了三样：一枚「区划」图标、等宽数字、一条引线。
   原来只有一串 12px 灰数字吊在左上角，隔 8px 才是 24px 衬线区名，
   读起来像漏了半行字；引线把这行补成「栏目头」，与图墙、页脚的分隔语言一致。
   —— 顺带把序号从正文字体换成 --en + tabular-nums：01 与 10 在比例字体下
   宽度差 1px 左右，14 格里逐行往下就是肉眼可见的抖。 */
/* 左右内边距沿用 base 的 20 —— 两个页面不并排出现，但同一套 .idx 的
   间距值不要分叉，否则以后改一处忘一处。首列由下面的 4n+1 规则压到 0。 */
.idx-grid .idx-i{ padding:20px 20px 24px; border-right:1px solid var(--line2); }
.idx-grid .idx-k{ display:flex; align-items:center; gap:8px; width:100%; }
.idx-grid .idx-k .ic-i{ width:14px; height:14px; color:var(--ink3); }
.idx-grid .idx-n{
  font-family:var(--en); font-size:var(--fs-sm); font-weight:400;
  letter-spacing:.1em; font-variant-numeric:tabular-nums; color:var(--ink3);
  transition:color .2s var(--ease);
}
.idx-rule{
  flex:1 1 auto; min-width:16px; height:1px; margin-left:6px;
  background:var(--line2); transition:background .2s var(--ease);
}
.idx-grid .idx-i:hover .idx-k .ic-i,
.idx-grid .idx-i:hover .idx-n{ color:var(--brand); }
.idx-grid .idx-i:hover .idx-rule{ background:var(--brand-mid); }
/* ⚠ 断点必须跟 .idx 自己的那两条走：980 → 2 列、560 → 1 列。
   一开始我按「1080 变 2 列」写，实测 1000 宽下仍是 4 列 ——
   页面上的 `.idx` 规则挂在 (max-width:980px) 上（不是 1260，那个块只管页头导航），
   于是 981–1080 这一段我的 2 列规则会把 16px 内边距加到第 2、4 列上，
   四列的左边距变成 0/16/0/16 交错。判据之所以没抓到，是因为只比了「同列内是否一致」，
   而同列恰好是一致的 —— 又是一次「判据写错比代码错更常见」。 */
@media (min-width:981px){
  .idx-grid .idx-i:nth-child(4n+1){ padding-left:0; }
  .idx-grid .idx-i:nth-child(4n){ border-right:0; }
  .idx-grid .idx-i:nth-child(n+5){ border-top:1px solid var(--line2); }
}
@media (max-width:980px){
  .idx-grid .idx-i{ padding:16px 16px 20px; }
  .idx-grid .idx-i:nth-child(2n+1){ padding-left:0; }
  .idx-grid .idx-i:nth-child(2n){ border-right:0; }
  .idx-grid .idx-i:nth-child(n+3){ border-top:1px solid var(--line2); }
}
@media (max-width:560px){
  .idx-grid .idx-i{ padding:16px 0; border-right:0; }
}
/* ---------------- 三段决策路径（首页 02） ----------------
   三列并排，靠细线分栏，不做卡片阴影：一屏三块，读的是"我属于哪一段"，
   不是"这三块哪个好看"。每块底部一个带面积筛选的入口，点进去就是列表页。 */
.stg3{ display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:0; margin-top:32px; border-top:1px solid var(--ink); }
.stg-c{ padding:24px 24px 24px 0; border-right:1px solid var(--line2); display:flex; flex-direction:column; }
.stg-c + .stg-c{ padding-left:24px; }
.stg-c:last-child{ border-right:0; padding-right:0; }
.stg-h{ display:flex; align-items:baseline; gap:8px; flex-wrap:wrap; }
/* 衬线字只有 500 一档可用（写 400 会被字体映射成 500，type 闸门判"字重落空"）。
   与 .sec-h h2 保持同一档。 */
.stg-h b{ font-family:var(--serif); font-size:calc(var(--fs-h3)*var(--k)); font-weight:500; letter-spacing:.02em; line-height:1.25; }
.stg-h span{ font-size:var(--fs-xs); color:var(--ink3); letter-spacing:.06em; }
.stg-l{ margin-top:16px; }
.stg-l li{ position:relative; padding-left:16px; font-size:var(--fs-bs); color:var(--ink2); line-height:1.9; }
.stg-l li + li{ margin-top:8px; }
.stg-l li::before{ content:''; position:absolute; left:0; top:.85em; width:5px; height:1px; background:var(--ink4); }
.stg-l b{ font-weight:700; color:var(--ink); }
.stg-go{ margin-top:auto; padding-top:24px; align-self:flex-start; font-size:var(--fs-bs); color:var(--ink); border-bottom:1px solid var(--ink4); padding-bottom:2px; }
.stg-go:hover{ color:var(--brand); border-color:var(--brand); }

/* ── 三层业务：线下 / 线上 / AI+（2026-10-22）
   与 .stg3 同构（顶线 + 竖分隔 + 底部链接对齐），差别只在每列多一行
   「层」标签 —— 这一段讲的是业务怎么交付，不是客户分几种，所以不能
   长得像「所处阶段不同」那段。
   ⚠️ 字号只能用既有档位：check_type 判「全站字号共 9 级」，
   这里多写一个新数值就会把级数顶到 10，闸门判红。 */
.biz3{ display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:0; margin-top:32px; border-top:1px solid var(--ink); }
.biz3 > li{ display:flex; flex-direction:column; padding:24px 28px 24px 0; border-right:1px solid var(--line2); }
.biz3 > li + li{ padding-left:28px; }
.biz3 > li:last-child{ border-right:0; padding-right:0; }
.biz-k{ display:flex; align-items:center; gap:12px; font-size:var(--fs-xs); letter-spacing:.1em; color:var(--ink3); }
.biz3 h3{ margin-top:16px; font-family:var(--serif); font-size:calc(var(--fs-h3)*var(--k)); font-weight:500; line-height:1.5; letter-spacing:.02em; }
.biz3 p{ margin-top:12px; font-size:var(--fs-bs); line-height:1.9; color:var(--ink2); }
.biz3 p b{ font-weight:700; color:var(--ink); }
/* min-height:44 + align-items:flex-end：980 以下 padding-top 降到 16px，
   实测热区只有 41.8px，低于「触控 ≥44px」这条硬约束。文字仍贴底，
   下划线与文字的间距不变，多出来的那一截在上方当热区。 */
.biz-go{ display:inline-flex; align-items:flex-end; min-height:44px; margin-top:auto; padding-top:24px; align-self:flex-start; font-size:var(--fs-bs); color:var(--ink); border-bottom:1px solid var(--ink4); padding-bottom:2px; }
.biz-go:hover{ color:var(--brand); border-color:var(--brand); }

/* ══ 页头在 1260 以下收起导航（2026-10-24）══════════════════════════
   为什么把这条从 980 提到 1260：导航有 11 项、共 677px，加 logo 127、
   电话+按钮 252、两段 28px 间距，一行的硬需求是 1,112px；而 .wrap 的内容区
   只有 min(1120, 视口−15) − 64。实测文档被撑到 1,255px 恒定不变 ——
   1259 及以下全部出现横向滚动条（1024 实测溢出 125px，26 个页面一个不落）。

   ⚠ 这一档以前修过两次，两次都是「收窄链接内边距」的微调（14→9px），
     只够省 41px。这次差的 195px 不是微调能补的：导航项从 8 个长到 11 个，
     收窄只会把每个字挤到断行。容量不够就换形态，不硬塞。

   ⚠ 只搬「收起导航 + 汉堡」这部分，不动 980 块里的触控尺寸规则
     （.ft li a / .mx a / .fv button 那些 44px 是手机专用，
      放到 1260 会白白把平板上的页脚和列表撑长）。 */
@media (max-width:1260px){
  .nav{ display:none; }
  /* 导航收起来之后，页面上再没有第二个入口 —— 用户只能退回首页。
     补一个 44×44 的菜单按钮，展开时把 .nav 变成顶栏下的整幅面板。 */
  .mnav-bt{ order:9; display:flex; flex-direction:column; justify-content:center; gap:4px;
    flex:0 0 auto; width:44px; height:44px; padding:0 8px; margin-left:8px;
    border:1px solid var(--line3); cursor:pointer; }
  .mnav-bt span{ display:block; height:1.5px; background:var(--ink); transition:transform .2s var(--ease), opacity .2s var(--ease); }
  .hd-r{ order:8; margin-left:auto; }
  /* 打开时两条线交叉成 ×，不是只转一条 —— 只转一条看起来像一条斜杠，
     而且「关闭」这个动作在图标上没有着落。 */
  .mnav-ck:checked ~ .mnav-bt span:nth-child(1){ transform:translateY(3.5px) rotate(45deg); }
  .mnav-ck:checked ~ .mnav-bt span:nth-child(2){ transform:translateY(-3.5px) rotate(-45deg); }
  .mnav-ck:checked ~ .nav{
    display:flex; flex-direction:column; align-items:stretch; gap:0;
    position:absolute; left:0; right:0; top:100%; margin:0; padding:8px 20px 12px;
    background:var(--paper); border-bottom:1px solid var(--line); box-shadow:0 12px 24px rgba(var(--ink-rgb), .06);
  }
  .mnav-ck:checked ~ .nav a{ display:flex; align-items:center; min-height:48px; padding:0;
    font-size:var(--fs-base); border-bottom:1px solid var(--line2); }
  .mnav-ck:checked ~ .nav a:last-child{ border-bottom:0; }
  /* 城市位跟着导航一起收进面板。手机上顶栏塞不下第二行，
     但「只做上海」是一条事实，不该在窄屏上凭空消失。
     ⚠ 2026-11-02：桌面那枚印记已改横排，这段里的 writing-mode 复位
       从此是「同值覆盖」（桌面与面板都是 horizontal-tb）。留着不删，
       因为一旦有人把桌面改回竖排，这行就是面板不被拉成一条窄字的那道闸。
     ⚠ 必须藏掉 ::before 那道朱文：它在桌面是绝对定位在 .city 顶边的，
       面板里 .city 被拉成 48px 高、padding 归零，红线会浮到「联系」下面去。
     ⚠ 字距收到 .06em：桌面现在也是 .06em，这里保留是为了不让面板继承
       桌面将来可能加大的字距 —— 面板宽 335px，字距一松就显散。 */
  .mnav-ck:checked ~ .nav .city{
    display:flex; align-items:center; width:100%; height:auto; min-height:48px;
    writing-mode:horizontal-tb; letter-spacing:.06em;
    margin:0; padding:0; border-left:0; font-size:var(--fs-base); color:var(--ink2);
  }
  /* 桌面那枚印章的朱文，在面板里改成行首一道 14×2 的红横线。
     保留这条线是为了让「上海」在两处长得像同一个东西；
     改成 static 定位是因为面板里它已经是普通流内元素，
     还留着 absolute 就会浮到上一项底下（试过，确实浮了）。 */
  .mnav-ck:checked ~ .nav .city::before{
    display:inline-block; position:static;
    width:14px; height:2px; margin-right:10px; vertical-align:middle;
    background:var(--brand);
  }
  .mnav-ck:checked ~ .nav a.on::after{ display:none; }
  /* 2026-10-23：点面板外的空白处收起菜单。
     纯 CSS 的 checkbox 方案没有「失焦关闭」—— 菜单展开后只能再点一次汉堡。
     面板占住首屏，用户第一反应是点旁边的正文，点不动就以为页面卡了。
     这块透明 label 铺在页头以下的整屏，点哪都等于再点一次开关；
     z-index 压在 .nav 下面，所以点菜单项照常跳转，不会误关。
     ⚠ 必须用 label[for] 而不是 div + JS：全站没有共用 JS 包，
     内容页只加载内联的年份脚本，加行为就得往每个页面写一遍。 */
  .mnav-ck:checked ~ .mnav-mask{
    display:block; position:fixed; left:0; right:0; top:76px; bottom:0; z-index:1;
    background:transparent; cursor:pointer;
  }
  /* 遮罩从页头下沿开始，页头本身（logo 与汉堡）保持可点 ——
     整屏覆盖的话，菜单打开时点 logo 不会跳首页，只会把菜单关掉。 */
  .mnav-ck:checked ~ .nav{ z-index:2; }
}

/* 以下是原 980 块主体（触控尺寸等），页头规则已上移到 1260 块 */
@media (max-width:980px){
  /* 三段决策：980 以下三列各剩 300 不到，"10–30 人 + 三条建议"会被挤成六七行，
     改成竖直三段，靠横线分栏 */
  .stg3{ grid-template-columns:minmax(0,1fr); }
  .stg-c{ padding:24px 0 24px; border-right:0; border-bottom:1px solid var(--line2); }
  .stg-c + .stg-c{ padding-left:0; }
  .stg-c:last-child{ border-bottom:0; padding-right:0; }
  .stg-go{ padding-top:16px; }
  /* 三层业务同理会挤成六七行，980 以下竖排 */
  .biz3{ grid-template-columns:minmax(0,1fr); }
  .biz3 > li{ padding:24px 0 24px; border-right:0; border-bottom:1px solid var(--line2); }
  .biz3 > li + li{ padding-left:0; }
  .biz3 > li:last-child{ border-bottom:0; padding-right:0; }
  .biz-go{ padding-top:16px; }
  .idx{ grid-template-columns:repeat(2,minmax(0,1fr)); margin-top:32px; }
  .idx-i{ padding:16px 16px 20px; }
  .idx-i:nth-child(2n){ border-right:0; }
  .idx-i:nth-child(n+3){ border-top:1px solid var(--line2); }
  .idx-i:nth-child(3){ padding-left:0; }
}
@media (max-width:560px){
  /* 页头三项（logo / 委托找房 + 电话 / 汉堡）之间原来吃掉了两段 28px 的 gap，
     加上新增的电话按钮，390 宽下整条溢出 21px。gap 收到 10、按钮内边距收一档。 */
  .hd .wrap{ gap:8px; }
  .hd-r{ gap:8px; }
  .btn{ padding:0 12px; }
  .mnav-bt{ margin-left:0; }

  .stg-go{ display:inline-flex; align-items:center; min-height:44px; padding-top:0; margin-top:16px; }
  .idx{ grid-template-columns:1fr; }
  .idx-i{ padding:16px 0 16px; border-right:0; border-top:1px solid var(--line2); }
  .idx-i:first-child{ border-top:0; }
}

/* ---------------- 全站公司条 .co ----------------
   92 个内页只讲「这栋楼」，从头到尾没说「是谁在讲这栋楼」。
   客户从搜索进来看到的是资料页，资料的可信度取决于出资料的人，
   但页面上没有一处交代出资料的人是谁、做过什么、怎么联系。
   这一条补的就是这个，每页一次，位置在所有正文之后、深色 CTA 之前：
   先让客户确认「你可靠」，再问他「要不要委托」。 */
.co{ background:var(--paper2); border-top:1px solid var(--line); padding:var(--sp-band) 0; }
.co .wrap{ display:grid; grid-template-columns:minmax(0,1fr) auto; gap:36px 64px; align-items:end; }
.co-l{ grid-column:1 / -1; }
.co-k{ font-size:var(--fs-sm); color:var(--ink3); letter-spacing:.06em; }
.co h2{ font-family:var(--serif); font-size:calc(var(--fs-h2) * var(--k)); font-weight:500; letter-spacing:.02em; margin-top:8px; }
/* 用 px 不用 ch：13px 下 1ch 只有 7px 左右，64ch 算出来 450，
   在 1296 的容器里左边挤成一条，右边空出半屏。 */
.co p{ margin-top:16px; font-size:var(--fs-bs); line-height:1.9; color:var(--ink2); max-width:520px; }
/* 三个数字各占等分格。
   原来是 flex + gap，三个 li 按内容宽度挤在左边 440px 里，而这一格有 1015 宽 ——
   实测 li 只到 505，右边 575px 是空的，深色带上就这么横着一道空。
   栅格三等分之后 li 落在 65 / 422 / 779，跟其他页的 .hstat 是同一种节奏。
   760 以下仍走 flex-wrap（三个一列排不下，要换行）。 */
.co-f{ display:flex; flex-wrap:wrap; gap:16px 56px; }
@media (min-width:761px){
  .co-f{ display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:16px 0; }
  .co-f li + li{ padding-left:32px; border-left:1px solid rgba(var(--white-rgb),.14); }
}
.co-f li{ display:flex; flex-direction:column; gap:4px; }
.co-f b{ font-family:var(--serif); font-size:calc(var(--fs-h3) * var(--k)); font-weight:300; line-height:1.1; font-variant-numeric:tabular-nums; }
.co-f em{ font-family:var(--sans); font-size:var(--fs-sm); font-style:normal; color:var(--ink3); margin-left:2px; }
.co-f span{ font-size:var(--fs-xs); color:var(--ink3); letter-spacing:.04em; }
.co-a{ display:flex; flex-wrap:wrap; gap:4px 24px; }
.co-a a{ display:inline-flex; align-items:center; min-height:32px; font-size:var(--fs-bs); color:var(--ink); border-bottom:1px solid var(--ink4); padding-bottom:2px; transition:color .2s var(--ease), border-color .2s var(--ease); }
.co-a a:hover{ color:var(--brand); border-color:var(--brand); }


/* ---------------- 入场：只动位移与透明度 ---------------- */
.rv{ opacity:0; transform:translateY(16px); transition:opacity .8s var(--ease), transform .8s var(--ease); }
.rv.in{ opacity:1; transform:none; }
@media (prefers-reduced-motion: reduce){
  html{ scroll-behavior:auto; }
  .rv{ opacity:1; transform:none; transition:none; }
  .pc-ph img,.lc-ph img,.wall img{ transition:none; }
  /* R14：上面几条只盖住「入场动画」，全站还有 42 个元素带 transition
     （悬停变色、卡片 sheen 扫光、.tilt 位移、汉堡两道线交叉、灯箱淡入）。
     其中只改颜色/透明度的不刺激，真正会动的是位移、缩放、旋转。
     用白名单放行颜色类，其余属性一律 .01ms 停掉 —— 不整站 transition:none，
     是因为那样连「按下去有没有反应」的即时反馈也一起没了。 */
  *,*::before,*::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-property:color,background-color,border-color,outline-color,fill,stroke,box-shadow,opacity !important;
    transition-duration:.01ms !important;
    transition-delay:0s !important;
  }
}

/* ============================================================
   响应式
   ============================================================ */
@media (min-width:1700px){
  .hero .sub{ font-size:calc(var(--fs-num)*var(--k)); }
  .hero-left{ padding-right:40px; }
}

/* 1280–1420：左栏右内边距 44 → 26。
   一条规则解决两件事 —— 标题多半行宽才排得下两行；
   文字与图片之间的空白也正好收掉（"中间大量留白"）。 */
@media (max-width:1420px){
  .hero-left{ padding-right:24px; }
}

@media (max-width:1280px){
  .hero-left{ padding:48px 24px 40px 0; }
  .est-grid{ grid-template-columns:280px minmax(0,1fr) 246px; gap:40px; }
  .pgrid{ gap:32px 24px; }
  .listwrap{ grid-template-columns:1fr 290px; gap:32px; }
}
@media (max-width:1120px){
  .hero-grid{ grid-template-columns:minmax(0,1fr) 42%; }
  .hero-left{ padding-right:36px; }
  .est-grid{ grid-template-columns:1fr 1fr; gap:32px; }
  .est-intro{ grid-column:1/-1; }
  .est-intro p{ max-width:520px; }
  .pgrid{ grid-template-columns:repeat(2,minmax(0,1fr)); }
  /* 四列栅格在 1120 以下撑不开：主图摊成一列、文字落到它下面，
     四张实拍改成 2×2。图与图之间仍是同一套 16px 间距。 */
  .db{ grid-template-columns:1fr; gap:32px; }
  .db-fig,.db-r{ grid-column:1 / -1; }
  .db-r{ padding-left:0; }
  .db-sub{ grid-template-columns:repeat(2,minmax(0,1fr)); }
  .cm{ grid-template-columns:1fr; gap:44px; }
}
@media (max-width:980px){
  /* 按钮桌面 40 高，手机上不够 44 的命中下限。
     另外手机上顶栏只剩 350 宽，logo + 按钮 + 菜单并排时「联系顾问」会折成两行，
     按钮变成一块方砖 —— 文字不换行 + 内边距收窄才放得下。 */
  .btn{ height:44px; padding:0 16px; white-space:nowrap; font-size:var(--fs-bs); }
  /* 手机上所有可点入口都要 44px 高：页脚 25 个链接原来只有 27px，
     手指点在两行字之间会落到空白里。 */
  /* 2026-11-02：`.ft li a` 从这一条里拿掉了。
     页脚的行高阶梯只允许有一份定义（见下方页脚段落的 base / ≤760），
     否则首页与其它页会拿到两套值：首页不引 beauty.css，只能吃这一条的 44；
     其它页被 beauty.css 的 `.ft li a{min-height:32px}` 压回 32 ——
     同一份页脚在 768 下，首页的 a=44、别的页 a=32，而 span 只有一套，
     于是「联系」列在首页比旁边矮 26.5px、在别的页正好齐平。
     判据两端都测过：只测一个模板会以为已经修好了。 */
  .ft-bot .links a,.crumb a{ min-height:44px; }
  /* 内链矩阵是手机上最主要的横跳入口：一行 4–5 个链接，每个只有 34 高，
     手指点在两行之间会落到空白。统一 44，这一节会变长，但它是导航。 */
  .mx a{ display:inline-flex; align-items:center; min-height:44px; }
  .fv button{ min-height:44px; }
  .sort button{ min-height:44px; }
  .sb-tabs button{ min-height:44px; padding-top:8px; }
  .sug a{ min-height:48px; }
  /* 侧栏「热门商圈/热门地铁」是 li>a 列表，每条 34 高，手指在两行之间会点空 */
  .linklist a{ min-height:44px; }
  /* 首屏估算带、区块标题右侧、「更多」「看清流程」、表单里的 chips —— 这些在手机上
     都是 30–32 高的独立可点元素，手指点在字缝里会落空。统一 44。 */
  .est-dens button,.est-acts .go,.est-acts .lite,.sec-h .more,.db-acts .more,
  .sb-tabs .all,.cf-more button,.ck span{ min-height:44px; }
  .cf-chips .ck{ min-height:44px; }
  .ck span{ display:inline-flex; align-items:center; }
  .page a,.page span{ min-width:44px; }
  .sb-panel a{ min-height:44px; display:inline-flex; align-items:center; }
  /* 首屏「按标准层」的四列网格要复位：327 宽下每列只剩 82px，
     装不下「2,000–3,000㎡」，会溢出成可见的横向滚动。 */
  .sb-panel[data-panel="a"].on{ display:flex; }
  /* 窄屏这一行会折行，点挂在任何一侧都会难看（挂前面就跑到行首，
     挂后面就掉到行尾悬着）。窄屏去掉点，改用间距分列。 */
  .sb-panel a:not(:last-child)::after{ content:none; }
  /* 八个区名在 390 宽下：8×26 + 7×24 = 376，容器只有 327 —— 折成两行，
     第二行只剩「普陀」两个字，看着像版式没排完。
     间距从 24 收到 14：208 + 98 = 306，一行放得下；再窄（≤360）自然折两行，也不再出孤儿。
     竖向 44 的触控高度不动 —— 那是手指落点，不是版式余量。 */
  .sb-panel{ gap:8px 16px; }
  .page a,.page span{ min-height:44px; }
  /* 手机上命中区放大到 44 之后，8 个分页项排不进 335 的容器（要 358）。
     只留「上一页 · 3/6 · 下一页」：数字条整块收起来，页码用一行小字交代。
     48 (上一页) + 44 (指示) + 48 (下一页) ≈ 150，一格不多。 */
  .page a:not(.step){ display:none; }
  .page{ flex-wrap:wrap; }
  .page .pg-now{
    display:inline-flex; align-items:baseline; gap:1px;
    min-width:0; height:44px; padding:0 4px; border:0;
    font-size:var(--fs-sm); color:var(--ink3); font-variant-numeric:tabular-nums;
  }
  .page .pg-now b{ font-size:var(--fs-lg); color:var(--ink); font-weight:500; line-height:1; }
  .page .pg-now i{ font-style:normal; }
  .page .step{ flex:1 1 0; }
  /* minmax(0,1fr) 而不是 1fr：1fr 的最小值等于内容 min-content，
     四个页签在 390 宽上会把整页撑宽 5px（页面上看不出来，但会横跳）。 */
  .hero-grid{ grid-template-columns:minmax(0,1fr); min-height:0; }
  /* 小屏：文字在前、图在后（2026-10-20 调整）。
     原先是 order:-1，图抢到最上面：390×844 上第一眼是一张 219px 高的楼景，
     标题被压到 400px 以下 —— 访客在判断「这是什么网站」的那一刻，
     看到的是一张不知道在哪的照片。改成先给标题、搜索与按钮，图接在后面，
     首屏仍能露出一截，只是不再占据第一眼。 */
  .hero-right{ height:auto; }
  .hero-fig{ flex:0 0 auto; }
  .hero-right img{ height:auto; aspect-ratio:16/9; }
  .hero{ padding-left:0; }
  .hero-left{ padding:36px 24px 40px; }
  .est-grid{ grid-template-columns:1fr; gap:24px; }
  .est-out b{ font-size:var(--fs-h2); }
  .sug{ left:0; right:0; }
  /* 1fr 的最小值等于 min-content，卡片里最宽的那行字会把栅格顶到 380，
     整页因此横向溢出 10px（手机上表现为页面能左右晃）。minmax(0,1fr) 才真的能收。 */
  .listwrap{ grid-template-columns:minmax(0,1fr); }
  .side{ position:static; }
  /* 980 以下列表改成整幅宽（侧栏落到底），三栏不用再缩：190 的图 + 132 的操作列都还有余量。
     原来这里把 .lc-r 折成整行，一行就多出 60px —— 现在不再折。 */
  .lcard{ grid-template-columns:176px minmax(0,1fr) 120px; }
  
  
  
  .matrix{ grid-template-columns:1fr 1fr; gap:32px; }
  /* 页脚六列在 1240 以下折成三列（见 beauty.css 同断点 —— 那边后加载，
     这里不重复写，否则写在这里也会被 beauty 的基础规则压掉）。 */
  .wall{ grid-template-columns:repeat(2,minmax(0,1fr)); }
  .il-fig img{ aspect-ratio:3.2/1; }
  /* 承接方：说明与四个事实本来并排，窄屏上事实块会挤成两行半，落到说明下面 */
  .deco-facts{ gap:12px; }
  /* 台账在 980 以下缩到一栏：列表 720 的固定宽会把注释挤成一条细缝 */
  .dcgrid{ grid-template-columns:minmax(0,1fr); gap:28px; }
  /* 五项业务：目录行本来就只占一行宽度，窄屏只收窄列宽，不折列 */
  .sv5 a{ grid-template-columns:176px minmax(0,1fr) 16px; gap:0 16px; padding:16px 8px; margin:0 -8px; }
  .sv5 em{ font-size:var(--fs-sm); }
  /* 公司条：右栏（事实 + 入口）在窄屏没有并排的空间，改成上下三段 */
  .co .wrap{ grid-template-columns:minmax(0,1fr); gap:28px; }
  .co-f{ gap:16px 32px; }
  .co-a a{ min-height:44px; }
  .sv5-h .more{ min-height:44px; }
}
@media (max-width:760px){
  /* 五项业务：手机上四列排不下，编号与名称并一行，说明落到下一行缩进对齐 */
  .sv5 a{ grid-template-columns:minmax(0,1fr); gap:4px 0; padding:16px 0; margin:0; }
  .sv5 i{ display:none; }
  /* 触屏没有 hover，整行高亮反而在点完之后留一块灰 —— 手机上只留标题变红 */
  .sv5 a:hover{ background:transparent; box-shadow:none; }
  /* 触屏档：地图点再撑到 40。不放到 44 是因为一屏有几十个点，
     40 已经是「不会点到隔壁」的尺寸，再大会把地图挡成一片黑。 */
  .mapbox .pin{ width:40px; height:40px; margin:-20px 0 0 -20px; }
  .mapbox .pin-c{ width:40px; height:40px; margin:-20px 0 0 -20px; }

  .sv5{ grid-template-columns:repeat(2,minmax(0,1fr)); }
  .sv5 li:nth-child(3n){ border-right:1px solid var(--line2); }
  .sv5 li:nth-child(2n){ border-right:0; }

  /* ---- 筛选折叠（手机）----
     改前实测 390 宽：五行筛选条 1074px（区域 157 / 商圈 349 / 地铁 301 /
     标准层 157 / 步行 109），第一栋楼要滚到 1909px 才出现 —— 2.3 屏。
     客户点进「全部房源」，前两屏看到的全是标签墙，一栋楼都没有。
     折叠后筛选条只剩这一行（44px），第一栋楼回到 900px 上下。
     用一个 checkbox 开合：纯 CSS、键盘可用、脚本挂了也不影响（脚本挂了本来就筛不了）。 */
  .fsum{
    display:flex; align-items:center; gap:8px;
    min-height:44px; padding:0 2px;
    font-size:var(--fs-bs); color:var(--ink);
    border-bottom:1px solid var(--line2);
  }
  .fsum svg{ flex:0 0 auto; color:var(--ink2); }
  .fsum-t{ flex:0 0 auto; letter-spacing:.04em; }
  /* 收起状态下必须能看见「现在筛了什么」，否则客户以为列表就是全部。
     条件由 portal-app.js 写进来，太长就截断（完整条件展开后仍在抽屉里）。 */
  .fsum-i{ flex:1 1 auto; min-width:0; color:var(--ink3);
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  .fsum-x{ flex:0 0 auto; margin-left:auto; font-weight:400; font-size:var(--fs-sm); color:var(--ink3); }
  .fsum-x::after{ content:'展开'; }
  /* 有筛选条件时给一个红点，避免「收起 + 有筛选」看起来像没筛 */
  .fsum.has .fsum-x::before{ content:''; display:inline-block; width:5px; height:5px; margin-right:8px;
    border-radius:50%; background:var(--brand); vertical-align:middle; }
  .ffx:checked ~ .fsum .fsum-x::after{ content:'收起'; }
  .ffx:checked ~ .fsum{ border-bottom-color:var(--line3); }

  /* ≤980 起筛选改抽屉，抽屉自己就是「面板」，再套一层白纸 + 描边等于两层框，
     而且 .fp-hd 和折叠条说的是同一件事。面板在这里退成无框，选项直接铺在纸上。 */
  .fpanel{ padding:0; background:transparent; border:0; }
  .fp-hd{ display:none; }
  .fv{ margin-left:0; }
  .filters{ display:none; }
  .ffx:checked ~ .filters{ display:block; }

  /* 抽屉展开后，行标签原来还是「左 92px 定宽列 + 右边标签墙」的桌面布局：
     商圈那一行有 21 个按钮、折成三四行，标签被垂直居中到中间去，
     看起来像「区域」两个字跑到了第二行。手机上标签改独占一行当小标题，
     标签区也从 283 宽变成整行，折行反而少了。 */
  /* ⚠ 必须是 minmax(0,1fr) 而不是 1fr（2026-10-27 实测）。
     桌面那条写的是 minmax(0,1fr)，手机这里退化成一个 1fr =
     minmax(auto,1fr)，下限变成 min-content —— 而 .fv-st 展开后是一整排
     nowrap 的站点按钮（2 号线 26 个），min-content 1159px。
     于是整列被撑到 1172，整页 scrollWidth 1179（视口 390），
     而抽屉收起时是 display:none，所以「收起态不溢出」量不出来。 */
  .frow{ grid-template-columns:minmax(0,1fr); }
  /* 双保险：滚动容器自身不进 min-content 计算 */
  .fv-wrap{ min-width:0; }
  .fl{ padding:12px 0 0; }
  .fv{ padding:8px 0 12px; }
  /* 这些按钮在手机上是主要操作，原来 35px 高（8px 上下内边距 + 13px 字）——
     低于 44 的触控底线，一指头下去经常点到邻居。撑到 44，横向内边距收一档
     保证一行还能放 4 个。抽屉是点开才看的，多出来的高度不影响默认首屏。 */
  .fv button{ min-height:44px; padding:8px 12px; }
  /* 面积 8 项两列成对（2026-10-27）：七档 + 不限共 8 项，flex 在 390 下折成
     3/2/2/1 —— 末行只剩「3,000㎡ 以上」一项，读起来像后面漏了一个。
     两列网格后固定 4 行、每行 2 项，左边缘对齐、行距一致，高度 217→220
     几乎没变。只给这一行用：其余行最多 5 项（租金 5、步行 4），flex 不会出孤项，
     统一改成网格反而把短选项（写字楼 / 产业园）拉成两列空框。 */
  [data-facets="area"]{ display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:8px 10px; }
  [data-facets="area"] button{ width:100%; padding:8px; justify-content:center; }
  /* 站点一行横滑（2026-10-27）：2 号线 25 站折成 5 行后，抽屉总高 1,765px，
     是 390 视口的两倍 —— 点开筛选要滚两屏才看得到「步行到地铁」和结果。
     横向滑动 + 右缘渐隐，与详情页大纲条同一套手法；44px 的触控高度不动。 */
  .fv-st{
    flex-wrap:nowrap; overflow-x:auto; overscroll-behavior-x:contain;
    padding-bottom:8px; scrollbar-width:none;
    -webkit-mask-image:linear-gradient(90deg,#000 0,#000 calc(100% - 26px),transparent 100%);
            mask-image:linear-gradient(90deg,#000 0,#000 calc(100% - 26px),transparent 100%);
  }
  .fv-st::-webkit-scrollbar{ display:none; }
  .fv-st button{ flex:0 0 auto; }
}
@media (max-width:760px){
  .wrap{ padding:0 20px; }
  .sec{ padding:64px 0; }
  .pgrid{ grid-template-columns:repeat(2,minmax(0,1fr)); }
  .pa{ grid-template-columns:1fr 1fr; }
  .pa a{ padding:20px 20px 24px 0; }
  .pa a:nth-child(2){ border-right:0; }
  .pa a + a{ padding-left:0; }
  .pa a:nth-child(2n){ padding-left:16px; border-right:0; }
  .pa a:nth-child(-n+2){ border-bottom:1px solid var(--line2); }
  .pa a:nth-child(3){ padding-left:0; }
  
  
  
  .adv{ grid-template-columns:1fr; }
  .adv li:nth-child(2n){ padding-left:0; border-left:0; }
  .cf{ padding:24px 20px 24px; }
  .cf-grid{ grid-template-columns:1fr; gap:0; }
  /* 页脚：手机上两列，品牌与「按地铁」两栏各占满一行 ——
     品牌是识别信息、地铁是控件，挤在半栏里都读不成样子。
     列数与 grid-column 由 beauty.css 的断点负责（那边后加载）。 */
  .ft-brand p{ max-width:none; }
  .ft-legal{ margin-top:32px; padding-top:16px; gap:6px 16px; }
  .ft-legal .links{ margin-left:0; }
  /* 合规区链接在窄屏撑到 44：audit_look 的 H08 按触屏底线量，
     原来给 36 时全站 298 处判红（关于/联系/工具/站点地图/回到顶部 ×
     390 与 700 两个宽度）。这一行不是正文，是唯一一处在手机上还能点的
     法务入口，压到 36 省下的 8px 不值得。 */
  .ft-rec a, .ft-legal .links a, .ft-copy .ft-icp{ min-height:44px; }
  /* 服务列表在手机上换成一行一项：名字独占一行，说明另起一行 */
  .deco-scope li{ grid-template-columns:minmax(0,1fr); gap:2px; padding:12px 0; }

  /* ---- 首屏标题：按「第一句几个字」反算字号 ----
     标题是「写字楼租赁最大的成本，<br>不是租金。」，第一句 11 个字。
     390 宽实测：h1 内容宽 327，34px 下 11 字要 375 —— 装不进，于是
     text-wrap:balance 把它劈成 6/5 两行，断在「最|大」之间。
     balance 只负责把两行拉等长，它不认识中文的词边界，切开一个词就切开了。

     所以字号不能固定档位，要由容器宽和这一句的字数反推：
       f × 11.11（含 letter-spacing 1%）≤ 容器宽  →  f ≤ 容器宽 / 11.11
     取 11.6 而不是 11.11，留约 4% 安全边距（不同字体回退、亚像素取整）。
     63 = 100vw 与 h1 内容宽的实际差值，390 / 360 / 320 三个宽度实测都是 63
     （wrap 左右各 20 + hero-left 右内边距 48 被吃掉的部分），不是估的。

     只在 ≤760 生效：再宽的屏 min() 取前一项（34px × --k），公式不参与。
     ⚠ 改首屏文案必须回头看这条 —— 字数变了，11.6 这个除数就得跟着改。 */
  .hero h1{ font-size:min(calc(var(--fs-display)*var(--k)), calc((100vw - 63px)/11.6)); }
}
@media (max-width:560px){
  .pgrid{ grid-template-columns:minmax(0,1fr); }
  .pa{ grid-template-columns:1fr; }
  .pa a,.pa a:nth-child(2n),.pa a:nth-child(3){ padding-left:0; border-right:0; }
  /* 手机上的列表行：原来整块图铺满整行（4:3 → 251 高）再叠五格数据，
     一行 629px，一屏还看不到第二栋。改成"左小图 + 右两行字"：
     104 方图贴左上，右边楼名 / 商圈·地铁 / 五格数据折两行。
     目标 160 上下，一屏能看到两行半。 */
  .lcard{ grid-template-columns:104px minmax(0,1fr); }
  .lc-ph{ aspect-ratio:1/1; align-self:start; margin-top:12px; }
  .lc-b{ padding:12px 12px 16px 12px; justify-content:flex-start; }
  .lc-n{ font-size:var(--fs-num); }
  /* 认证标签在 390 宽里一定会被挤到第二行，白白多吃 28px；手机上看楼名和地铁就够，
     认证进详情页看。 */
  .lc-cert{ display:none; }
  /* 地址在 390 宽里一定会折成两行，让位给地铁距离（那个才是决策字段） */
  .lc-addr{ display:none; }
  /* 折行以后行首的「·」变成孤零零一个点，整组分隔符一起去掉 */
  .lc-loc{ flex-direction:column; align-items:flex-start; white-space:normal; gap:1px; margin-top:8px; font-size:var(--fs-sm); }
  .lc-loc > span{ overflow:visible; text-overflow:clip; }
  .lc-loc > span + span::before{ content:none; }
  /* 地铁单独占一行。注意这里必须是 width:100% 而不是 flex:1 1 100% ——
     .lc-loc 已经改成纵向 flex，flex-basis 100% 在纵向里被当成**高度**，
     那一行会撑到整行高，看起来像图裂了。 */
  .lc-metro{ width:100%; flex-wrap:wrap; align-items:flex-start; white-space:normal; }
  .lc-metro > span{ min-width:0; white-space:normal; }
  /* 折行以后「·」落在行首，去掉；两块各自成句 */
  .lc-walk::before{ content:none; }
  /* 图标在手机上是纯装饰，占掉 19px 正好把地铁那行挤到第二行 —— 撤掉换一整行密排 */
  .lc-metro svg{ display:none; }
  /* 五格在 390 宽里「物业费 元/㎡·月」会被切成「物业费 元/...」；砍掉总层数，
     剩四格两行两列。 */
  /* 面积这一格在 19px 下「2,500–2,700㎡」要 134px，1.35fr 在 390 档只给 119 ——
     尾巴被截成「2,500–2,70…」。这里动了两处，各自解决一半：
       ① 列宽 1.35fr → 1.8fr（119 → 133）；
       ② 面积的字号 19px → 17px（134 → 120）。
     只动一处都还在边上：1.8fr 单靠列宽，133 对 134 差 1px；只缩字号，119 对 120 差 1px。
     两处一起做，133 装 120 还剩 13px 余量（`_probe_search_w.mjs` 实测 0 裁剪）。 */
  .lc-d{ grid-template-columns:1.8fr 1fr; row-gap:8px; margin-top:8px; padding-top:8px; }
  .lc-d > div:nth-child(2){ display:none; }
  .lc-key b{ font-size:var(--fs-lg); }
  /* 缩了列宽，第二格本来只剩 74px、装不下「物业费 元/㎡·月」的 88px ——
     但自动排布是按可见顺序铺的：1、3 进第一行，4、5 进第二行，
     物业费（第 4 个）落回的正是第一列（133px），够。所以这里不用给它开折行。 */
  /* 数字和标签原来各占 24.5px 行高（继承 1.75），两行就吃掉 106px */
  .lc-d b{ line-height:1.5; }
  .lc-d span{ line-height:1.5; }
  .lc-d > div:nth-child(3n+1){ padding-left:0; border-left:0; }
  .lc-d > div:nth-child(odd){ padding-left:0; border-left:0; }
  .lc-d > div:nth-child(even){ padding-left:8px; }
  /* 右侧那一列（报价 + 查看详情）在手机上没地方站，整列撤掉，用右边缘的箭头代替可点暗示；
     但价格不能跟着没 —— 它是选楼的第一判据。挂到楼名行右端，一行解决。 */
  .lc-r{ display:none; }
  .lc-prm{
    display:inline-flex; align-items:baseline; margin-left:auto; flex:0 0 auto;
    /* 楼名是 21px 衬线、价格是 12px 无衬线，baseline 对齐会让价格"掉"到楼名基线下方，
       看起来像另起一行。改成自己居中于这一行，视觉上才和楼名平齐。 */
    align-self:center;
    font-size:var(--fs-sm); color:var(--ink); font-variant-numeric:tabular-nums; white-space:nowrap;
  }
  .lc-prm em{ font-style:normal; font-size:var(--fs-xs); color:var(--ink3); margin-left:4px; }
  .lc-prm.na{ color:var(--ink3); }
  .lcard::after{
    content:''; position:absolute; right:4px; top:50%; width:7px; height:7px; margin-top:-4px;
    border-top:1.5px solid var(--ink4); border-right:1.5px solid var(--ink4); transform:rotate(45deg);
  }
  .wall{ grid-template-columns:1fr; }
  .matrix{ grid-template-columns:1fr; }
  .sec-h{ grid-template-columns:1fr; }
  /* 排序条：五个按钮在 390 宽里各折成 3–6 行，整条被撑到三行高。
     改成不换行 + 横向可滑，手指往左滑看后面两个，条高不变。
     结果条本身是两列 grid（条件+说明 / 排序），窄屏必须显式落成一列 ——
     grid 不会像 flex 那样自己换行。 */
  .resbar{ grid-template-columns:minmax(0,1fr); gap:12px; padding:16px 0 12px; }
  /* 手机：条件标签与页面标题重复（标题就是"全部房源"），这一列里也该由
     折叠条上的条件摘要说话 —— 撤掉标签，只留价格口径那条小字。 */
  .resbar .cond{ display:none; }
  .resbar .pnote{ padding-left:0; border-left:0; }
  .sort{ width:100%; overflow-x:auto; scrollbar-width:none; }
  .sort::-webkit-scrollbar{ display:none; }
  .sort button{ white-space:nowrap; flex:0 0 auto; padding:8px 12px; }
}

/* 360 宽（iPhone SE / 老安卓）页头还差 24px：
   logo 127 + 按钮组 138 + 汉堡 44 + 两段 gap = 329，可用只有 305。
   红色标记本身认得出品牌，把 "VANSHI" 字样撤掉（alt 仍在，读屏不受影响），
   再把两段 gap 收到 8/6，整条 297，留 8px 余量。 */
@media (max-width:400px){
  .logo .wm{ display:none; }
  .logo{ gap:0; }
  .hd .wrap{ gap:8px; }
  .hd-r{ gap:8px; }
  .btn{ padding:0 12px; }
  /* 列表卡「面积」这一格：@360 第一列只有 114px，而 17px 的「2,500–2,700㎡」
     要 120px —— 17px 那一档在 390 上是够的，到 360 又不够了。
     这一档降到 14px（99px），和旁边 层高/竣工 同字号：
     360 宽里本来没有主次可讲，先保证把数字读全。 */
  .lc-key b{ font-size:var(--fs-md); }
}

/* 首屏「按标准层」七项在 379 以下只剩 3 个/行，折成 3+3+1，末行孤零零一项。
   两列网格：前六项三行、末项跨两列占满 —— 7 是奇数，两列必然留一个孤儿，
   只有让它占满整行才不显得没排完。
   ⚠ 不能写进 @media (max-width:400px)：390 也在里面，而 390 下 flex 排的是
   4+3（两行 102px），改成网格会变成 4 行 212px —— 越改越差，实测过一次。 */
@media (max-width:379px){
  .sb-panel[data-panel="a"].on{ display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:8px 12px; }
  .sb-panel[data-panel="a"] a:last-child{ grid-column:1/-1; }
}

/* 320 CSS px（WCAG 1.4.10 的重排基准宽，闸门真的会按这个宽度开一屏）：
   卡片内容只剩 161px，两列的「面积」那格 88px，连 14px 的「2,500–2,700㎡」
   （99px）都装不下。这一档改成单列 —— 四格竖排，每格 137px，
   面积和「物业费 元/㎡·月」都读得全。卡片会高一些，但没有一个字被切。
   ⚠ 不要试图靠调 fr 解决：两列加起来 137px，而这两格的文字自然宽合计已经 187px。 */
@media (max-width:339px){
  .lc-d{ grid-template-columns:minmax(0,1fr); }
  .lc-d > div{ padding-left:0; border-left:0; }
}


/* ---------------- 键盘可达：只在键盘操作时出现焦点框 ---------------- */
a:focus-visible,button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,
summary:focus-visible,[tabindex]:focus-visible{
  outline:1.5px solid var(--ink); outline-offset:3px;
}
.sform-r1 input:focus-visible{ outline:0; }
.sform-r1:focus-within{ box-shadow:0 0 0 1.5px var(--ink); }
/* skip link 跳进来之后焦点落在 <main tabindex="-1"> 上。
   main 是整页正文，画一圈焦点环没有意义（而且会框住几千像素高的区域），
   这里只让它「接住焦点」，视觉反馈由「页面已经滚到正文」来给。
   选择器用 #main 是故意的：要压过上面 [tabindex]:focus-visible 那条通用规则。 */
#main:focus{ outline:0; }

/* ============================================================
   大屏（≥2100 / ≥2500 / ≥3100）：容器、区块节奏、列表栏宽
   —— 必须放在文件末尾，否则会被上面的基础规则反超（同名选择器后者胜）
   ============================================================ */
@media (min-width:2100px){
  .sec{ padding:112px 0; }
  .sec.tight{ padding:76px 0; }
  .est-band{ padding:56px 0; }
  .est-grid{ grid-template-columns:400px minmax(0,1fr) 340px; gap:56px; }
  .est-row{ max-width:600px; }
  .lcard{ grid-template-columns:240px minmax(0,1fr) 150px; }
  .listwrap{ grid-template-columns:1fr 360px; gap:48px; }
  .pa a{ padding:28px 32px 32px 0; }
  .pa a + a{ padding-left:32px; }
  .pa p{ max-width:320px; }
  .ft{ padding:68px 0 32px; }
  .ft-top{ gap:44px; }
}
@media (min-width:2500px){
  /* 大屏留白只到 128，不再往上加 144 —— 96 与 128 差 33%，人眼看得出；
     128 与 144 只差 12%，多出来的 16px 换不来"更大气"，只是让 4K 屏
     和 2K 屏不是同一套节奏。tight 同步收到 80。 */
  .sec{ padding:128px 0; }
  .sec.tight{ padding:80px 0; }
  .pgrid{ gap:44px 32px; }
  .listwrap{ grid-template-columns:1fr 400px; }
  .lcard{ grid-template-columns:260px minmax(0,1fr) 160px; }
}

/* ============================================================
   矮视口（可用高度 ≤700px）：1280×720 / 1366×768 的笔记本
   扣掉标签栏、地址栏、书签栏与任务栏后，实际可视高度只剩 600–620。
   不处理的话首屏 553 + 顶栏 77 = 630，比视口还高，下一屏一点都看不到。
   这里只压首屏内部节奏，不缩正文。
   ============================================================ */
@media (max-height:700px){
  .hd .wrap{ height:64px; }
  /* 页头在 ≤760 收到 64 高，遮罩的起点要跟着上移，否则会压住页头下沿 12px */
  .mnav-ck:checked ~ .mnav-mask{ top:64px; }
  .logo img{ height:28px; }

  /* 首屏高度改由视口决定，不再由图片自己的 16:9 反推整行：
     height:calc(100vh - 96px) = 顶栏 64 + 32px 让下一段露出来。
     用 height 而不是 min-height —— min-height 只设下限，行高仍会被内容撑大，
     图就永远缩不下来（量过：设 504 实际还是 515）。
     图片在剩下的空间里 flex 撑满、cover 裁切 —— 666 宽时约 364 高，
     比例 1.83，和原图 1.78 几乎一样，看不出来被裁。 */
  .hero-grid{ height:max(430px, calc(100vh - 96px)); min-height:0; }
  .hero-fig{ flex:1 1 auto; min-height:0; }
  .hero-right img{ height:100%; aspect-ratio:auto; }

  .hero-left{ padding:24px 24px 20px 0; }
  .hero h1{ font-size:var(--fs-num-lg); margin-top:12px; }
  .hero .sub{ font-size:calc(var(--fs-lg)*var(--k)); margin-top:8px; }
  .sform{ margin-top:16px; }
  .sform-r1{ height:52px; }
  .sb-tabs{ margin-top:12px; }
  .sb-panel{ padding-top:8px; }
  .hero-foot{ margin-top:8px; }
}

/* ============================================================
   首页收尾（五件事之后）
   ============================================================
   首页到「选址之外，一家公司能接的五件事」即结束。这一段不是新的一节：
   没有标题、没有底色块，一条发丝线 + 一段说明 + 三个去向。
   把「流程 / 装修 / 需求单」三个出口放在这里，首页就不必再各写一节。 */
.home-end{ padding:44px 0 56px; border-top:1px solid var(--line); display:grid; gap:20px; }
.home-end p{ margin:0; max-width:64ch; color:var(--ink2); font-size:var(--fs-base); line-height:1.9; }
.home-end p a{ display:inline-flex; align-items:center; min-height:24px; color:var(--ink); text-decoration:underline; text-underline-offset:3px; text-decoration-color:var(--line2); }
.home-end p a:hover{ text-decoration-color:var(--brand); }
.home-end-a{ display:flex; flex-wrap:wrap; align-items:center; gap:16px 24px; }
/* 收尾这一排是「现在就走」的动作，不是正文里的行内链接。
   两个 .more 原来没有任何尺寸规则，落到浏览器默认行高 26px —— 手机上点不准。
   与 .btn / .home-tel 统一到同一档高度。 */
.home-end-a .more{ display:inline-flex; align-items:center; min-height:34px;
  font-size:var(--fs-bs); color:var(--ink2);
  border-bottom:1px solid var(--line3); padding-bottom:4px;
  transition:color .2s var(--ease), border-color .2s var(--ease); }
.home-end-a .more:hover{ color:var(--brand); border-color:var(--brand); }
/* 顾问电话（2026-10-20）：需求单是「留个话」，电话是「现在就说」。
   两条并排放在收尾，客户走成本最低的那条。数字用等宽，分组读得清。 */
.home-tel{ display:inline-flex; align-items:center; gap:8px; min-height:32px;
  font-size:var(--fs-bs); color:var(--ink); font-variant-numeric:tabular-nums;
  border-bottom:1px solid var(--ink); padding-bottom:2px;
  transition:color .2s var(--ease), border-color .2s var(--ease); }
.home-tel:hover{ color:var(--brand); border-color:var(--brand); }
.home-tel svg{ flex:0 0 auto; color:var(--ink3); }
@media (max-width:640px){
  .home-end{ padding:32px 0 40px; }
  .home-end-a{ gap:12px 16px; }
  /* 手机上这一排是主要出口，全部抬到 44 —— 只有 .more 两个还停在 34 */
  .home-end-a .more{ min-height:44px; }
  .home-tel{ min-height:44px; }
}
/* 触控档不止 640。641–760（平板竖屏、半屏笔记本）也是手指，
   而上面那两个 44 只写在 ≤640 里 —— 中间的 700 因此一直停在 34 / 32，
   新的 700 档第一次把它量出来（`a.more` 82×34、`a.home-tel` 170×32）。
   这里单独补一条，不动 640 那段的内边距，只补高度。 */
@media (max-width:760px){
  .home-end-a .more{ min-height:44px; }
  .home-tel{ min-height:44px; }
}

/* ============================================================
   孤字（orphan）
   —— 中文段落折行后，末行只剩一两个字，是"不精细"里最容易被一眼看出来的：
      「…带看时实测层 / 高」「…租金按单元单报 / 。」
   这是排版问题，不是文案问题，靠改字去迁就断行是治标 —— 换个屏宽又回来了。

   两条规则分工，不能混用：
   · 短块（2–3 行：栏目说明、按钮旁注、图注）用 balance —— 把两行拉成等长，
     孤字自然消失。Chrome 对 balance 有 6 行上限，正好覆盖这类文字。
   · 长段（超过 6 行）用 pretty —— balance 会失效（超上限后浏览器直接放弃），
     而 pretty 至少能避免末行只剩一个词。

   ⚠ 2026-10-21 实测：只有 pretty 是不够的。Chrome 的 pretty 定义里
   「孤字」= 末行只有一个**词**；中文没有空格，每个字都是一个词，
   于是「末行剩两个字」在它眼里不算孤字，完全不处理。
   中文短块必须用 balance。
   ============================================================ */
.hero-fact,
.stg-l li,
.sv5 em,
.idx-i em,
.cp-sub,
.wall-t p{ text-wrap:balance; }

/* `.dread-l li p`（原 `.dread li p`）：右栏加了 `.dnb` 之后，选择器要收到左栏，
   否则同一条规则会摸到右栏里的段落。右栏现在没有 <p>，但收严不花钱。
   ⚠ 2026-10-23：这里写 pretty 会被这儿的选择器「锁死」——beauty.css 里那条
   `p{text-wrap:balance}` 权重低，改不动 .dtnote，于是全站 5 个页脚的
   「楼盘与房源数据见各详情页标注」永远断成「标注。」单吊一行。改成 balance。 */
.dread-l li p,
.dtnote,
.dul-lead,
.dul-ag p{ text-wrap:balance; }

/* ── 页脚免责说明（2026-10-22 补）────────────────────────────
   首页只加载 ed.css，而 .dtnote 此前在 ed.css 里只有一条 text-wrap，
   字号和行宽全靠浏览器默认值 —— 实测按 16px 渲染、1360 宽下一行排 86 个字，
   比正文还大、还长。它是注释级信息，必须比正文小、比正文短。
   max-width 44em ≈ 44 个字，是中文长段落舒服的上限（闸门卡 46）。 */
.dtnote{
  margin-top:16px;
  font-size:var(--fs-sm);
  line-height:1.75;
  color:var(--ink3);
  letter-spacing:.02em;
  max-width:44em;
}

/* ── 首页企业事实条（2026-10-22）───────────────────────────────
   ⚠ 这一段放在 ed.css 不是 pages.css：index.html 只加载 ed.css（首页自带一套
   版式），写在 pages.css 里的规则对首页**一条都不生效** —— 实测这块上线时
   整块是裸的，直到 adapt 闸门报「热区<24」才暴露。组件跟着页面走。
   一行说清「谁、做什么、多少钱、在哪」—— 这一块是给 AI 抓的锚点，
   也是给第一次进来的人一个 8 秒钟的信任判断。
   视觉上只加上下两根发丝线，不做背景、不做卡片：首屏已经有一张主图，
   这里再加视觉重量，整页就散了。 */
.factband{ border-top:1px solid var(--line); border-bottom:1px solid var(--line); padding:32px 0; }
.factband-in{ display:grid; grid-template-columns:minmax(0,572px) minmax(0,1fr); gap:52px; align-items:start; }
/* 572px 不是随手写的：正文 13px、中文 1 字 ≈ 1em ⇒ 572/13 = 44 字/行，
   压在「每行 ≤46 字」的判据线以内（check_type 第 5 步逐档量）。
   原来是 1.55fr 均分，1440 下左栏 795px、每行 58 字 —— 长句横着铺满，回行会串行。
   ⚠ 别在**网格**上用 em 写这个宽度：grid 的 em 按容器的 16px 算（44em=704px），
   不是按段落的 13px 算 —— 实测那样写每行还是 51 字，判据照样红。
   所以网格用 px 定宽，段落自己再兜一道 max-width:44em（这里的 em 才是 13px）。 */
.factband-txt{ font-size:var(--fs-bs); line-height:1.9; color:var(--ink2); max-width:44em; }
.factband-txt b{ color:var(--ink); font-weight:700; }
.factband-k{ display:grid; grid-template-columns:1fr 1fr; gap:16px 24px; margin:0; }
.factband-k dt{ font-family:var(--sans); font-size:var(--fs-xs); color:var(--ink3); letter-spacing:.06em; }
.factband-k dd{ margin:4px 0 0; font-size:var(--fs-bs); color:var(--ink); }
/* 电话是这一格里唯一能直接拨的入口，必须给足可点高度：
   行内文字只有 20px，鼠标点在字缝里会落空（adapt 闸门第 7 步按 24px 判，
   实测报「热区<24 1 个（A:20）」）。32px 与页脚那几个链接同一口径。 */
.factband-k a{ display:inline-flex; align-items:center; min-height:32px; color:var(--ink); }
.factband-k a:hover{ color:var(--brand); }
/* 2026-10-27：手机上同一处补到 40。32 是给「鼠标点」的（桌面临界 24 + 余量），
   手机上这个电话是**唯一能直接拨出去**的入口，手指落点按 40 才稳。
   只在窄屏改，桌面那一格的四行键值对不能被撑高（整块是首屏下方的节奏块）。 */
@media (max-width:760px){ .factband-k a{ min-height:40px; } }
@media (max-width:860px){
  /* 节奏档只有 {0,8,32,40,44,64,96}（check_unify 第 4 条逐页量）。
     这里原来写 24px —— 桌面档 30px 也是同一个毛病：随手写一个「看着差不多」的数，
     跨页节奏就对不上了。 */
  .factband{ padding:32px 0; }
  .factband-in{ grid-template-columns:1fr; gap:20px; }
}

/* 底部一行分类计数：给「这里有多少存量」一个明确的数。
   没有这一行，读者看到三条会以为整个栏目只有三条。 */
.ins-cats{ display:flex; flex-wrap:wrap; gap:8px; margin-top:32px; }
.ins-cats a{
  display:inline-flex; align-items:baseline; gap:8px;
  padding:8px 16px; border:1px solid var(--line3);
  font-size:var(--fs-sm); color:var(--ink2); transition:border-color .25s, color .25s;
}
/* 2026-10-27：手机上这排分类计数只有 39 高，差 1px 过不了 40 的触控线
   （insight/index.html 三个都是 39 —— 21px 行高 + 上下 8px）。挪到 padding
   而不是 min-height：它和 .ft-more 不同，这里本来就没有基线对齐的邻居。 */
@media (max-width:760px){ .ins-cats a{ padding:9px 16px; } }
.ins-cats a:hover{ border-color:var(--ink); color:var(--ink); }
.ins-cats b{ font-weight:400; color:var(--ink3); font-variant-numeric:tabular-nums; }

/* ============================================================
   首页 3.0 · AI 选址顾问
   ------------------------------------------------------------
   左文案右表单。表单刻意不用卡片（没有背景、没有圆角、没有阴影）——
   只靠一条上墨线起头。卡片会把它读成「一个促销组件」，
   一条线把它读成「一张要填的表」，后者才配得上这个业务。
   ============================================================ */
.ai-wrap{ display:grid; grid-template-columns:minmax(0,1fr) minmax(0,540px); gap:clamp(40px,5vw,80px); align-items:stretch; }
.ai-lead{
  margin:20px 0 0; font-family:var(--serif); font-weight:300;
  font-size:var(--fs-lg); line-height:1.9; color:var(--ink); max-width:30em;
}
.ai-lead b{ font-weight:500; }
.ai-pts{ margin:24px 0 32px; padding:0; list-style:none; }
.ai-pts li{
  position:relative; padding:12px 0 12px 16px; border-top:1px solid var(--line);
  font-size:var(--fs-md); color:var(--ink3); line-height:1.75;
}
.ai-pts li:last-child{ border-bottom:1px solid var(--line); }
.ai-pts li::before{ content:""; position:absolute; left:0; top:21px; width:6px; height:1px; background:var(--ink3); }
.ai-pts b{ color:var(--ink); font-weight:700; }

/* 开放接口入口：一条横贯的窄带，压在这个板块底部。
   它与表单是两件事（一个给客户用，一个给 AI 用），所以不放进表单里，
   放在板块末尾单独立一条线。 */
/* 左右两栏同高（v3.1）：原来右栏只有表单，比左栏矮 250px，
   右下角是一片没有任何内容的纸面，整块看起来像没做完。
   现在两栏 stretch，各自把「最后一行」压到同一底线上 ——
   左边是「开放数据接口」那条横带，右边是表单说明。
   中间多出来的高度变成呼吸区，而不是缺口。 */
.ai-l{ display:flex; flex-direction:column; }
.ai-api{
  display:flex; align-items:baseline; justify-content:space-between; gap:24px;
  margin-top:auto; padding:16px 0;
  border-top:1px solid var(--line); border-bottom:1px solid var(--line);
  transition:border-color .25s;
}
.ai-api:hover{ border-color:var(--ink3); }
.ai-api span{ font-size:var(--fs-md); color:var(--ink); }
.ai-api em{ font-style:normal; font-size:var(--fs-sm); color:var(--ink3); }

.ai-form{ border-top:1px solid var(--ink); padding-top:24px; display:flex; flex-direction:column; }
.ai-f{ display:grid; grid-template-columns:1fr 1fr; gap:20px; margin-bottom:24px; }
.ai-f:last-of-type{ margin-bottom:24px; }
.ai-f label{ display:block; font-size:var(--fs-sm); color:var(--ink3); letter-spacing:.04em; }
.ai-f select, .ai-f input{
  width:100%; margin-top:8px; padding:8px 0;
  border:0; border-bottom:1px solid var(--line3); border-radius:0; background:none;
  font-family:var(--sans); font-size:var(--fs-lg); color:var(--ink);
  transition:border-color .25s;
}
.ai-f select{ appearance:none; background-image:none; cursor:pointer; }
.ai-f select:focus, .ai-f input:focus{ outline:0; border-bottom-color:var(--ink); }
.ai-f input::placeholder{ color:var(--ink4); }
.ai-form .btn{ width:100%; }
/* margin-top:auto 把它压到表单底部，与左栏的「开放数据接口」横带同一底线。
   padding-top 保留原来那 14px 的呼吸，改成 padding 是为了 auto 边距能吃掉剩余空间。 */
.ai-hint{ margin:auto 0 0; padding-top:16px; font-size:var(--fs-xs); color:var(--ink3); line-height:1.75; }
/* ⚠ 2026-10-25：这枚内联链接的行盒只有 17px 高，而闸门（adapt.js）把「可点热区 < 24px」
   当硬项 —— 首页 15 档视口**每一档都判红**，报的就是它（60×17）。
   内联元素加竖向 padding 不会改变行盒高度（不影响任何版面），但会撑大 getBoundingClientRect，
   正好用来补热区：17 + 4 + 3 = 24。不加负 margin —— 竖向内边距本来就不占行高。 */
.ai-hint a{ color:var(--ink); border-bottom:1px solid var(--line3); padding:4px 0 4px; }

/* ── 深墨段：首页「AI 选址顾问」（2026-10-27）────────────────────────
   首页 8,538px／15 个区块，从头到尾是纸白 + 两种浅灰。读到第四屏时，
   眼睛已经分不清「又换了一节」还是「还在上一节」—— 章节边界只能靠
   96px 留白去猜。
   tokens.css 早就备好了 --ink-deep 那一组（关于页、装修页各用过一次），
   规则也写在那儿：「长页读到中段会失去层次，给 1–2 处深墨段，页面才有章节感」。
   这次给它 —— 全站唯一带「工具」性质的区块。深底上一块表单，
   比白底上一块表单更像「这里可以输入」。
   ⚠ 深底上每一处文字都必须重写颜色：全站默认墨色文字，直接套深底 = 黑字压黑底。
     所以下面把这一节里出现的每个类都点了名，一个不落。
   ⚠ 按钮不能沿用 .btn 的墨黑实心（黑底上一块看不见的黑），改品牌红。
     这是全站唯一一枚非首屏的红色实心按钮，理由只有一条：
     它是这一节唯一的行动点，深底上必须有落点。
   ⚠ 下拉的 option 由系统绘制，不受父级 color 控制，必须单独给
     （浅字深底那套在 Windows 上是白底白字，是这里最容易漏的一处）。 */
.sec.deep{ background:var(--ink-deep); }
.sec.deep .sec-k,
.sec.deep .sec-k h2,
.sec.deep h2{ color:var(--on-deep); }
.sec.deep .ai-lead{ color:var(--on-deep2); }
.sec.deep .ai-lead b{ color:var(--on-deep); }
.sec.deep .ai-pts li{
  border-top-color:rgba(var(--white-rgb),.13); color:var(--on-deep2);
}
.sec.deep .ai-pts li:last-child{ border-bottom-color:rgba(var(--white-rgb),.13); }
.sec.deep .ai-pts li::before{ background:var(--on-deep3); }
.sec.deep .ai-pts b{ color:var(--on-deep); }
.sec.deep .ai-api{ border-color:rgba(var(--white-rgb),.16); }
.sec.deep .ai-api:hover{ border-color:rgba(var(--white-rgb),.4); }
.sec.deep .ai-api span{ color:var(--on-deep); }
.sec.deep .ai-api em{ color:var(--on-deep3); }
.sec.deep .ai-form{ border-top-color:var(--on-deep); }
.sec.deep .ai-f label{ color:var(--on-deep3); }
.sec.deep .ai-f select,
.sec.deep .ai-f input{
  color:var(--on-deep); background:none;
  border-bottom-color:rgba(var(--white-rgb),.24);
}
.sec.deep .ai-f select:focus,
.sec.deep .ai-f input:focus{ border-bottom-color:var(--on-deep); }
.sec.deep .ai-f input::placeholder{ color:var(--on-deep3); }
.sec.deep .ai-f select option{ color:var(--ink); background:var(--white); }
.sec.deep .ai-form .btn{
  background:var(--brand); border-color:var(--brand); color:var(--white);
}
.sec.deep .ai-form .btn:hover{ background:var(--brand-d); border-color:var(--brand-d); }
.sec.deep .ai-hint{ color:var(--on-deep3); }
.sec.deep .ai-hint a{ color:var(--on-deep); border-bottom-color:rgba(var(--white-rgb),.3); }

/* 首页这四类短段落补 balance（2026-10-24 实测，见 _dev/_probe_home_widow.mjs）。
   为什么只有这四类：index.html **只加载 ed.css**，而 `p{text-wrap:balance}`
   写在 beauty.css 里（其余页面都加载它，首页不加载）。
   所以首页的段落一直只拿到 body 的 `pretty` —— 而 pretty 是按西文词边界工作的，
   对中文一字未改（beauty.css 头部的 A/B 早就量过）。
   实测这四段在加 balance 前后的末行填充率：
     1440  .ai-hint     18% → 58%
     390   .factband-txt 12% → 87%   .ai-lead 15% → 71%
   ⚠ 不给全局 `p{balance}`：Chrome 的 balance 只在 ≤6 行的块上生效，超过就退回
     普通断行 —— 全局加上会把长段落本来有的 `pretty` 也顶掉，那是净退步。
     这四类都短（各档宽下最多 6 行），所以逐个点名加。 */
.ai-hint,
.sec-sub,
.factband-txt,
.ai-lead,
.biz3 li p{ text-wrap:balance; }

@media (max-width:980px){
  .ai-wrap{ grid-template-columns:1fr; gap:40px; }
}
@media (max-width:600px){
  .ai-f{ grid-template-columns:1fr; gap:16px; }
  .ai-api{ flex-direction:column; gap:8px; }
}

/* ============================================================
   首页 3.0 · 行业资讯（四列栏目版）
   ------------------------------------------------------------
   2026-10-22 老板：「市场报告和行业咨询单独我会发你，不要自己编」。
   所以这一版**没有头条图、没有「最新一篇」** —— 手上没有稿子，
   任何「最新」都是编的。

   改成四列栏目目录：每列一个分类，列 3 个具体标题（都是站内真实页面），
   底部给「全部 N 篇」。信息密度比一大三小高，也不依赖任何配图。
   老板的市场报告到了以后，在这一排前面加一张头条卡即可（.ins-grid 那套
   样式还留着，就是给那时候用的）。
   ============================================================ */
.ins-4{ display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:0 40px; align-items:stretch; }
/* 每列做成一竖列 flex，让「全部 N 篇」压到列底：
   四列的条目长短不一（第一条三行、第三条一行），不用 auto 边距的话
   四条底边会各差几像素，一眼扫过去是没对齐。 */
.ins-c{ display:flex; flex-direction:column; border-top:1px solid var(--ink); padding-top:16px; }
.ins-c-h{ display:flex; align-items:baseline; justify-content:space-between; gap:8px; padding-bottom:16px; }
.ins-c-h span{ font-size:var(--fs-sm); letter-spacing:.06em; color:var(--ink); }
.ins-c-h b{ font-family:var(--serif); font-weight:500; font-size:var(--fs-num); color:var(--ink3); font-variant-numeric:tabular-nums; }
/* 三条标题之间用浅线分隔，最后一条不需要 —— 下面的「全部 N 篇」自己带一条 */
.ins-c ul{ margin:0; padding:0; list-style:none; }
.ins-c li{ border-top:1px solid var(--line); }
.ins-c li:first-child{ border-top:0; }
.ins-c li a{
  display:block; padding:12px 0;
  font-size:var(--fs-md); line-height:1.75; color:var(--ink2);
  transition:color .22s var(--ease);
}
.ins-c li a:hover{ color:var(--brand); }
.ins-c-all{
  display:flex; align-items:center; justify-content:space-between; gap:8px;
  margin-top:auto; padding:12px 0 0; border-top:1px solid var(--line);
  font-size:var(--fs-sm); color:var(--ink3);
}
.ins-c:hover .ins-c-all{ color:var(--ink); }
/* 2026-10-27：手机上「全部 N 篇 →」只有 34 高（21 行高 + 12 上内距）。
   它是卡片底部唯一的出口，也是手指最容易点到的一条，补到 40。 */
@media (max-width:760px){ .ins-c-all{ min-height:40px; } }
@media (max-width:980px){
  .ins-4{ grid-template-columns:1fr 1fr; gap:32px 32px; }
}
@media (max-width:600px){
  .ins-4{ grid-template-columns:1fr; gap:24px; }
}

/* ============================================================
   v3.1 · 图纸语汇（2026-10-22 四轮）
   ------------------------------------------------------------
   老板：「自己在网页生成一些高级的图标、艺术字、图片的剪辑、
   边框、分割线……细节方面再进行全新大规模升级」。

   为什么是「图纸」而不是通用 Web 装饰：
   这家公司做的是写字楼租赁，客户拿到的第一份东西就是平面图。
   定位轴线、图框、图号、标注引线、比例尺 —— 客户天天在看，
   看到同一套语汇出现在网页上，信任是自动建立的；
   换成渐变球、玻璃卡片、粒子背景，反而像另一个行业的官网。

   四条自限：
   1. **不新增字号**。check_type 判「字号必须是 11 档令牌之一」，
      所以所谓艺术字全靠字距、字重、描边、竖排与线来做，
      不靠「再大一号」。全站最大仍是 --fs-display。
   2. **不改图片尺寸**。装饰一律走 outline / 伪元素 / 绝对定位，
      绝不用 border 加宽 —— check_wm 的 W09 判「框比例 == 源图比例」，
      给 img 加 1px 边框就会让 0.5% 阈值擦线。
   3. **hover 全进 @media (hover:hover)**。触屏上 :hover 会粘住，
      手指点完那块区域一直是悬停态。这是存量代码没有做的事，新加的不重犯。
   4. 线只有三个颜色：--line（纸）、--line3（强）、--ink4（装饰）。
      再用第四个灰就是「脏」的开始。
   ============================================================ */

/* ── 1. 图标基类 ──────────────────────────────────────────────
   ⚠️ 类名是 `.ic-i`，**不是 `.ic`**。
   `.ic` 在 pages.css 里已被 assets/portal.js 占用（2026-10-21 那套参数图标：
   16×16 网格、14px 固定、浅灰、按标签文字映射、浏览器里注入到 <dt> 前）。
   两套图标的网格与用途都不同，混用一个类名会让同一张参数表里出现
   两种笔画密度 —— 所以分命名空间，谁的路径谁管。

   尺寸用 em 而不是 px：图标跟着所在文字走，12px 的标签里是 12px 的图标，
   24px 的数字旁边就是 24px —— 不需要在每个组件里各写一个尺寸。
   stroke 用 currentColor，颜色永远和旁边那行字一致，不会出现
   「文字是 ink3、图标是 ink」的半档错位。 */
.ic-i{
  width:1em; height:1em; flex:0 0 auto;
  display:inline-block; vertical-align:-.125em;
  fill:none; stroke:currentColor; stroke-width:1.5;
  stroke-linecap:round; stroke-linejoin:round;
  overflow:visible;
}

/* ── 3. 图片画框（图框）───────────────────────────────────────
   outline 而不是 border：border 会把盒子撑宽 2px，
   W09 的「框比例 == 源图比例」判据阈值是 0.5%，一个 860 宽的图加 2px 就是 0.23%，
   图一多就会擦线；outline + offset:-1px 画在盒子内侧，布局尺寸一个像素都不动。 */
.frm{ outline:1px solid rgba(var(--ink-rgb),.12); outline-offset:-1px; }
/* 图号：图片左上角的小字，像图纸标题栏的图号位。
   底色必须够深 —— 白字压在半透明墨底上，底色的实际亮度取决于**照片**，
   而照片最亮可以到纯白。46% 的墨底在白墙照片上只有 3.54:1，
   对比度闸门判红（2026-10-22 实测，详情页与房源页各 1–2 条）。
   78% 是按「最坏情况：底图纯白」算的：0.78×16 + 0.22×255 = 69，
   白字对比约 9:1，任何照片都过。视觉上与 .dh-more 的 82% 同一档。 */
.frm-no{
  position:absolute; z-index:var(--z-raised);
  top:10px; left:10px; padding:2px 8px;
  font-family:var(--en); font-size:var(--fs-xs); line-height:1.5;
  letter-spacing:.1em; font-variant-numeric:tabular-nums;
  color:var(--white); background:rgba(var(--ink-rgb),.78);
  pointer-events:none;
}

/* 「还有 N 张」（v6.0）：首屏图行只放得下 1–3 张，剩下的必须留个记号，
   否则客户看到一行图就以为「这套就这几张」，而图带在下面要往下滚。
   放在最后一张的右下角，与 .frm-no 同一套视觉语言（墨底白字）：
   一眼能看出这是「张数」而不是照片本身的内容。
   只做视觉、不做点击 —— 外面已经是 <button>（点开大图），
   按钮里再嵌链接是无效结构，读屏会读乱。「看全部」的入口在下面那行小字里。
   对比度按最坏情况（底图纯白）算：0.78 墨底 ≈ 9:1。 */
.frm-more{
  position:absolute; z-index:var(--z-raised);
  right:10px; bottom:10px; padding:4px 8px;
  font-size:var(--fs-xs); line-height:1.5; letter-spacing:.04em;
  color:var(--white); background:rgba(var(--ink-rgb),.78);
  pointer-events:none;
}


/* ── 4. 竖排小字 ──────────────────────────────────────────────
   中文竖排是这套版式里唯一「只有中文能用」的机关 —— 英文竖排要么转字，
   要么读不了。只给图注与侧栏小标用，每页最多一处，多了就像招牌街。 */
.vd{
  writing-mode:vertical-rl; text-orientation:mixed;
  letter-spacing:.26em; line-height:1;
}

/* ── 6. 数字一律等宽 ──────────────────────────────────────────
   tabular-nums 存量已在 62 处使用，但都是逐个类写的。
   这里兜一刀：所有 time / data 属性与 .num 容器。 */
.num,.dhmeta b,.dquotebar .v,[data-num]{ font-variant-numeric:tabular-nums; }

/* ── 7. 触屏不继承 hover ──────────────────────────────────────
   存量里有 200+ 条 :hover 没有包在 (hover:hover) 里。
   全部重写代价太大且容易改坏选择器优先级，所以只对「新加的元素」
   统一走这一条约定：新写的 hover 一律包进媒体查询。
   老的用 @media (hover:none) 逐块归零 —— 见下面各组件段落。 */
@media (hover:none){
  .frm{ outline-color:rgba(var(--ink-rgb),.10); }
}

/* ── 两类物业：两道门（2026-10-23）──────────────────────────────
   老板：「整个房源信息和网站做归类，写字楼，园区两个分类」。
   首页是入口，必须一眼看到分岔 —— 这两个分类之前在全站任何地方都不存在，
   客户只能按区或商圈摸索，而「我要产业园」这件事跟区没关系。

   版式沿用编辑设计的对开：中间一道 1px 竖线，各自「序 + 名称 + 大数 + 一句」。
   不用图：园区与写字楼没有可分辨的分类图，拿灰块或图标凑比留白更难看；
   数字本身就是这两类的差别（1,728 对 496），让它当主角。

   序号写成「01 · Office」而不是全大写英文眉标 —— 后者是这套设计语言里
   明确禁掉的一档（2026-10-21 定）。 */
.sxb{ display:grid; grid-template-columns:1fr 1fr; margin-top:36px; border-top:1px solid var(--ink); }
.sxb-i{ display:block; padding:32px 40px 36px 0; border-right:1px solid var(--line2); transition:background .22s var(--ease); }
.sxb-i + .sxb-i{ padding-left:40px; padding-right:0; border-right:0; }
.sxb-k{ display:block; font-size:var(--fs-sm); color:var(--ink3); letter-spacing:.12em; }
.sxb-t{
  display:block; margin-top:16px; font-family:var(--serif);
  font-size:calc(var(--fs-h2) * var(--k)); font-weight:500;
  letter-spacing:.04em; line-height:1.25; transition:color .22s var(--ease);
}
.sxb-n{
  display:block; margin-top:8px; font-family:var(--serif);
  font-size:calc(var(--fs-display) * var(--k)); font-weight:500;
  font-variant-numeric:tabular-nums; letter-spacing:.01em; line-height:1.1;
}
.sxb-n em{
  font-style:normal; margin-left:8px; font-family:var(--sans);
  font-size:var(--fs-bs); font-weight:400; color:var(--ink3); letter-spacing:.06em;
}
.sxb-s{ display:block; margin-top:16px; max-width:32em; font-size:var(--fs-bs); color:var(--ink2); line-height:1.9; }
.sxb-go{
  display:inline-flex; align-items:center; gap:8px; min-height:44px; margin-top:16px;
  font-size:var(--fs-bs); color:var(--ink); border-bottom:1px solid var(--ink4);
  transition:color .22s var(--ease), border-color .22s var(--ease);
}
.sxb-i:hover .sxb-t{ color:var(--brand); }
.sxb-i:hover .sxb-go{ color:var(--brand); border-color:var(--brand); }
@media (max-width:760px){
  .sxb{ grid-template-columns:minmax(0,1fr); }
  .sxb-i{ padding:24px 0 28px; border-right:0; border-bottom:1px solid var(--line2); }
  .sxb-i + .sxb-i{ padding-left:0; border-bottom:0; }
}

/* ── .adv 在窄屏转单列（2026-10-23）──────────────────────────────
   `.adv` 是「标题 + 说明」的两列网格，原本没有移动端规则：在 390 宽下
   每列只剩 170px，四段说明各挤成五六行、行首参差，读起来比堆成一段还难。
   整备版首页（indexEmptyPage）用它排四条数据标准时暴露出来 ——
   同一时刻 about / services 两页也在用这个类，所以改在这里而不是局部覆盖。 */
@media (max-width:760px){
  .adv{ grid-template-columns:minmax(0,1fr); }
  .adv li{ padding:16px 0; }
  .adv li:nth-child(2n){ padding-left:0; border-left:0; }
}

/* ============================================================
   动效与交互状态层（2026-10-25）
   —— 这一层只做三件事，全部是「补缺」，不改任何已有尺寸与颜色：
      ① 按下态（:active）——全站原来只有 1 处
      ② 禁用态（:disabled）——原来 3 处且没统一
      ③ 尊重「减少动态效果」系统偏好——原来 0 处
   —— 刻意不做的事（都是为了不变成「炫技」）：
      · 不加骨架屏。本站搜索与筛选是**全量数据在客户端**
        （assets/data/buildings.js 一次载入，portal.js 纯前端过滤），
        没有「等待中」这个状态。给不存在的过程配动画，等于骗人。
      · 不做滚动视差、不做自动播放视频。2026 年 B2B 的共识是克制动效：
        自动播放视频的跳出率高 40%，无字幕视频完播率只有 27%。
   ============================================================ */

/* ── ① 按下态 ─────────────────────────────────────────────────
   为什么必须有：hover 回答「这里能点」，active 才回答「你点到了」。
   缺 active 的站点，点下去没反应，用户会以为没点上，于是再点一次 ——
   在提交需求单的场景里，这一下就是重复提交。
   做法：块级按钮位移 1px。位移**不参与布局**（不触发重排），
   所以不会推挤相邻元素，版面一毫米不动。
   ⚠ 不用 scale(.98)：44px 高的按钮上 1px 是 2.3%，而 scale 会把内部文字
     一起缩小，中文小字缩完会糊。 */
.btn:active,
.biz-go:active,
.lc-go:active,
.sb-go:active,
.stg-go:active,
.sxb-go:active,
.mcta:active,
.uarch-cta:active,
.dp-btn:active,
.gal-btn:active,
.dtop-cta:active,
.hero-call:active,
.empty .ea button:active,
.empty .ea a:active{
  transform:translateY(1px);
  /* 按下要比 hover 更快「跟手」：60ms 而不是 160ms。
     这不是新的一档节奏，是「触觉同步」——超过 100ms 就觉得迟。 */
  transition-duration:60ms;
}
.btn.pri:active{ background:var(--brand-deep); border-color:var(--brand-deep); }
.co .btn:active{ background:var(--ink-press); border-color:var(--ink-press); }
/* 图标不要在按钮位移之外再位移一次，否则看着抖两下 */
.btn:active .ic-i, .hero-call:active .ic-i{ transform:none; }

/* ── ② 禁用态 ─────────────────────────────────────────────────
   本站禁用态很少，但一旦出现必须一眼看出不能点。
   pointer-events:none 是防止「双击的第二下落到已禁用元素上」
   —— 表单提交后按钮立即禁用，就是这么防重复提交的。 */
button:disabled,
input:disabled,
select:disabled,
textarea:disabled,
.btn[aria-disabled="true"],
a[aria-disabled="true"]{
  opacity:.42;
  cursor:not-allowed;
  pointer-events:none;
}

/* ── ③ 减少动态效果 ───────────────────────────────────────────
   macOS「减弱动态效果」、Windows「显示动画：关」、以及前庭功能障碍用户
   都会打开这个偏好。全站原来一处都没处理：这些人看到的是
   16px 上移 + 0.8 秒淡入，在 8000px 的长页上连续触发十几次。
   处理方式不是「变快」，是「取消位移、只留极短淡入」——
   位移动画是引发眩晕的主因，淡入几乎不会。
   ⚠ 最后那条 .rv 是安全网：.rv 初始 opacity:0，靠 JS 加 .in 才显示。
     若 JS 被拦（CSP / 老浏览器 / 脚本 404），整页内容会永远不可见。
     这里强制显示，等于给 .rv 一条不依赖 JS 的兜底。 */
@media (prefers-reduced-motion:reduce){
  *, *::before, *::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
    scroll-behavior:auto !important;
  }
  .rv{ opacity:1 !important; transform:none !important; }
  .btn:active, .biz-go:active, .lc-go:active, .sb-go:active,
  .stg-go:active, .sxb-go:active, .mcta:active, .uarch-cta:active,
  .dp-btn:active, .gal-btn:active, .dtop-cta:active, .hero-call:active{
    transform:none;
  }
}

/* ══ 交互状态补全（2026-10-26 · DEEP-1026 判据 D）════════════════════════
   ⚠ 为什么写在 ed.css 而不是 beauty.css：**首页只引 tokens + ed**。
   tokens → ed → pages → beauty → premium 是内页的加载链，首页只走前两层。
   补丁放进 beauty.css 时，实测 index.html 的 active 覆盖率仍只有 8%，
   而内页已经到 47% —— 同一份规则在两个页面上效果截然不同，
   原因就是首页根本没加载那个文件。改这一层，全站 4.7 万页一次覆盖。

   来源：M3 State Layers「Hover +8% / Focus +10% / Press +10%」；
        Apple HIG Buttons「Always include a pressed state — without one,
        users may think the button isn't responding」。
   实测基线：hover 76.1%、active 11.0%（缺的全是页头导航与页脚出口）。 */
.nav a:active,
.ft li a:active,
.ft-more:active,
.logo:active,
.car-t:active,
.chip:active,
.gal-btn:active { opacity:.62; }

.ft-more:hover{ color:var(--ink); text-decoration:underline; text-underline-offset:3px; }
.logo:hover{ opacity:.85; }
.car-t:hover img{ opacity:.86; }

/* 兜底：任何链接/按钮按下时都有反馈。
   上面那批精确类名覆盖了导航、页脚、缩略条、chip、图集按钮（约 60% 的元素），
   剩下的是电话链接、页脚列标题出口、目录条这类零散结构 —— 逐个点名的写法
   永远会漏（本轮先漏了 .ft-more，补完又漏了 .ft-tel）。
   与其追着漏网之鱼补选择器，不如用一条覆盖全站的行为规则：
   **按下时视觉必须有变化**，这是 M3 / Apple HIG 的共同要求，与具体组件无关。
   0.72 比精确规则的 0.62 稍轻，避免和已有 transform 反馈叠加后显得过暗。 */
a[href]:active,
button:active { opacity:.72; }

/* 视觉隐藏，但语义与 Tab 序列都保留（2026-10-27）。
   用途：页面在视觉上不需要标题，但 h1 不能没有 —— audit3000 与 audit_ui 都以
   「整页没有 h1」判 P0，读屏器与搜索引擎也靠它认页面主体。找楼页首屏改为
   「打开就筛选」后，标题让位给筛选面板，h1 退到这里。
   ⚠ 不要改成 display:none / visibility:hidden / opacity:0：
   三条闸门的可见性判据都是「宽高≥1 且 opacity>0.05」，那样会变成「0 个 h1」。
   尺寸留 1px 是刻意的 —— 既满足「宽高≥1」，又不占版面。
   position 必须带 !important（audit3000 对 .sr/.sr-only 的硬规定）：
   使用方的组件类与它同权时会把绝对定位顶掉，隐形标题就会跳出来占一整行。
   颜色取 --ink 而不是浅灰：视觉上不可见，但万一被对比度闸门扫到也必须合规。 */
.sr-only{
  position:absolute !important;
  width:1px; height:1px; margin:-1px; padding:0; border:0;
  overflow:hidden; clip-path:inset(50%); white-space:nowrap;
  color:var(--ink);
}
