/* ============================================================
   VANSHI · 办公空间自助设计工具  assets/tool.css
   ── 换肤自老板的「办公室设计助手」独立页：
      青绿体系（#0b7f73）整体换成万仕行的纸 / 墨 / 线 / 品牌红，
      字号收进 tokens.css 的 11 档、圆角收到 2–4px、去掉两处毛玻璃。
      本文件只管工具本体；页面外壳（站头 / 首屏标题 / 页脚）由 gen_site.js 出，
       所以这里不再写 html,body{height:100%;overflow:hidden} —— 页面要能滚。
   ============================================================ */
    /* 图标雪碧图的容器：整段 <symbol> 定义不该占版面，但也不能用 display:none ——
       某些浏览器会因此不渲染 <use> 引用的符号。原来这三行写在行内 style 里，
       每次改都要去 HTML 里找；现在归位到样式表。 */
    .icon-sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

    /* 工具页原来自己维护一整套调色盘：17 个变量，值是从 tokens.css 抄过来的。
       抄的时候对得上，但下次改主色要改两个文件 —— 这就是「同一件事在四处说四个答案」的入口。
       现在只保留名字（工具页里 500 多处 var(--xxx) 一行不用动），值统一指回共享令牌：
       名字与共享令牌同名的（--ink / --line / --white / --brand）直接删掉，从 tokens.css 继承；
       名字不同的写成别名。--topbar-h 这几个是工具页自己的版式尺寸，不属于全站令牌，留在这里。 */
    :root {
      --ink-2: var(--ink2);
      --muted: var(--ink3);
      --line-strong: var(--line3);
      --canvas: var(--paper2);
      --panel: var(--white);
      --brand-dark: var(--brand-d);
      --brand-soft: var(--brand-wash2);
      /* 2026-10-26：--rose / --amber / --amber-soft 三个功能色此前只被引用、
         从没定义过（规则里是裸 var()，浏览器直接丢弃整条声明）。
         它们现在定义在 tokens.css 的 :root 里，名字与引用处一致，
         **这里不写任何别名行** —— 同名令牌本来就继承得到。
         ⚠ 千万别写 `--rose: var(--rose)`：那是自引用，
         CSS 变量循环依赖会让它变成 guaranteed-invalid，
         比「未定义」更糟 —— 未定义时至少还有别的层能补上。 */
      --shadow: 0 7px 26px rgba(var(--ink-rgb), 0.08);
      --shadow-sm: 0 2px 8px rgba(var(--ink-rgb), 0.07);
      --topbar-h: 56px;
      --rail-w: 82px;
      --library-w: 342px;
      --status-h: 36px;
    }

    * { box-sizing: border-box; }
    body {
      color: var(--ink);
      font-family: -apple-system,BlinkMacSystemFont,"PingFang SC","Microsoft YaHei","Helvetica Neue",Arial,sans-serif;
      -webkit-font-smoothing: antialiased;
    }
    button, input, select { font: inherit; }
    button { color: inherit; }
    button:focus-visible, input:focus-visible, select:focus-visible {
      outline: 2px solid rgba(var(--brand-rgb), 0.46);
      outline-offset: 2px;
    }
    button:disabled { cursor: not-allowed; opacity: 0.38; }
    .icon { width: 19px; height: 19px; flex: 0 0 auto; display: block; }
    .sr-only {
      position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px;
      overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
    }

    /* 工具带：整幅通栏，上下各一根发丝线，与页面正文分开。
       高度跟着视口走，但保底 520px —— 再矮画布就没法用了。 */
    .tool-stage{ background:var(--canvas); border-top:1px solid var(--line); border-bottom:1px solid var(--line); }
    .app {
      /* 2026-10-20 整屏应用页：站头 77px + tool-stage 上下发丝线 2px，
         工具撑满剩下整个视口，页脚/首屏标题区已撤（gen_site.js toolsPage）。
         100dvh 而非 100vh：手机浏览器地址栏收放时跟着缩，不会把状态栏顶掉。 */
      height: calc(100dvh - 79px);
      min-height: 480px;
      display: grid;
      grid-template-rows: var(--topbar-h) minmax(0, 1fr);
      background: var(--canvas);
    }

    .topbar {
      position: relative;
      z-index: var(--z-topbar);
      height: var(--topbar-h);
      display: flex;
      align-items: center;
      gap: 20px;
      padding: 0 16px;
      background: var(--white);
      border-bottom: 1px solid var(--line);
    }
    .brand {
      min-width: 0;
      display: flex;
      align-items: center;
      gap: 8px;
      white-space: nowrap;
    }
    /* 用官网那个红底 VS 标，不用通用图标 —— 工具条是产品身份，
       和上面站头同一个标，客户才知道这是万仕行自己的工具。 */
    .brand-mark {
      width: 38px;
      height: 29px;
      flex: 0 0 auto;
      display: grid;
      place-items: center;
    }
    .brand-mark img { width: 100%; height: 100%; object-fit: contain; display: block; }
    .brand-copy { display: grid; gap: 2px; }
    /* 页面级 h1（2026-10-20 从首屏标题区移进工具顶栏）：视觉与原来的
       <strong> 完全一致 —— 14px / 700 / 行高 1.2，h1 的 UA 默认样式全部清零。
       字号 14 在 tokens 的 11 档里，type 闸门过得去。 */
    .brand-title { margin: 0; font-size:var(--fs-md); font-weight: 700; line-height: 1.2; letter-spacing: 0; font-family: inherit; }
    .brand-copy span { color: var(--muted); font-size:var(--fs-xs); line-height: 1.2; }
    .project-wrap {
      min-width: 0;
      display: flex;
      align-items: center;
      gap: 8px;
      flex: 1;
    }
    .project-label {
      flex: 0 0 auto;
      color: var(--muted);
      font-size:var(--fs-sm);
      padding: 4px 7px;
      border-radius:var(--r-1);
      background: var(--paper2);
    }
    .project-name {
      min-width: 170px;
      max-width: 460px;
      width: min(32vw, 420px);
      height: 34px;
      padding: 0 8px;
      color: var(--ink);
      font-size:var(--fs-bs);
      font-weight: 600;
      text-overflow: ellipsis;
      background: transparent;
      border: 1px solid transparent;
      border-radius:var(--r-1);
    }
    .project-name:hover { border-color: var(--line); background: var(--white); }
    .project-name:focus { border-color: var(--line-strong); background: white; }
    .top-actions {
      display: flex;
      align-items: center;
      gap: 6px;
      margin-left: auto;
    }
    .action-group {
      display: flex;
      align-items: center;
      gap: 2px;
      padding-right: 8px;
      margin-right: 2px;
      border-right: 1px solid var(--line);
    }
    .icon-btn, .soft-btn, .primary-btn {
      height: 40px;
      min-width: 34px;   /* 只剩一个图标的 primary-btn 会缩到 31，按不准 */
      display: inline-flex;
      align-items: center;
      justify-content: center;
      gap: 7px;
      border: 1px solid transparent;
      border-radius:var(--r-1);
      background: transparent;
      cursor: pointer;
      white-space: nowrap;
      transition: background 140ms var(--ease), border-color 140ms var(--ease), color 140ms var(--ease);
    }
    .icon-btn { width: 38px; padding: 0; color: var(--ink-2); }
    .icon-btn:hover:not(:disabled), .soft-btn:hover:not(:disabled) { background: var(--paper2); }
    .soft-btn {
      padding: 0 12px;
      color: var(--ink-2);
      border-color: var(--line);
      background: white;
      font-size:var(--fs-sm);
      font-weight: 600;
    }
    .primary-btn {
      padding: 0 16px;
      color: white;
      background: var(--brand);
      border-color: var(--brand);
      font-size:var(--fs-sm);
      font-weight: 700;
      box-shadow: var(--shadow-sm);
    }
    .primary-btn:hover { background: var(--brand-dark); border-color: var(--brand-dark); }
    .save-state {
      height: 26px;
      display: inline-flex;
      align-items: center;
      gap: 6px;
      margin-right: 5px;
      padding: 0 8px;
      color: var(--muted);
      font-size:var(--fs-xs);
      border-radius:var(--r-1);
      background: var(--paper2);
      white-space: nowrap;
    }
    .save-state::before {
      content: "";
      width: 6px;
      height: 6px;
      border-radius: 50%;
      background: var(--ink2);
    }
    .save-state.saving::before { background: var(--ink4); }
    .save-state.error::before { background: var(--brand); }

    .workspace {
      min-height: 0;
      display: grid;
      grid-template-columns: var(--rail-w) minmax(0, 1fr) var(--library-w);
    }
    .toolrail {
      position: relative;
      z-index: var(--z-chrome);
      min-height: 0;
      display: flex;
      flex-direction: column;
      align-items: stretch;
      gap: 5px;
      padding: 12px 9px 10px;
      background: var(--panel);
      border-right: 1px solid var(--line);
      overflow-y: auto;
      scrollbar-width: none;
    }
    .toolrail::-webkit-scrollbar { display: none; }
    .tool-btn {
      min-height: 55px;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      gap: 5px;
      padding: 6px 3px;
      color: var(--ink3);
      border: 1px solid transparent;
      border-radius:var(--r-1);
      background: transparent;
      cursor: pointer;
      transition: color 140ms var(--ease), background 140ms var(--ease), border-color 140ms var(--ease);
    }
    .tool-btn .icon { width: 20px; height: 20px; }
    .tool-btn span { font-size:var(--fs-xs); font-weight: 600; line-height: 1.2; }
    .tool-btn:hover { color: var(--ink); background: var(--paper2); }
    .tool-btn.active {
      color: var(--brand-dark);
      background: var(--brand-soft);
      border-color: rgba(var(--brand-rgb), 0.16);
    }
    .rail-separator { height: 1px; margin: 5px 6px; background: var(--line); }
    .rail-spacer { flex: 1; min-height: 8px; }
    .rail-help {
      display: grid;
      place-items: center;
      gap: 3px;
      min-height: 48px;
      color: var(--muted);
      font-size:var(--fs-xs);
      text-align: center;
      line-height: 1.3;
    }
    .rail-help .icon { width: 16px; height: 16px; }

    .canvas-column {
      position: relative;
      min-width: 0;
      min-height: 0;
      display: grid;
      grid-template-rows: minmax(0, 1fr) var(--status-h);
      overflow: hidden;
      background: var(--canvas);
    }
    .stage-shell {
      position: relative;
      min-height: 0;
      overflow: hidden;
      background:
        radial-gradient(circle at 1px 1px, rgba(var(--ink-rgb), 0.07) 1px, transparent 1px) 0 0 / 22px 22px,
        var(--paper3);
    }
    .stage-shell.dragging-file::after {
      content: "";
      position: absolute;
      inset: 16px;
      z-index: var(--z-pop);
      border: 2px dashed var(--brand);
      border-radius:var(--r-2);
      background: rgba(var(--brand-wash2-rgb), 0.9);
      pointer-events: none;
    }
    .stage-frame {
      position: absolute;
      inset: 25px;
      display: grid;
      place-items: center;
      pointer-events: none;
    }
    #stage {
      width: 100%;
      height: 100%;
      display: block;
      pointer-events: auto;
      overflow: visible;
      filter: drop-shadow(0 7px 18px rgba(var(--ink-rgb), 0.12));
      touch-action: none;
      user-select: none;
    }
    #stage[data-tool="select"] { cursor: default; }
    #stage[data-tool="wall"] { cursor: crosshair; }
    #stage[data-tool="room"] { cursor: crosshair; }
    #stage[data-tool="hand"] { cursor: grab; }
    #stage[data-tool="eraser"] { cursor: not-allowed; }
    /* 拖动平移时压过 [data-tool="hand"] 的 grab。两条都是 #stage 上的等权规则，
       本行排在后面就已经胜出 —— 原来的 !important 是多余的，删掉后行为不变（已用计算样式验过）。 */
    #stage.panning { cursor: grabbing; }
    .canvas-context {
      position: absolute;
      top: 14px;
      left: 14px;
      z-index: var(--z-float);
      display: flex;
      align-items: center;
      gap: 7px;
      max-width: calc(100% - 210px);
      min-height: 34px;
      padding: 5px 9px 5px 6px;
      color: var(--ink-2);
      font-size:var(--fs-xs);
      background: var(--white);
      border: 1px solid var(--line-strong);
      border-radius:var(--r-1);
      box-shadow: var(--shadow-sm);
    }
    .tool-avatar {
      width: 24px;
      height: 24px;
      display: grid;
      place-items: center;
      flex: 0 0 auto;
      color: var(--brand-dark);
      background: var(--brand-soft);
      border-radius:var(--r-1);
    }
    .tool-avatar .icon { width: 14px; height: 14px; }
    .context-copy { min-width: 0; display: flex; align-items: center; gap: 7px; }
    .context-copy strong { flex: 0 0 auto; color: var(--ink); font-size:var(--fs-sm); }
    .context-copy span {
      min-width: 0;
      overflow: hidden;
      color: var(--muted);
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    .plan-chip {
      display: none;
      align-items: center;
      gap: 5px;
      max-width: 190px;
      margin-left: 4px;
      padding-left: 8px;
      border-left: 1px solid var(--line);
      color: var(--ink-2);
      font-size:var(--fs-xs);
    }
    .plan-chip.show { display: flex; }
    .plan-chip span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .plan-chip .icon { width: 14px; height: 14px; color: var(--brand); }
    .empty-state {
      position: absolute;
      top: 50%;
      left: 50%;
      z-index: var(--z-pop);
      width: min(440px, calc(100% - 60px));
      transform: translate(-50%, -50%);
      text-align: center;
      pointer-events: none;
    }
    .empty-state[hidden] { display: none; }
    /* 空态里的示例平面图（2026-10-20 从页面的 figure 图注搬来）：
       既回答「能拿什么开工」，也承担字号闸门「每页至少一张 ≥80×60 的图」。
       只缩不放：源图 861×405，这里最大 340px 宽（0.39×），裁切 0。
       原来 210px —— 画布 740px 宽，一张 210px 的平面图缩在正中，
       看着像「这张图没加载出来」而不是「这就是你要上传的东西」。 */
    .empty-plan {
      width: min(340px, 72vw);
      margin: 0 auto 16px;
    }
    .empty-plan img {
      display: block;
      width: 100%;
      height: auto;
      background: var(--white);
      border: 1px solid var(--line-strong);
      border-radius:var(--r-1);
    }
    .empty-plan-cap {
      display: block;
      margin-top: 6px;
      color: var(--muted);
      font-size:var(--fs-xs);
      line-height: 1.5;
    }
    /* 空态标题保持段落 + 类名：页面级 h1 在工具顶栏的品牌名
       （2026-10-20 从首屏标题区移进来），一页只能有一个（SEO 闸门判红）。
       24px 是字号阶梯上的 --fs-h3。 */
    .empty-title {
      margin: 0;
      color: var(--ink);
      font-size:var(--fs-h3);
      font-weight: 700;
      line-height: 1.35;
      letter-spacing: 0;
    }
    .empty-state p {
      margin: 7px 0 16px;
      color: var(--muted);
      font-size:var(--fs-sm);
      line-height: 1.7;
    }
    .empty-actions {
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 8px;
      flex-wrap: wrap;
      pointer-events: auto;
    }
    .empty-actions .primary-btn, .empty-actions .soft-btn { height: 38px; padding: 0 16px; }
    /* 手机上空态的三个按钮是这一页最重要的入口（生成方案 / 上传平面图 / 看示例），
       38 高偏小。桌面保持 38 的密度，手机上抬到 44。工具条里的 32 高小控件
       不跟着抬 —— 那是应用surface的常规密度，WCAG 2.2 AA 的下限是 24。 */
    @media (max-width: 560px) {
      .empty-actions .primary-btn, .empty-actions .soft-btn, .empty-actions .text-btn { min-height: 44px; }
    }
    .text-btn {
      height: 34px;
      padding: 0 6px;
      color: var(--muted);
      font-size:var(--fs-xs);
      border: 0;
      background: transparent;
      cursor: pointer;
    }
    .text-btn:hover { color: var(--ink); }
    .zoom-box {
      position: absolute;
      left: 14px;
      bottom: 14px;
      z-index: var(--z-float);
      height: 34px;
      display: flex;
      align-items: center;
      gap: 1px;
      padding: 2px;
      background: var(--white);
      border: 1px solid var(--line-strong);
      border-radius:var(--r-1);
      box-shadow: var(--shadow-sm);
    }
    /* 缩放手柄是画布里最常按的一对键，28 高在触屏笔电上偏小；提到 32，
       与全站地图缩放的 32 对齐。 */
    .zoom-box .icon-btn { width: 32px; height: 32px; }
    .zoom-value {
      min-width: 50px;
      padding: 0 5px;
      color: var(--ink-2);
      font-size:var(--fs-xs);
      text-align: center;
    }
    .canvas-legend {
      position: absolute;
      right: 14px;
      bottom: 14px;
      z-index: var(--z-float);
      display: flex;
      align-items: center;
      gap: 7px;
      height: 28px;
      padding: 0 9px;
      color: var(--muted);
      font-size:var(--fs-xs);
      background: var(--white);
      border: 1px solid var(--line);
      border-radius:var(--r-1);
    }
    .legend-line { width: 22px; height: 4px; border-radius:var(--r-1); background: var(--ink2); }
    .statusbar {
      min-width: 0;
      display: flex;
      align-items: center;
      gap: 12px;
      padding: 0 16px;
      color: var(--muted);
      font-size:var(--fs-xs);
      background: var(--panel);
      border-top: 1px solid var(--line);
    }
    .status-item {
      display: inline-flex;
      align-items: center;
      gap: 5px;
      white-space: nowrap;
    }
    .status-item .icon { width: 13px; height: 13px; }
    /* 「办公室平面 · 按厘米绘」这条提示只在有富余时才成立：
       1024 下状态栏总内容比栏体宽 7px，最后 3 个字符被 .canvas-column 的
       overflow:hidden 切掉（排版取证 H03 抓到）。它不是数据，是提示，
       宽度不够就整条收掉，比切一半留个「按厘米」更像话。 */
    @media (max-width: 1200px) { .statusbar .mobile-status { display: none; } }
    .status-spacer { flex: 1; }
    .coord-readout { min-width: 126px; font-variant-numeric: tabular-nums; }

    .library {
      position: relative;
      z-index: var(--z-chrome);
      min-width: 0;
      min-height: 0;
      display: flex;
      flex-direction: column;
      background: var(--panel);
      border-left: 1px solid var(--line);
    }
    .library-head {
      flex: 0 0 auto;
      display: flex;
      align-items: center;
      gap: 8px;
      padding: 12px 16px 8px;
    }
    .library-head h2 { margin: 0; font-size:var(--fs-md); letter-spacing: 0; }
    .library-count {
      margin-left: auto;
      color: var(--muted);
      font-size:var(--fs-xs);
      white-space: nowrap;
    }
    .library-close { display: none; }
    .library-tabs {
      flex: 0 0 auto;
      display: grid;
      grid-template-columns: repeat(4, minmax(0, 1fr));
      margin: 0 16px 12px;
      padding: 3px;
      background: var(--paper3);
      border-radius:var(--r-1);
    }
    .library-tab {
      height: 32px;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      gap: 4px;
      padding: 0 3px;
      color: var(--ink3);
      font-size:var(--fs-sm);
      font-weight: 600;
      white-space: nowrap;
      border: 0;
      border-radius:var(--r-1);
      background: transparent;
      cursor: pointer;
    }
    .library-tab .icon { width: 14px; height: 14px; }
    .library-tab.active {
      color: var(--ink);
      background: white;
      box-shadow: 0 1px 4px rgba(var(--ink-rgb), 0.09);
    }
    .library-body {
      min-height: 0;
      flex: 1;
      overflow-y: auto;
      padding: 0 16px 16px;
      scrollbar-color: var(--scroll) transparent;
      scrollbar-width: thin;
    }
    .panel[hidden] { display: none; }
    .search-wrap { position: relative; margin-bottom: 8px; }
    .search-wrap .icon {
      position: absolute;
      top: 50%;
      left: 10px;
      width: 15px;
      height: 15px;
      transform: translateY(-50%);
      color: var(--ink5);
      pointer-events: none;
    }
    .search-input {
      width: 100%;
      height: 36px;
      padding: 0 8px 0 32px;
      color: var(--ink);
      font-size:var(--fs-xs);
      background: white;
      border: 1px solid var(--line);
      border-radius:var(--r-1);
    }
    .search-input::placeholder { color: var(--ink4); }
    .category-row {
      display: flex;
      gap: 5px;
      margin: 0 -1px 11px;
      overflow-x: auto;
      scrollbar-width: none;
    }
    .category-row::-webkit-scrollbar { display: none; }
    .category-chip {
      /* 27px：鼠标点得中，手指点不准。这一排是设计助手里最常点的控件
         （全部/工位/会议/休闲/专注/储物/接待），撑到 34 —— 与站内
         .sb-tabs / .fsum 的触控档同高，且不至于把工具栏撑高一倍。 */
      height: 34px;
      padding: 0 12px;
      flex: 0 0 auto;
      color: var(--ink3);
      font-size:var(--fs-xs);
      border: 1px solid var(--line);
      border-radius:var(--r-1);
      background: transparent;
      cursor: pointer;
    }
    .category-chip.active {
      color: var(--brand-dark);
      border-color: rgba(var(--brand-rgb), 0.24);
      background: var(--brand-soft);
    }
    .furniture-grid {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: 8px;
    }
    .furniture-card {
      min-width: 0;
      display: grid;
      grid-template-rows: 62px auto;
      padding: 0;
      overflow: hidden;
      text-align: left;
      background: white;
      border: 1px solid var(--line);
      border-radius:var(--r-1);
      cursor: grab;
      transition: border-color 140ms var(--ease), box-shadow 140ms var(--ease), transform 140ms var(--ease);
    }
    .furniture-card:hover {
      border-color: var(--line-hover);
      box-shadow: var(--shadow-sm);
      transform: translateY(-1px);
    }
    .furniture-card:active { cursor: grabbing; }
    .furniture-card.selected {
      border-color: var(--brand);
      box-shadow: inset 0 0 0 1px var(--brand);
    }
    .furniture-thumb {
      display: grid;
      place-items: center;
      overflow: hidden;
      background: var(--paper2);
    }
    .furniture-thumb svg { width: 84%; height: 84%; }
    .furniture-copy { padding: 7px 8px 8px; min-width: 0; }
    .furniture-copy strong {
      display: block;
      overflow: hidden;
      color: var(--ink);
      font-size:var(--fs-xs);
      line-height: 1.35;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    .furniture-copy span {
      display: block;
      margin-top: 2px;
      color: var(--muted);
      font-size:var(--fs-xs);
      font-variant-numeric: tabular-nums;
    }
    .empty-result {
      grid-column: 1 / -1;
      padding: 28px 8px;
      color: var(--muted);
      font-size:var(--fs-sm);
      text-align: center;
    }
    .section-label {
      display: flex;
      align-items: center;
      gap: 6px;
      margin: 0 0 9px;
      color: var(--ink-2);
      font-size:var(--fs-xs);
      font-weight: 700;
    }
    .section-label .icon { width: 14px; height: 14px; color: var(--brand); }
    .floor-note {
      margin: 0 0 16px;
      color: var(--muted);
      font-size:var(--fs-xs);
      line-height: 1.6;
    }
    .target-pill {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      min-height: 27px;
      margin-bottom: 12px;
      padding: 4px 9px;
      color: var(--ink-2);
      font-size:var(--fs-xs);
      border: 1px solid var(--line);
      border-radius:var(--r-1);
      background: white;
    }
    .target-pill strong { color: var(--brand-dark); font-weight: 700; }
    .material-grid {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: 8px;
    }
    .material-card {
      position: relative;
      min-width: 0;
      padding: 0;
      overflow: hidden;
      text-align: left;
      background: white;
      border: 1px solid var(--line);
      border-radius:var(--r-1);
      cursor: pointer;
    }
    .material-card:hover { border-color: var(--line-hover); }
    .material-card.active { border-color: var(--brand); box-shadow: inset 0 0 0 1px var(--brand); }
    .material-preview { height: 48px; position: relative; }
    .material-copy {
      display: flex;
      align-items: center;
      gap: 4px;
      padding: 6px 8px 7px;
      min-width: 0;
    }
    .material-copy strong {
      overflow: hidden;
      color: var(--ink);
      font-size:var(--fs-sm);
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    .material-check {
      display: none;
      width: 16px;
      height: 16px;
      place-items: center;
      margin-left: auto;
      color: white;
      background: var(--brand);
      border-radius: 50%;
    }
    .material-card.active .material-check { display: grid; }
    .material-check .icon { width: 11px; height: 11px; }
    .settings-block {
      margin-top: 16px;
      padding-top: 16px;
      border-top: 1px solid var(--line);
    }
    .setting-row {
      display: flex;
      align-items: center;
      gap: 8px;
      min-height: 33px;
      color: var(--ink-2);
      font-size:var(--fs-xs);
    }
    .setting-row label { min-width: 66px; }
    /* 滑块和开关都按 ≥24px 触控高度做 —— 检查页会量热区，且手机上本来就不该抠 16px。 */
    .setting-row input[type="range"] { flex: 1; min-width: 60px; height: 24px; accent-color: var(--brand); }
    .setting-row output { width: 34px; text-align: right; font-variant-numeric: tabular-nums; }
    .switch {
      position: relative;
      width: 38px;
      height: 24px;
      margin-left: auto;
      display: inline-flex;
      align-items: center;
      cursor: pointer;
    }
    /* 输入框铺满整个开关：既保焦点可达，热区也就是 38×24 */
    .switch input { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; }
    .switch span {
      width: 38px;
      height: 24px;
      border-radius:var(--r-1);
      background: var(--line3);
      transition: background 140ms var(--ease);
    }
    .switch span::after {
      content: "";
      position: absolute;
      top: 4px;
      left: 4px;
      width: 16px;
      height: 16px;
      border-radius: 50%;
      background: white;
      box-shadow: 0 1px 3px rgba(var(--ink-rgb), 0.2);
      transition: transform 140ms var(--ease);
    }
    .switch input:checked + span { background: var(--brand); }
    .switch input:checked + span::after { transform: translateX(14px); }
    .upload-mini {
      width: 100%;
      justify-content: center;
      margin-top: 12px;
    }
    .template-list { display: grid; gap: 8px; }
    .template-card {
      width: 100%;
      display: grid;
      grid-template-columns: 104px minmax(0, 1fr);
      gap: 12px;
      align-items: center;
      padding: 8px;
      text-align: left;
      background: white;
      border: 1px solid var(--line);
      border-radius:var(--r-1);
      cursor: pointer;
    }
    .template-card:hover { border-color: var(--line-hover); box-shadow: var(--shadow-sm); }
    .template-preview {
      height: 66px;
      display: grid;
      place-items: center;
      background: var(--paper3);
      border-radius:var(--r-1);
      overflow: hidden;
    }
    .template-preview svg { width: 94%; height: 94%; }
    .template-copy { min-width: 0; display: grid; gap: 4px; }
    .template-copy strong { font-size:var(--fs-sm); line-height: 1.3; }
    .template-copy span { color: var(--muted); font-size:var(--fs-sm); line-height: 1.45; }
    .selection-panel {
      position: sticky;
      top: 0;
      z-index: var(--z-raised);
      margin-bottom: 12px;
      padding: 12px;
      background: var(--paper2);
      border: 1px solid var(--line3);
      border-radius:var(--r-1);
      box-shadow: 0 6px 16px rgba(var(--ink-rgb), 0.08);
    }
    .selection-panel[hidden] { display: none; }
    .selection-head {
      display: flex;
      align-items: flex-start;
      gap: 8px;
      margin-bottom: 9px;
    }
    .selection-head-copy { min-width: 0; flex: 1; }
    .selection-head strong {
      display: block;
      overflow: hidden;
      font-size:var(--fs-xs);
      line-height: 1.35;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    .selection-head span { display: block; margin-top: 2px; color: var(--muted); font-size:var(--fs-xs); }
    .selection-actions { display: flex; gap: 3px; }
    .selection-actions .icon-btn { width: 27px; height: 27px; background: white; border-color: var(--line); }
    .selection-actions .icon-btn .icon { width: 14px; height: 14px; }
    .field-grid {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: 7px;
    }
    /* 区域面板里「名称」在上、宽深在后，两截之间要留一道缝。
       原来这 7px 以行内 style 写在 HTML 上；用相邻选择器表达就不必再挂类名 ——
       它是「一栏字段后面紧跟一排字段」这件事本身的间距，不是某个类的属性。 */
    .field + .field-grid { margin-top: 7px; }
    .field { display: grid; gap: 4px; }
    .field.full { grid-column: 1 / -1; }
    .field label { color: var(--muted); font-size:var(--fs-xs); }
    .field input, .field select {
      width: 100%;
      height: 30px;
      padding: 0 7px;
      color: var(--ink);
      font-size:var(--fs-xs);
      background: white;
      border: 1px solid var(--line);
      border-radius:var(--r-1);
    }
    .rotate-row {
      display: flex;
      gap: 6px;
      margin-top: 8px;
    }
    .rotate-row .soft-btn { height: 31px; flex: 1; justify-content: center; font-size:var(--fs-xs); }
    .stat-line {
      margin-top: 9px;
      color: var(--muted);
      font-size:var(--fs-xs);
      line-height: 1.5;
    }
    .menu-wrap { position: relative; }
    .project-menu {
      position: absolute;
      top: calc(100% + 8px);
      right: 0;
      z-index: var(--z-header);
      width: 176px;
      padding: 5px;
      background: white;
      border: 1px solid var(--line);
      border-radius:var(--r-1);
      box-shadow: 0 12px 30px rgba(var(--ink-rgb), 0.14);
    }
    .project-menu[hidden] { display: none; }
    .menu-item {
      width: 100%;
      height: 34px;
      display: flex;
      align-items: center;
      gap: 8px;
      padding: 0 9px;
      color: var(--ink-2);
      font-size:var(--fs-sm);
      text-align: left;
      border: 0;
      border-radius:var(--r-1);
      background: transparent;
      cursor: pointer;
    }
    .menu-item:hover { background: var(--paper2); }
    .menu-item .icon { width: 15px; height: 15px; }
    .menu-item.danger { color: var(--rose); }
    .toast {
      position: fixed;
      left: 50%;
      bottom: 54px;
      z-index: var(--z-toast);
      max-width: min(420px, calc(100vw - 40px));
      padding: 8px 16px;
      color: white;
      font-size:var(--fs-sm);
      line-height: 1.45;
      text-align: center;
      border-radius:var(--r-1);
      background: rgba(var(--ink-rgb), 0.94);
      box-shadow: 0 8px 26px rgba(var(--ink-rgb), 0.2);
      opacity: 0;
      transform: translate(-50%, 8px);
      pointer-events: none;
      transition: opacity 160ms var(--ease), transform 160ms var(--ease);
    }
    .text-btn { font-size:var(--fs-sm); }
    .toast.show { opacity: 1; transform: translate(-50%, 0); }
    .drawer-scrim { display: none; }

    /* Premium test-fit workspace */
    .brand-title { font-size:var(--fs-md); }
    .brand-copy span { letter-spacing: 0.04em; }
    .project-name { font-weight: 600; }
    .scheme-btn {
      height: 34px;   /* 同 .category-chip：31 差 3px 到触控底线 */

      display: inline-flex;
      align-items: center;
      gap: 6px;
      padding: 0 9px;
      color: var(--brand-dark);
      font-size:var(--fs-xs);
      font-weight: 700;
      white-space: nowrap;
      background: var(--brand-soft);
      border: 1px solid rgba(var(--brand-rgb), 0.18);
      border-radius:var(--r-1);
      cursor: pointer;
    }
    .scheme-btn .icon { width: 13px; height: 13px; }
    .scheme-btn:hover { background: var(--brand-wash); }
    .scheme-popover {
      position: absolute;
      top: calc(100% + 8px);
      left: 0;
      z-index: var(--z-header);
      width: 240px;
      padding: 7px;
      background: white;
      border: 1px solid var(--line);
      border-radius:var(--r-2);
      box-shadow: 0 14px 34px rgba(var(--ink-rgb), 0.15);
    }
    .scheme-popover[hidden] { display: none; }
    .scheme-pop-head {
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 5px 6px 8px;
      color: var(--muted);
      font-size:var(--fs-xs);
    }
    .scheme-pop-head strong { color: var(--ink); font-size:var(--fs-xs); }
    .scheme-item {
      width: 100%;
      display: flex;
      align-items: center;
      gap: 8px;
      padding: 8px;
      text-align: left;
      border: 0;
      border-radius:var(--r-1);
      background: transparent;
      cursor: pointer;
    }
    .scheme-item:hover { background: var(--paper2); }
    .scheme-item.active { background: var(--brand-soft); }
    .scheme-letter {
      width: 26px;
      height: 26px;
      display: grid;
      place-items: center;
      flex: 0 0 auto;
      color: var(--brand-dark);
      font-size:var(--fs-xs);
      font-weight: 800;
      background: white;
      border: 1px solid var(--line);
      border-radius:var(--r-1);
    }
    .scheme-item-copy { min-width: 0; flex: 1; }
    .scheme-item-copy strong {
      display: block;
      overflow: hidden;
      font-size:var(--fs-xs);
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    .scheme-item-copy span { display: block; margin-top: 2px; color: var(--muted); font-size:var(--fs-xs); }
    .scheme-add {
      width: 100%;
      height: 32px;
      display: flex;
      align-items: center;
      gap: 7px;
      margin-top: 4px;
      padding: 0 8px;
      color: var(--brand-dark);
      font-size:var(--fs-xs);
      font-weight: 700;
      border: 1px dashed rgba(var(--brand-rgb), 0.32);
      border-radius:var(--r-1);
      background: transparent;
      cursor: pointer;
    }
    .scheme-add:hover { background: var(--brand-soft); }
    .canvas-viewbar {
      position: absolute;
      top: 14px;
      right: 14px;
      z-index: var(--z-float);
      display: flex;
      align-items: center;
      gap: 3px;
      padding: 3px;
      background: var(--white);
      border: 1px solid var(--line-strong);
      border-radius:var(--r-1);
      box-shadow: var(--shadow-sm);
    }
    .view-btn {
      height: 32px;
      display: inline-flex;
      align-items: center;
      gap: 5px;
      padding: 0 9px;
      color: var(--muted);
      font-size:var(--fs-xs);
      font-weight: 600;
      border: 0;
      border-radius:var(--r-1);
      background: transparent;
      cursor: pointer;
    }
    .view-btn .icon { width: 13px; height: 13px; }
    .view-btn.active {
      color: var(--ink);
      background: var(--paper3);
    }
    .axon-view {
      position: absolute;
      inset: 0;
      z-index: var(--z-pop);
      display: grid;
      grid-template-rows: 46px minmax(0, 1fr);
      background: var(--paper3);
    }
    .axon-view[hidden] { display: none; }
    .axon-head {
      display: flex;
      align-items: center;
      gap: 8px;
      padding: 0 16px;
      color: var(--ink-2);
      font-size:var(--fs-xs);
      background: var(--white);
      border-bottom: 1px solid var(--line);
    }
    .axon-head strong { color: var(--ink); font-size:var(--fs-sm); }
    .axon-badge {
      display: inline-flex;
      align-items: center;
      gap: 5px;
      margin-left: 2px;
      padding: 4px 7px;
      color: var(--brand-dark);
      font-size:var(--fs-xs);
      font-weight: 700;
      background: var(--brand-soft);
      border-radius:var(--r-1);
    }
    .axon-head-spacer { flex: 1; }
    .axon-close {
      width: 31px;
      height: 31px;
      display: grid;
      place-items: center;
      color: var(--ink-2);
      border: 1px solid var(--line);
      border-radius:var(--r-1);
      background: white;
      cursor: pointer;
    }
    .axon-canvas-wrap {
      min-height: 0;
      display: grid;
      place-items: center;
      padding: 16px;
      overflow: hidden;
    }
    #axonStage {
      width: 100%;
      height: 100%;
      display: block;
      filter: drop-shadow(0 18px 30px rgba(var(--ink-rgb), 0.14));
    }
    .library-tabs { grid-template-columns: repeat(4, 1fr); }
    .library-tab { padding: 0 3px; font-size:var(--fs-xs); }
    .furniture-thumb {
      background:
        linear-gradient(180deg, rgba(var(--white-rgb), .4), rgba(242, 242, 240, 0.9)),
        repeating-linear-gradient(90deg, rgba(var(--ink-rgb), 0.04) 0 1px, transparent 1px 18px);
    }
    .premium-panel {
      margin-bottom: 16px;
      padding-bottom: 16px;
      border-bottom: 1px solid var(--line);
    }
    .premium-panel:last-child { border-bottom: 0; }
    .brief-form { display: grid; gap: 8px; }
    .brief-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 7px; }
    .brief-field { display: grid; gap: 4px; min-width: 0; }
    .brief-field.full { grid-column: 1 / -1; }
    .brief-field label { color: var(--muted); font-size:var(--fs-xs); }
    .brief-field input, .brief-field select {
      width: 100%;
      height: 31px;
      min-width: 0;
      padding: 0 8px;
      color: var(--ink);
      font-size:var(--fs-sm);
      background: white;
      border: 1px solid var(--line);
      border-radius:var(--r-1);
    }
    .primary-wide {
      width: 100%;
      height: 38px;
      justify-content: center;
      margin-top: 2px;
    }
    .style-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }
    .style-card {
      min-width: 0;
      padding: 6px;
      text-align: left;
      background: white;
      border: 1px solid var(--line);
      border-radius:var(--r-1);
      cursor: pointer;
    }
    .style-card.active { border-color: var(--brand); box-shadow: inset 0 0 0 1px var(--brand); }
    .style-swatch {
      height: 35px;
      display: flex;
      overflow: hidden;
      margin-bottom: 5px;
      border-radius:var(--r-1);
    }
    .style-swatch i { flex: 1; }
    .style-card strong {
      display: block;
      overflow: hidden;
      font-size:var(--fs-xs);
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    .diagnostic-list { display: grid; gap: 6px; }
    .diagnostic {
      display: flex;
      align-items: flex-start;
      gap: 7px;
      padding: 8px;
      color: var(--ink-2);
      font-size:var(--fs-xs);
      line-height: 1.55;
      background: var(--paper2);
      border-radius:var(--r-1);
    }
    .diagnostic .icon { width: 14px; height: 14px; margin-top: 1px; color: var(--brand); }
    .diagnostic.warn { color: var(--ink2); background: var(--amber-soft); }
    .diagnostic.warn .icon { color: var(--amber); }
    /* 表格下面那句免责说明。只在这一处出现（列表里的诊断由 JS 动态生成，
       靠 .diagnostic-list 的 gap 排布，不该带外边距），所以用相邻选择器钉住位置。 */
    .schedule-table + .diagnostic { margin-top: 12px; }
    .schedule-summary {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: 7px;
      margin-bottom: 12px;
    }
    .summary-tile {
      min-height: 62px;
      padding: 9px;
      background: white;
      border: 1px solid var(--line);
      border-radius:var(--r-1);
    }
    .summary-tile span { display: block; color: var(--muted); font-size:var(--fs-xs); }
    .summary-tile strong { display: block; margin-top: 5px; font-size:var(--fs-lg); line-height: 1; }
    .summary-tile em { display: block; margin-top: 4px; color: var(--muted); font-size:var(--fs-xs); font-style: normal; }
    .schedule-table { width: 100%; border-collapse: collapse; font-size:var(--fs-xs); }
    .schedule-table th {
      padding: 6px 3px;
      color: var(--muted);
      font-weight: 700;
      text-align: left;
      border-bottom: 1px solid var(--line);
    }
    .schedule-table td { padding: 7px 3px; border-bottom: 1px solid var(--paper3); }
    .schedule-table td:last-child, .schedule-table th:last-child { text-align: right; }
    
    
    
    
    
    
    .proposal-overlay {
      position: fixed;
      inset: 0;
      z-index: var(--z-overlay);
      display: grid;
      grid-template-rows: 58px minmax(0, 1fr);
      background: var(--paper4);
    }
    .proposal-overlay[hidden] { display: none; }
    .proposal-top {
      display: flex;
      align-items: center;
      gap: 8px;
      padding: 0 16px;
      background: var(--ink);
      color: white;
    }
    .proposal-top strong { font-size:var(--fs-bs); }
    .proposal-top span { color: rgba(var(--white-rgb), .78); font-size:var(--fs-xs); }
    
    .proposal-top .soft-btn { color: white; background: rgba(var(--white-rgb), .08); border-color: rgba(var(--white-rgb), .18); }
    .proposal-top .primary-btn { background: var(--brand); border-color: var(--brand); color: var(--white); }
    .proposal-body {
      min-height: 0;
      display: grid;
      place-items: center;
      padding: 24px;
      overflow: auto;
    }
    #reportSvg {
      width: min(1400px, 100%);
      height: auto;
      background: var(--paper);
      box-shadow: 0 22px 56px rgba(var(--ink-rgb), 0.18);
    }
    .report-toolbar {
      display: flex;
      align-items: center;
      gap: 8px;
      margin-left: auto;
    }
    
    
    

    /* SVG plan styles are repeated inside the SVG so PNG export is fully self-contained. */
    .room-label {
      font-family: "PingFang SC","Microsoft YaHei","Noto Sans CJK SC",sans-serif;
      font-size: 22px;
      font-weight: 700;
      fill: var(--ink);
      paint-order: stroke;
      stroke: rgba(var(--white-rgb), 0.91);
      stroke-width: 5px;
      stroke-linejoin: round;
      pointer-events: none;
    }
    .room-size {
      font-family: "PingFang SC","Microsoft YaHei","Noto Sans CJK SC",sans-serif;
      font-size:var(--fs-md);
      font-weight: 600;
      fill: var(--ink3);
      paint-order: stroke;
      stroke: rgba(var(--white-rgb), 0.9);
      stroke-width: 4px;
      stroke-linejoin: round;
      pointer-events: none;
    }
    .room-outline { fill: none; stroke: rgba(var(--ink-rgb), 0.16); stroke-width: 1.2; pointer-events: none; }
    .room.selected .room-outline { stroke: var(--brand); stroke-width: 2.4; }
    .room { cursor: pointer; }
    .wall-hit { stroke: transparent; stroke-width: 30; fill: none; cursor: pointer; pointer-events: stroke; }
    .wall-line { fill: none; stroke: var(--line-plan); stroke-linecap: square; pointer-events: none; }
    .plan-item { cursor: move; }
    .plan-fixture { cursor: move; }
    .plan-item .item-hit { fill: transparent; pointer-events: all; }
    .selection-border { fill: none; stroke: var(--brand); stroke-width: 2; stroke-dasharray: 8 5; vector-effect: non-scaling-stroke; }
    .selection-handle { fill: white; stroke: var(--brand); stroke-width: 1.5; vector-effect: non-scaling-stroke; }
    .selection-resize { cursor: nwse-resize; pointer-events: all; }
    .selection-action { cursor: pointer; pointer-events: all; }
    .selection-action-bg { fill: var(--brand); stroke: white; stroke-width: 1.5; vector-effect: non-scaling-stroke; }
    .selection-action-icon { fill: none; stroke: white; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; pointer-events: none; }
    .selection-angle-pill { fill: var(--ink); opacity: .93; }
    .selection-angle-text { fill: white; font-size:var(--fs-xs); font-weight: 700; font-family: "PingFang SC","Microsoft YaHei","Noto Sans CJK SC",sans-serif; pointer-events: none; }
    .wall-selection { fill: none; stroke: var(--brand); stroke-width: 3; stroke-dasharray: 9 5; stroke-linecap: square; pointer-events: none; vector-effect: non-scaling-stroke; }
    .preview-room { fill: var(--brand-soft); stroke: var(--brand); stroke-width: 2; stroke-dasharray: 7 5; vector-effect: non-scaling-stroke; }
    .preview-wall { stroke: var(--line-plan); stroke-width: 12; stroke-linecap: square; opacity: 0.78; }
    .preview-length {
      font-family: "PingFang SC","Microsoft YaHei","Noto Sans CJK SC",sans-serif;
      font-size: 16px;
      font-weight: 700;
      fill: var(--ink);
      paint-order: stroke;
      stroke: white;
      stroke-width: 5px;
    }

    /* Readability pass: keep dense tools scannable without sub-12px UI text. */
    .brand-copy span,
    .save-state,
    .scheme-btn,
    .tool-btn span,
    .rail-help,
    .context-copy strong,
    #toolHint,
    .view-btn,
    .zoom-value,
    .canvas-legend,
    .statusbar,
    .library-count,
    .library-tab,
    .category-chip,
    .furniture-copy strong,
    .furniture-copy span,
    .section-label,
    .floor-note,
    .target-pill,
    .setting-row,
    .field label,
    .rotate-row .soft-btn,
    .brief-field label,
    .style-card strong,
    .diagnostic,
    .menu-item,
    .toast {
      font-size:var(--fs-sm);
    }
    .selection-head strong { font-size:var(--fs-sm); }
    .selection-head span, .stat-line { font-size:var(--fs-xs); }
    .field input, .field select, .brief-field input, .brief-field select { font-size:var(--fs-sm); }

    @media (max-width: 1380px) {
      .topbar { gap: 8px; padding: 0 12px; }
      .brand { min-width: 170px; }
      .project-name { width: min(25vw, 260px); min-width: 120px; }
      .save-state { display: none; }
      #saveBtn .action-label, #proposalBtn .action-label { display: none; }
      #saveBtn, #proposalBtn { width: 34px; padding: 0; }
    }

    @media (max-width: 1220px) {
      :root { --library-w: 312px; --rail-w: 76px; }
      .brand { min-width: 170px; }
      .brand-copy span { display: none; }
      .save-state { display: none; }
      .furniture-grid { grid-template-columns: 1fr; }
      .furniture-card { grid-template-columns: 78px 1fr; grid-template-rows: auto; }
      .furniture-thumb { min-height: 58px; }
    }

    @media (max-width: 900px) {
      :root { --topbar-h: 58px; --status-h: 32px; }
      .app { min-height: 520px; }
      .topbar { gap: 8px; padding: 0 8px; }
      .brand { min-width: 0; gap: 8px; }
      .brand-mark { width: 31px; height: 31px; }
      .brand-title { font-size:var(--fs-sm); }
      .project-label { display: none; }
      .project-name { width: min(42vw, 220px); min-width: 80px; font-size:var(--fs-sm); }
      .top-actions .action-label, .top-actions .soft-btn .action-label { display: none; }
      .top-actions { gap: 2px; }
      .top-actions .soft-btn, .top-actions .primary-btn { width: 34px; padding: 0; }
      .action-group { padding-right: 3px; margin-right: 0; }
      .workspace { grid-template-columns: 1fr; }
      .toolrail {
        position: absolute;
        left: 10px;
        right: 10px;
        bottom: 44px;
        z-index: var(--z-chrome);
        width: auto;
        max-width: none;
        height: 54px;
        flex-direction: row;
        align-items: center;
        gap: 2px;
        padding: 4px;
        overflow-x: auto;
        border: 1px solid var(--line-strong);
        border-radius:var(--r-2);
        box-shadow: var(--shadow);
        transform: none;
      }
      .toolrail .tool-btn { width: 46px; min-width: 46px; min-height: 44px; height: 44px; gap: 2px; }
      .toolrail .tool-btn .icon { width: 17px; height: 17px; }
      .toolrail .tool-btn span { font-size:var(--fs-sm); }
      .rail-separator, .rail-spacer, .rail-help { display: none; }
      .library {
        position: fixed;
        top: var(--topbar-h);
        right: 0;
        bottom: 0;
        z-index: var(--z-drawer);
        width: min(92vw, 360px);
        border-left: 1px solid var(--line-strong);
        box-shadow: -14px 0 34px rgba(var(--ink-rgb), 0.13);
        transform: translateX(104%);
        /* 关着的抽屉必须 visibility:hidden —— 只靠 transform 推出去的话，
           元素仍占据视口右侧外的矩形，「溢出元素」闸门会判它跑出视口。
           visibility 参与过渡：开时立即可见，关时等动画结束才隐藏。 */
        visibility: hidden;
        transition: transform 180ms var(--ease), visibility 180ms var(--ease);
      }
      .library.open { transform: translateX(0); visibility: visible; }
      .library-close { display: inline-flex; margin-left: 2px; }
      .library-count { margin-left: 0; }
      .drawer-scrim {
        position: fixed;
        inset: var(--topbar-h) 0 0;
        z-index: var(--z-scrim);
        display: block;
        background: rgba(var(--ink-rgb), 0.24);
        opacity: 0;
        pointer-events: none;
        transition: opacity 180ms var(--ease);
      }
      .drawer-scrim.open { opacity: 1; pointer-events: auto; }
      .stage-frame { inset: 12px; }
      .canvas-context { top: 20px; left: 20px; max-width: calc(100% - 176px); }
      .canvas-viewbar { top: 20px; right: 20px; }
      .canvas-viewbar .view-btn { padding: 0 7px; }
      .empty-state { width: min(380px, calc(100% - 38px)); }
      .empty-plan { width: min(176px, 54vw); margin-bottom: 8px; }
      .empty-title { font-size:var(--fs-num); }
      .zoom-box { bottom: 13px; left: 50%; transform: translateX(-50%); }
      .statusbar { padding: 0 9px; gap: 8px; }
      .status-spacer { display: none; }
      .statusbar .mobile-status { margin-left: auto; }
      .toast { bottom: 94px; }
      .material-grid, .furniture-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
      .furniture-card { grid-template-columns: none; grid-template-rows: 62px auto; }
      .proposal-body { padding: 8px; place-items: start center; }
      .proposal-top { padding: 0 8px; gap: 6px; }
      .proposal-top span { display: none; }
      .proposal-top .soft-btn, .proposal-top .primary-btn { padding: 0 9px; }
    }

    @media (max-width: 560px) {
      /* ≤560px 顶栏放不下品牌文字（logo + 方案名 + 五个动作已经排满）。
         但 h1 不能 display:none —— 读屏器会整段跳过，手机端就没有页面标题了。
         走 ed.css 里 .sr 的同一套隐形范式：零布局占用，但留在无障碍树里。 */
      .brand-copy { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
      /* 手机上真正没地方放的才在这里收：工具提示、底图名、坐标读数、墙体图例。
         768–900 的平板竖屏画布是全宽的，这些都有地方显示（2026-10-20 从
         ≤900 挪下来 —— 那之前平板用户看不到 hint 也看不到坐标）。 */
      /* .plan-chip 是 .canvas-context 的子元素，所以「.canvas-context .plan-chip」
         （0,2,0）与「.plan-chip.show」（0,2,0）等权，而这条写在文件后面 ——
         已经压得住，!important 是多余的。 */
      .canvas-context .context-copy span, .canvas-context .plan-chip { display: none; }
      .canvas-legend { display: none; }
      .coord-readout { display: none; }
      .project-name { width: 132px; min-width: 132px; }
      .project-wrap > .menu-wrap { display: none; }
      #saveBtn, #proposalBtn { display: none; }
      /* 31 改 34：手机上这排按钮 31 宽，手指按撤销常点到旁边。
         高度已经是 38，宽度也过 32 的触控下限就行，不必再宽。 */
      .top-actions .icon-btn { width: 34px; }
      .top-actions .soft-btn, .top-actions .primary-btn { width: 31px; }
      .action-group { border-right: 0; }
      .empty-state p { display: none; }
      .empty-actions { margin-top: 12px; }
      .zoom-value { min-width: 44px; }
      .statusbar { font-size:var(--fs-sm); }
      .statusbar .mobile-status { display: none; }
      .scheme-btn { padding: 0 7px; }
      .scheme-btn .icon { display: none; }
      .canvas-context { max-width: calc(100% - 154px); }
      .canvas-viewbar .view-btn { padding: 0 6px; font-size:var(--fs-sm); }
      .canvas-viewbar .view-btn .icon { width: 11px; height: 11px; }
    }

    @media (prefers-reduced-motion: reduce) {
      *, *::before, *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        scroll-behavior: auto !important;
        transition-duration: 0.001ms !important;
      }
    }