@pioneer_zmc/dsh-workbench 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +98 -0
  3. package/README.zh.md +100 -0
  4. package/client.js +122 -0
  5. package/cordis.patch.yml +8 -0
  6. package/dist/check-building.js +1669 -0
  7. package/dist/check-room.js +980 -0
  8. package/dist/index.js +2873 -0
  9. package/package.json +60 -0
  10. package/skills/specdev-building/SKILL.md +85 -0
  11. package/skills/specdev-building/assets/layouts/court.json +53 -0
  12. package/skills/specdev-building/assets/layouts/row.json +48 -0
  13. package/skills/specdev-building/assets/layouts/single.json +27 -0
  14. package/skills/specdev-building/assets/layouts/tower-9.json +71 -0
  15. package/skills/specdev-building/assets/layouts/tower.json +59 -0
  16. package/skills/specdev-building/references/blueprint-contract.md +126 -0
  17. package/skills/specdev-building/references/diagnostics.md +101 -0
  18. package/skills/specdev-building/references/layouts.md +112 -0
  19. package/skills/specdev-business/SKILL.md +91 -0
  20. package/skills/specdev-business/assets/plan-template.md +66 -0
  21. package/skills/specdev-business/assets/spec-template.md +111 -0
  22. package/skills/specdev-business/assets/tasks-template.md +36 -0
  23. package/skills/specdev-business/references/change.md +117 -0
  24. package/skills/specdev-business/references/evidence-review.md +125 -0
  25. package/skills/specdev-business/references/implementation.md +67 -0
  26. package/skills/specdev-business/references/project-contract.md +211 -0
  27. package/skills/specdev-business/references/source-map.md +110 -0
  28. package/skills/specdev-business/references/specification.md +93 -0
  29. package/skills/specdev-business/references/workflow.md +126 -0
  30. package/skills/specdev-room/SKILL.md +77 -0
  31. package/skills/specdev-room/assets/intro-room.json +14 -0
  32. package/skills/specdev-room/references/diagnostics.md +21 -0
  33. package/skills/specdev-room/references/room-contract.md +59 -0
  34. package/vendor/archify-renderer/VERSION.md +52 -0
  35. package/vendor/archify-renderer/archify/LICENSE +22 -0
  36. package/vendor/archify-renderer/archify/THIRD_PARTY_NOTICES.md +56 -0
  37. package/vendor/archify-renderer/archify/assets/template.html +14787 -0
  38. package/vendor/archify-renderer/archify/bin/archify.mjs +1990 -0
  39. package/vendor/archify-renderer/archify/renderers/shared/brand-marks.mjs +563 -0
  40. package/vendor/archify-renderer/archify/renderers/shared/cli.mjs +218 -0
  41. package/vendor/archify-renderer/archify/renderers/shared/desktop-readability.mjs +26 -0
  42. package/vendor/archify-renderer/archify/renderers/shared/diagnostics.mjs +127 -0
  43. package/vendor/archify-renderer/archify/renderers/shared/engineering-profiles.mjs +157 -0
  44. package/vendor/archify-renderer/archify/renderers/shared/generated-brand-marks.mjs +2003 -0
  45. package/vendor/archify-renderer/archify/renderers/shared/generated-validators.mjs +13 -0
  46. package/vendor/archify-renderer/archify/renderers/shared/geometry.mjs +1423 -0
  47. package/vendor/archify-renderer/archify/renderers/shared/i18n.mjs +594 -0
  48. package/vendor/archify-renderer/archify/renderers/shared/legend.mjs +217 -0
  49. package/vendor/archify-renderer/archify/renderers/shared/output-path.mjs +321 -0
  50. package/vendor/archify-renderer/archify/renderers/shared/repository-evidence.mjs +235 -0
  51. package/vendor/archify-renderer/archify/renderers/shared/text-fit.mjs +49 -0
  52. package/vendor/archify-renderer/archify/renderers/shared/utils.mjs +232 -0
  53. package/vendor/archify-renderer/archify/renderers/shared/validator.mjs +86 -0
  54. package/vendor/archify-renderer/archify/renderers/workflow/render-workflow.mjs +35 -0
  55. package/vendor/archify-renderer/archify/renderers/workflow/workflow-compiler.mjs +4400 -0
  56. package/vendor/archify-renderer/archify/renderers/workflow/workflow-migration-geometry.mjs +144 -0
  57. package/vendor/archify-renderer/archify/schemas/common.schema.json +115 -0
  58. package/vendor/archify-renderer/archify/schemas/workflow.schema.json +428 -0
  59. package/vendor/archify-renderer/archify/scripts/check-render-output.mjs +835 -0
  60. package/vendor/archify-renderer/shims/process.mjs +18 -0
  61. package/vendor/archify-renderer/stubs/child_process.mjs +2 -0
  62. package/vendor/archify-renderer/stubs/crypto.mjs +3 -0
  63. package/vendor/archify-renderer/stubs/dns-promises.mjs +2 -0
  64. package/vendor/archify-renderer/stubs/fs.mjs +3 -0
  65. package/vendor/archify-renderer/stubs/http.mjs +3 -0
  66. package/vendor/archify-renderer/stubs/https.mjs +3 -0
  67. package/vendor/archify-renderer/stubs/net.mjs +3 -0
  68. package/vendor/archify-renderer/stubs/path.mjs +3 -0
  69. package/vendor/archify-renderer/stubs/url.mjs +3 -0
  70. package/web/assets/building-kit.js +1157 -0
  71. package/web/assets/building-look.js +185 -0
  72. package/web/assets/building-plan.js +495 -0
  73. package/web/assets/building-scene.js +529 -0
  74. package/web/assets/building-walk.js +248 -0
  75. package/web/assets/building.js +859 -0
  76. package/web/assets/business.js +124 -0
  77. package/web/assets/chart-link.js +165 -0
  78. package/web/assets/common.js +302 -0
  79. package/web/assets/details.js +197 -0
  80. package/web/assets/evidence.js +30 -0
  81. package/web/assets/furniture/SOURCES.md +24 -0
  82. package/web/assets/furniture/assets/ceramic-display-stand-01/asset.json +25 -0
  83. package/web/assets/furniture/assets/ceramic-display-stand-01/model.js +116 -0
  84. package/web/assets/furniture/assets/ceramic-display-stand-01/preview.webp +0 -0
  85. package/web/assets/furniture/assets/ceramic-floor-lamp-01/asset.json +61 -0
  86. package/web/assets/furniture/assets/ceramic-floor-lamp-01/model.js +56 -0
  87. package/web/assets/furniture/assets/ceramic-floor-lamp-01/preview.webp +0 -0
  88. package/web/assets/furniture/assets/ceramic-low-cabinet-01/asset.json +81 -0
  89. package/web/assets/furniture/assets/ceramic-low-cabinet-01/model.js +67 -0
  90. package/web/assets/furniture/assets/ceramic-low-cabinet-01/preview.webp +0 -0
  91. package/web/assets/furniture/assets/ceramic-vase-01/asset.json +21 -0
  92. package/web/assets/furniture/assets/ceramic-vase-01/model.js +119 -0
  93. package/web/assets/furniture/assets/ceramic-vase-01/preview.webp +0 -0
  94. package/web/assets/furniture/assets/fairy-bed-01/asset.json +61 -0
  95. package/web/assets/furniture/assets/fairy-bed-01/model.js +63 -0
  96. package/web/assets/furniture/assets/fairy-bed-01/preview.webp +0 -0
  97. package/web/assets/furniture/assets/fairy-book-stack-01/asset.json +21 -0
  98. package/web/assets/furniture/assets/fairy-book-stack-01/model.js +71 -0
  99. package/web/assets/furniture/assets/fairy-book-stack-01/preview.webp +0 -0
  100. package/web/assets/furniture/assets/fairy-bookshelf-01/asset.json +32 -0
  101. package/web/assets/furniture/assets/fairy-bookshelf-01/model.js +168 -0
  102. package/web/assets/furniture/assets/fairy-bookshelf-01/preview.webp +0 -0
  103. package/web/assets/furniture/assets/fairy-desk-01/asset.json +25 -0
  104. package/web/assets/furniture/assets/fairy-desk-01/model.js +132 -0
  105. package/web/assets/furniture/assets/fairy-desk-01/preview.webp +0 -0
  106. package/web/assets/furniture/assets/fairy-notice-board-01/asset.json +23 -0
  107. package/web/assets/furniture/assets/fairy-notice-board-01/model.js +125 -0
  108. package/web/assets/furniture/assets/fairy-notice-board-01/preview.webp +0 -0
  109. package/web/assets/furniture/assets/fairy-potted-plant-01/asset.json +21 -0
  110. package/web/assets/furniture/assets/fairy-potted-plant-01/model.js +128 -0
  111. package/web/assets/furniture/assets/fairy-potted-plant-01/preview.webp +0 -0
  112. package/web/assets/furniture/assets/fairy-reading-chair-01/asset.json +61 -0
  113. package/web/assets/furniture/assets/fairy-reading-chair-01/model.js +66 -0
  114. package/web/assets/furniture/assets/fairy-reading-chair-01/preview.webp +0 -0
  115. package/web/assets/furniture/assets/fairy-table-lamp-01/asset.json +21 -0
  116. package/web/assets/furniture/assets/fairy-table-lamp-01/model.js +182 -0
  117. package/web/assets/furniture/assets/fairy-table-lamp-01/preview.webp +0 -0
  118. package/web/assets/furniture/catalog.js +137 -0
  119. package/web/assets/furniture/index.json +110 -0
  120. package/web/assets/furniture/registry.js +72 -0
  121. package/web/assets/furniture-page.css +68 -0
  122. package/web/assets/furniture-page.js +302 -0
  123. package/web/assets/home.js +65 -0
  124. package/web/assets/node-detail.js +148 -0
  125. package/web/assets/panel-link.js +47 -0
  126. package/web/assets/read.js +746 -0
  127. package/web/assets/room-scene.js +386 -0
  128. package/web/assets/room.css +287 -0
  129. package/web/assets/room.js +437 -0
  130. package/web/assets/rooms/bindings.js +449 -0
  131. package/web/assets/rooms/ceramic-reflection.js +193 -0
  132. package/web/assets/rooms/ceramic-room.js +302 -0
  133. package/web/assets/rooms/door.js +35 -0
  134. package/web/assets/rooms/fairy-room.js +492 -0
  135. package/web/assets/rooms/furniture-assembly.js +113 -0
  136. package/web/assets/rooms/navigation.js +262 -0
  137. package/web/assets/rooms/placeholder-catalog.json +71 -0
  138. package/web/assets/rooms/placeholder-furniture.js +76 -0
  139. package/web/assets/rooms/placement.js +588 -0
  140. package/web/assets/rooms/reader.js +441 -0
  141. package/web/assets/rooms/reading-gate.js +157 -0
  142. package/web/assets/rooms/room-lighting.js +50 -0
  143. package/web/assets/rooms/templates.json +50 -0
  144. package/web/assets/rooms/walk-frame.js +64 -0
  145. package/web/assets/rooms/walk-session.js +138 -0
  146. package/web/assets/save-result.js +89 -0
  147. package/web/assets/screenshots/business.png +0 -0
  148. package/web/assets/screenshots/node-detail.png +0 -0
  149. package/web/assets/screenshots/project-home.png +0 -0
  150. package/web/assets/screenshots/workflow.png +0 -0
  151. package/web/assets/showcase.js +232 -0
  152. package/web/assets/style.css +836 -0
  153. package/web/assets/template.js +7 -0
  154. package/web/assets/theme.js +29 -0
  155. package/web/assets/three/OrbitControls.js +1972 -0
  156. package/web/assets/three/VERSION.md +12 -0
  157. package/web/assets/three/three.core.js +60586 -0
  158. package/web/assets/three/three.module.js +19719 -0
  159. package/web/assets/workspaces.css +21 -0
  160. package/web/assets/workspaces.js +81 -0
  161. package/web/building.html +131 -0
  162. package/web/business.html +43 -0
  163. package/web/furniture.html +47 -0
  164. package/web/index.html +57 -0
  165. package/web/read.html +107 -0
  166. package/web/room.html +146 -0
  167. package/web/showcase.html +50 -0
  168. package/web/workspaces.html +32 -0
@@ -0,0 +1,836 @@
1
+ /* 两套主题共享语义色;业务状态色与品牌强调色分开。 */
2
+ :root {
3
+ color-scheme: dark;
4
+ --page: #111419; --surface: #181d25; --surface-soft: #141a22;
5
+ --hover: #202834; --border: #2b3442; --border-strong: #536781;
6
+ --text: #edf2fa; --secondary: #c2ccda; --muted: #9caabd;
7
+ --accent: #8ab9ff; --accent-bg: #1b2c45; --accent-border: #42638e; --accent-hover: #273e5c;
8
+ --primary: #619eff; --primary-ink: #0b172a;
9
+ --success: #80d6ac; --success-bg: #163428; --success-border: #34654b; --success-hover: #214e38;
10
+ --warning: #efc777; --warning-bg: #342b19; --warning-border: #745e34;
11
+ --danger: #f2a1aa; --danger-bg: #362027; --danger-border: #75404b;
12
+ --purple: #c5b5f0; --purple-bg: #2b253b;
13
+ --code-bg: #10151d; --canvas: #020617;
14
+ --glow: rgba(75, 133, 229, .12); --grid: rgba(116, 147, 189, .13);
15
+ --shadow: 0 12px 32px rgba(0, 0, 0, .12);
16
+ }
17
+ :root[data-theme="light"] {
18
+ color-scheme: light;
19
+ --page: #f6f8fb; --surface: #ffffff; --surface-soft: #f0f4f9;
20
+ --hover: #eaf0f8; --border: #dce3ed; --border-strong: #99abc3;
21
+ --text: #1b2a41; --secondary: #41516a; --muted: #5c6d84;
22
+ --accent: #245dc1; --accent-bg: #eaf1ff; --accent-border: #a8c3ee; --accent-hover: #dce9ff;
23
+ --primary: #2865d5; --primary-ink: #ffffff;
24
+ --success: #206e4b; --success-bg: #e6f4ec; --success-border: #9bc8ae; --success-hover: #cee8d9;
25
+ --warning: #825607; --warning-bg: #fff4dc; --warning-border: #dac28c;
26
+ --danger: #ac354a; --danger-bg: #fff0f2; --danger-border: #e0aeb7;
27
+ --purple: #6d46a5; --purple-bg: #f0eafa;
28
+ --code-bg: #edf2f9; --canvas: #f8fafc;
29
+ --glow: rgba(72, 133, 239, .10); --grid: rgba(70, 112, 169, .13);
30
+ --shadow: 0 12px 32px rgba(29, 53, 88, .06);
31
+ }
32
+ /* 共用阅读组件:保留原有交互结构,使用统一主题色。 */
33
+ * { box-sizing: border-box; }
34
+ body {
35
+ margin: 0; padding: 0;
36
+ font: 14px/1.65 "Segoe UI", "Microsoft YaHei", system-ui, sans-serif;
37
+ color: var(--text); background: var(--page);
38
+ }
39
+ a { color: var(--accent); text-decoration: none; }
40
+ a:hover { text-decoration: underline; }
41
+ .top { display: flex; justify-content: space-between; align-items: flex-start; gap: 24px; margin-bottom: 20px; }
42
+ .top h1 { margin: 0 0 4px; font-size: 22px; }
43
+ .sub { margin: 0; color: var(--muted); max-width: 72ch; }
44
+ .crumbs { margin: 0 0 6px; font-size: 13px; color: var(--muted); }
45
+ .status { margin: 2px 0 0; font-size: 13px; color: var(--muted); white-space: nowrap; }
46
+ .status[data-kind="ok"] { color: var(--success); }
47
+ .status[data-kind="bad"] { color: var(--danger); }
48
+ .status[data-kind="warn"] { color: var(--warning); }
49
+ .error {
50
+ margin: 0 0 16px; padding: 10px 14px; border-radius: 8px;
51
+ background: var(--danger-bg); border: 1px solid var(--danger-border); color: var(--danger);
52
+ overflow-wrap: anywhere; white-space: pre-wrap;
53
+ }
54
+ .guide {
55
+ margin: 0 0 20px; padding: 14px 18px; border-radius: 10px;
56
+ background: var(--surface-soft); border: 1px solid var(--border-strong);
57
+ }
58
+ .guide h2 { margin: 0 0 8px; font-size: 16px; }
59
+ .guide p { margin: 6px 0; color: var(--secondary); }
60
+ .guide pre {
61
+ margin: 8px 0; padding: 12px 14px; border-radius: 8px; overflow-x: auto;
62
+ background: var(--code-bg); border: 1px solid var(--border); color: var(--accent); font-size: 13px;
63
+ }
64
+ .cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 14px; }
65
+ .card {
66
+ display: block; padding: 16px 18px; border-radius: 10px;
67
+ background: var(--surface); border: 1px solid var(--border); color: inherit;
68
+ }
69
+ .card:hover { border-color: var(--border-strong); text-decoration: none; }
70
+ .card h2 { margin: 0 0 6px; font-size: 16px; color: var(--text); }
71
+ .card p { margin: 0; color: var(--muted); }
72
+ .card .meta { margin-top: 10px; font-size: 13px; color: var(--muted); }
73
+ .badge {
74
+ display: inline-block; margin-left: 8px; padding: 1px 8px; border-radius: 999px;
75
+ font-size: 12px; vertical-align: 1px;
76
+ }
77
+ .badge[data-kind="identical"] { background: var(--success-bg); color: var(--success); }
78
+ .badge[data-kind="changed"] { background: var(--warning-bg); color: var(--warning); }
79
+ .badge[data-kind="no-snapshot"] { background: var(--surface-soft); color: var(--muted); }
80
+ .badge[data-kind="compare-failed"] { background: var(--purple-bg); color: var(--purple); }
81
+ .badge[data-kind="invalid"] { background: var(--danger-bg); color: var(--danger); }
82
+ /* 状态汇总小徽标(首页业务卡小行+业务页汇总行):颜色复用四状态语义色;
83
+ 业务页上是按钮,点一下跳到第一张该状态的图卡。 */
84
+ .chip-row { display: flex; flex-wrap: wrap; gap: 8px; }
85
+ .chip-row .badge { margin-left: 0; }
86
+ .chip-row button.badge { border: 0; padding: 3px 10px; font-family: inherit; cursor: pointer; }
87
+ .chip-row button.badge:hover { text-decoration: underline; }
88
+ .panel {
89
+ margin: 0 0 20px; padding: 14px 18px; border-radius: 10px;
90
+ background: var(--surface); border: 1px solid var(--border);
91
+ }
92
+ .panel h2 { margin: 0 0 10px; font-size: 15px; }
93
+ .doc-list { margin: 0; padding-left: 18px; }
94
+ .versions { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 16px; }
95
+ .versions button, .versions .current-item {
96
+ padding: 6px 12px; border-radius: 8px; border: 1px solid var(--border);
97
+ background: var(--surface); color: var(--text); cursor: pointer; font-size: 13px;
98
+ }
99
+ .versions button[aria-current="true"] { border-color: var(--accent); background: var(--accent-bg); }
100
+ .stage-note { color: var(--muted); }
101
+ /* 「已选」状态条(E·选中同步):写在图层外面的一条提示,只报图里当前选中的步骤;
102
+ 不给图加任何东西。未选中时整条隐藏(不给"没选"占位)。 */
103
+ .selection-bar {
104
+ margin: 0 0 12px; padding: 8px 14px; border-radius: 8px;
105
+ background: var(--accent-bg); border: 1px solid var(--accent-border); color: var(--accent);
106
+ }
107
+ .selection-bar[data-kind="selected"] b { color: var(--text); }
108
+ .selection-bar[data-kind="warn"] {
109
+ background: var(--warning-bg); border-color: var(--warning-border); color: var(--warning);
110
+ }
111
+ .detail-open {
112
+ margin-left: 12px; padding: 3px 12px; border-radius: 6px;
113
+ border: 1px solid var(--accent-border); background: var(--accent-bg); color: var(--accent);
114
+ font-size: 13px; cursor: pointer;
115
+ }
116
+ .detail-open:hover { background: var(--accent-hover); }
117
+ /* 节点详情弹层(F):读某个步骤在当前所选版本里的说明;弹出期间挡住图(模态),
118
+ 关闭后图原样——弹层不碰 iframe,缩放与位置都不动。 */
119
+ .detail-dialog {
120
+ width: min(1440px, calc(100vw - 48px)); max-width: none; height: 88dvh; max-height: 960px; margin: auto; padding: 0;
121
+ border: 1px solid var(--border-strong); border-radius: 12px; background: var(--surface); color: var(--text);
122
+ }
123
+ .detail-dialog[open] { display: flex; flex-direction: column; }
124
+ .detail-dialog::backdrop { background: rgba(6, 8, 12, .62); }
125
+ .detail-dialog-head {
126
+ display: flex; justify-content: space-between; align-items: center;
127
+ padding: 10px 14px 10px 22px; border-bottom: 1px solid var(--border);
128
+ color: var(--muted); font-size: 13px;
129
+ }
130
+ .detail-close {
131
+ width: 28px; height: 28px; border-radius: 6px; border: 1px solid var(--border);
132
+ background: var(--surface-soft); color: var(--secondary); font-size: 16px; line-height: 1; cursor: pointer;
133
+ }
134
+ .detail-close:hover { background: var(--hover); }
135
+ .detail-dialog-body { padding: 16px 28px; overflow-y: auto; min-height: 0; overscroll-behavior: contain; }
136
+ .detail-dialog-head, .detail-dialog > .detail-source { flex-shrink: 0; }
137
+ .reader-tools { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin: 12px 0; font-size: 13px; }
138
+ .reader-tools button { padding: 8px 12px; border: 1px solid var(--border); border-radius: 8px; background: var(--surface); color: var(--text); cursor: pointer; }
139
+ .reader-title { margin: 8px 0; font-size: 26px; }
140
+ .reader-columns { display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); gap: 40px; padding: 18px 0 12px; color: var(--muted); font-size: 12px; letter-spacing: .08em; }
141
+ .reader-pair { display: grid; grid-template-columns: minmax(0, 1.15fr) 40px minmax(0, 1fr); align-items: start; padding: 26px 0; border-top: 1px solid var(--border); }
142
+ .reader-code, .reader-prose { min-width: 0; }
143
+ .reader-prose { line-height: 1.85; overflow-wrap: anywhere; padding-left: 6px; }
144
+ .reader-prose h3 { margin: 0 0 16px; font-size: 20px; }
145
+ .reader-prose p { margin: 0 0 14px; }
146
+ .reader-link { border-top: 1px dashed var(--border-strong); margin-top: 32px; }
147
+ .reader-unpaired .reader-link { visibility: hidden; }
148
+ .reader-snippet { margin: 0 0 14px; border: 1px solid var(--border); border-radius: 10px; background: var(--surface-soft); overflow: hidden; }
149
+ .reader-snippet figcaption { padding: 12px 14px 4px; font-size: 13px; font-weight: 600; }
150
+ .reader-snippet .ev-src { padding: 0 14px 8px; overflow-wrap: anywhere; }
151
+ .reader-snippet .ev-code { border: 0; border-top: 1px solid var(--border); border-radius: 0; white-space: pre; max-width: 100%; }
152
+ .reader-snippet .ev-bad { padding: 12px 14px; }
153
+ .detail-example { white-space: pre; overflow-x: auto; padding: 12px; background: var(--surface-soft); }
154
+ @media (max-width: 850px) {
155
+ .detail-dialog { width: calc(100vw - 20px); height: 94dvh; max-height: 94dvh; }
156
+ .detail-dialog-body { padding: 14px 18px; }
157
+ .reader-columns { display: none; }
158
+ .reader-pair { grid-template-columns: minmax(0, 1fr); gap: 16px; }
159
+ .reader-link { width: 0; height: 16px; border-top: 0; border-left: 1px dashed var(--border-strong); margin: -16px 0 0 20px; }
160
+ .reader-tools { align-items: flex-start; flex-direction: column; }
161
+ }
162
+ .detail-dialog-body .detail-block { background: var(--surface-soft); }
163
+ /* 保存版本(G):版本条上的入口 + 保存弹层。弹层外观沿用节点详情弹层那一套,
164
+ 只有表单区不同;关闭三方式与详情层一致。 */
165
+ .versions button.save-open {
166
+ border-color: var(--success-border); background: var(--success-bg); color: var(--success);
167
+ }
168
+ .versions button.save-open:hover { background: var(--success-bg); }
169
+ .save-dialog {
170
+ width: min(560px, calc(100vw - 48px)); max-height: 82vh; margin: auto; padding: 0;
171
+ border: 1px solid var(--border-strong); border-radius: 12px; background: var(--surface); color: var(--text);
172
+ }
173
+ .save-dialog[open] { display: flex; flex-direction: column; }
174
+ .save-dialog::backdrop { background: rgba(6, 8, 12, .62); }
175
+ .save-dialog-body { padding: 16px 22px 18px; overflow-y: auto; }
176
+ .save-check {
177
+ margin: 0 0 14px; padding: 8px 12px; border-radius: 8px;
178
+ background: var(--surface-soft); border: 1px solid var(--border); color: var(--secondary); font-size: 13px;
179
+ }
180
+ .save-check[data-kind="ok"] { background: var(--success-bg); border-color: var(--success-border); color: var(--success); }
181
+ .save-check[data-kind="warn"] { background: var(--warning-bg); border-color: var(--warning-border); color: var(--warning); }
182
+ .save-check[data-kind="bad"] { background: var(--danger-bg); border-color: var(--danger-border); color: var(--danger); }
183
+ .save-problems { margin: 6px 0 0; padding-left: 18px; }
184
+ .save-field { display: block; margin: 0 0 14px; font-size: 13px; color: var(--secondary); }
185
+ .save-label { display: block; margin-bottom: 6px; color: var(--muted); }
186
+ .save-field input[type="text"], .save-field textarea {
187
+ width: 100%; box-sizing: border-box; padding: 8px 10px; border-radius: 8px;
188
+ border: 1px solid var(--border); background: var(--page); color: var(--text); font-size: 13px;
189
+ }
190
+ .save-field textarea { resize: vertical; font-family: inherit; }
191
+ .save-stages { border: 0; padding: 0; margin: 0 0 14px; }
192
+ .save-stages label { margin-right: 16px; }
193
+ .save-error {
194
+ margin: 0 0 12px; padding: 8px 12px; border-radius: 8px;
195
+ background: var(--danger-bg); border: 1px solid var(--danger-border); color: var(--danger); font-size: 13px;
196
+ }
197
+ .save-actions { display: flex; gap: 10px; justify-content: flex-end; }
198
+ .save-submit, .save-cancel {
199
+ padding: 7px 18px; border-radius: 8px; font-size: 13px; cursor: pointer;
200
+ border: 1px solid var(--border); background: var(--surface); color: var(--text);
201
+ }
202
+ .save-submit { border-color: var(--success-border); background: var(--success-bg); color: var(--success); }
203
+ .save-submit:hover:not(:disabled) { background: var(--success-hover); }
204
+ .save-submit:disabled { opacity: .5; cursor: not-allowed; }
205
+ .save-cancel:hover { background: var(--hover); }
206
+ .detail-lead-line { margin: 0 0 12px; color: var(--secondary); max-width: 82ch; }
207
+ .detail-miss { margin: 0 0 8px; color: var(--secondary); max-width: 82ch; }
208
+ .detail-source {
209
+ margin: 0; padding: 10px 22px 14px; border-top: 1px solid var(--border);
210
+ color: var(--muted); font-size: 12px;
211
+ }
212
+ .detail-source:empty { display: none; }
213
+ /* 现场渲染画布:原生装配出的整页装在 iframe(独立小房间)里,样式自带;
214
+ 这里只管小房间在阅读页里的占位与外观,滚动由小房间内部自己处理 */
215
+ .chart-stage {
216
+ padding: 6px;
217
+ background: var(--canvas);
218
+ border: 1px solid var(--border);
219
+ border-radius: 10px;
220
+ }
221
+ .chart-frame {
222
+ display: block;
223
+ width: 100%;
224
+ height: 78vh;
225
+ border: 0;
226
+ border-radius: 8px;
227
+ background: var(--canvas);
228
+ }
229
+ .muted { color: var(--muted); font-size: 13px; }
230
+ /* 渲染失败说明卡(B·说人话):坏的是哪份 / 原因 / 建议 + 可折叠技术原文 */
231
+ .fail-card {
232
+ max-width: 640px;
233
+ margin: 40px auto;
234
+ padding: 18px 22px;
235
+ border-radius: 10px;
236
+ background: var(--surface-soft);
237
+ border: 1px solid var(--border-strong);
238
+ }
239
+ .fail-card h2 { margin: 0 0 8px; font-size: 17px; color: var(--danger); }
240
+ .fail-card p { margin: 6px 0; line-height: 1.7; }
241
+ .fail-which { color: var(--muted); font-size: 13px; }
242
+ .fail-reason { color: var(--text); }
243
+ .fail-hint { color: var(--success); }
244
+ .fail-detail { margin-top: 12px; }
245
+ .fail-detail summary { cursor: pointer; color: var(--muted); font-size: 13px; }
246
+ .fail-detail pre {
247
+ margin: 8px 0 0; padding: 10px 14px; border-radius: 8px;
248
+ background: var(--code-bg); border: 1px solid var(--border); color: var(--accent);
249
+ font-size: 12px; overflow-wrap: anywhere; white-space: pre-wrap;
250
+ }
251
+ /* 说明文档面板(C):一个步骤一块,块内正文按段落与列表排 */
252
+ .details-panel {
253
+ margin: 20px 0 0; padding: 16px 22px; border-radius: 10px;
254
+ background: var(--surface); border: 1px solid var(--border);
255
+ }
256
+ .details-panel h2 { margin: 0 0 6px; font-size: 15px; }
257
+ .details-lead { margin: 0 0 14px; color: var(--secondary); max-width: 82ch; }
258
+ .details-warn {
259
+ margin: 0 0 14px; padding: 10px 14px; border-radius: 8px;
260
+ background: var(--warning-bg); border: 1px solid var(--warning-border); color: var(--warning);
261
+ }
262
+ .detail-block {
263
+ margin: 0 0 14px; padding: 12px 16px; border-radius: 8px;
264
+ background: var(--surface-soft); border: 1px solid var(--border);
265
+ }
266
+ .detail-block h3 { margin: 0 0 6px; font-size: 14px; color: var(--text); }
267
+ .detail-block p { margin: 0 0 6px; color: var(--secondary); max-width: 82ch; }
268
+ .detail-block p:last-child, .detail-block ul:last-child { margin-bottom: 0; }
269
+ .detail-block ul { margin: 0 0 6px; padding-left: 20px; color: var(--secondary); }
270
+ .detail-block li { margin: 2px 0; }
271
+ .detail-block code {
272
+ padding: 1px 5px; border-radius: 4px; background: var(--code-bg); color: var(--accent); font-size: 12px;
273
+ }
274
+ .detail-sub { margin-left: 8px; color: var(--muted); font-size: 12px; font-weight: 400; }
275
+ .detail-note { margin-left: 8px; color: var(--muted); font-size: 12px; font-weight: 400; }
276
+ .detail-id { margin-left: 8px; font-weight: 400; }
277
+
278
+ /* 源码证据面板(D):一条证据一块;有效引用贴带行号代码,坏引用红字说原因 */
279
+ .evidence-panel {
280
+ margin: 20px 0 0; padding: 16px 22px; border-radius: 10px;
281
+ background: var(--surface); border: 1px solid var(--border);
282
+ }
283
+ .evidence-panel h2 { margin: 0 0 6px; font-size: 15px; }
284
+ .ev-summary { margin: 0 0 6px; color: var(--secondary); }
285
+ .ev-warn {
286
+ margin: 0; padding: 10px 14px; border-radius: 8px;
287
+ background: var(--warning-bg); border: 1px solid var(--warning-border); color: var(--warning);
288
+ }
289
+ .ev-block {
290
+ margin: 0 0 14px; padding: 12px 16px; border-radius: 8px;
291
+ background: var(--surface-soft); border: 1px solid var(--border);
292
+ }
293
+ .ev-block:last-child { margin-bottom: 0; }
294
+ .ev-block h3 { margin: 0 0 6px; font-size: 14px; color: var(--text); }
295
+ .ev-src { margin: 0 0 6px; color: var(--muted); font-size: 12px; }
296
+ .ev-code {
297
+ margin: 0; padding: 10px 14px; border-radius: 8px;
298
+ background: var(--code-bg); border: 1px solid var(--border); color: var(--secondary);
299
+ font-size: 12px; line-height: 1.6; overflow-x: auto;
300
+ }
301
+ .ev-bad { margin: 0; color: var(--danger); }
302
+ .ev-block-bad { border-color: var(--danger-border); }
303
+
304
+ /* 页面骨架与首页。装饰只出现在首页介绍区,不进入正文和图画布。 */
305
+ [hidden] { display: none !important; }
306
+ html { scroll-behavior: smooth; scroll-padding-top: 24px; }
307
+ body { min-width: 320px; -webkit-font-smoothing: antialiased; }
308
+ button, input, textarea { font-family: inherit; }
309
+ button, a { -webkit-tap-highlight-color: transparent; }
310
+ a, button { touch-action: manipulation; }
311
+ :focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
312
+ ::selection { background: var(--accent-bg); color: var(--text); }
313
+ .app-bar {
314
+ min-height: 88px; padding: 18px max(32px, calc((100% - 1200px) / 2));
315
+ display: flex; justify-content: space-between; align-items: center; gap: 20px;
316
+ border-bottom: 1px solid var(--border);
317
+ }
318
+ .brand { display: inline-flex; align-items: center; gap: 12px; color: var(--text); font-size: 19px; font-weight: 650; letter-spacing: -.5px; }
319
+ .brand:hover { text-decoration: none; }
320
+ .brand-mark {
321
+ position: relative; display: grid; place-items: center; width: 35px; height: 35px;
322
+ background: var(--accent-bg); border: 1px solid var(--accent-border); border-radius: 10px;
323
+ color: var(--accent); font: 600 23px/1 "Segoe UI", sans-serif;
324
+ }
325
+ .brand-mark span { position: absolute; width: 5px; height: 5px; background: var(--accent); right: -3px; top: 6px; border-radius: 2px; }
326
+ .brand-caption { padding-left: 15px; margin-left: 15px; border-left: 1px solid var(--border); color: var(--muted); font-size: 12px; font-weight: 400; letter-spacing: .5px; }
327
+ .theme-switch { display: flex; padding: 4px; gap: 3px; border: 1px solid var(--border); border-radius: 10px; background: var(--surface-soft); flex-shrink: 0; }
328
+ .theme-switch button { padding: 6px 12px; border: 1px solid transparent; border-radius: 7px; background: transparent; color: var(--muted); font-size: 12px; cursor: pointer; line-height: 1.5; }
329
+ .theme-switch button span { font-size: 15px; margin-right: 3px; }
330
+ .theme-switch button[aria-pressed="true"] { background: var(--surface); color: var(--text); border-color: var(--border); box-shadow: 0 2px 4px rgba(0, 0, 0, .04); }
331
+ .theme-switch button:hover { color: var(--text); }
332
+ .skip-link { position: absolute; top: -70px; left: 20px; padding: 10px 18px; background: var(--surface); border: 1px solid var(--accent); border-radius: 8px; z-index: 10; }
333
+ .skip-link:focus { top: 16px; }
334
+ .home-main { max-width: 1280px; margin: 0 auto; padding: 0 40px; }
335
+ .project-hero { display: grid; grid-template-columns: 1.25fr 1fr; align-items: center; gap: 40px; padding: 66px 0 52px; min-height: 390px; }
336
+ .hero-copy { min-width: 0; position: relative; z-index: 1; }
337
+ .eyebrow { margin: 0 0 17px; display: flex; align-items: center; gap: 10px; color: var(--muted); font-size: 11px; font-weight: 500; letter-spacing: 2px; }
338
+ .eyebrow-line { display: inline-block; width: 20px; height: 2px; background: var(--accent); }
339
+ .project-hero h1 { margin: 0 0 22px; color: var(--text); font-size: clamp(30px, 3.2vw, 46px); line-height: 1.35; letter-spacing: -1.3px; font-weight: 650; text-wrap: balance; overflow-wrap: anywhere; }
340
+ .hero-description { margin: 0; max-width: 55ch; color: var(--muted); font-size: 14px; line-height: 1.9; overflow-wrap: anywhere; }
341
+ .hero-actions { display: flex; flex-wrap: wrap; gap: 20px; align-items: center; margin: 28px 0 22px; }
342
+ .primary-link { display: inline-flex; gap: 30px; align-items: center; padding: 11px 19px; border-radius: 8px; background: var(--primary); color: var(--primary-ink); font-size: 13px; font-weight: 600; transition: filter .15s, transform .15s; }
343
+ .primary-link span { font-size: 18px; line-height: 1; }
344
+ .primary-link:hover { filter: brightness(1.09); transform: translateY(-1px); text-decoration: none; }
345
+ /* 首页 hero 的主按钮:进建筑是这一页最想让人点的那一下,尺寸与间距都压过次级入口。 */
346
+ .primary-link-lead { gap: 36px; padding: 15px 24px; font-size: 15px; box-shadow: var(--shadow); }
347
+ .secondary-link { display: inline-flex; align-items: center; padding: 12px 18px; border: 1px solid var(--border-strong); border-radius: 8px; background: var(--surface-soft); color: var(--text); font-size: 13px; font-weight: 600; transition: border-color .15s, color .15s; }
348
+ .secondary-link:hover { border-color: var(--accent); color: var(--accent); text-decoration: none; }
349
+ .hero-hint { font-size: 12px; color: var(--muted); }
350
+ .workspace-details { margin-top: 20px; max-width: 100%; color: var(--muted); font-size: 12px; }
351
+ .workspace-details summary { cursor: pointer; width: fit-content; max-width: 100%; overflow-wrap: anywhere; }
352
+ .workspace-details p { margin: 8px 0 0; padding: 10px 12px; background: var(--surface-soft); border: 1px solid var(--border); border-radius: 6px; overflow-wrap: anywhere; }
353
+ .top .workspace-details { margin-top: 12px; }
354
+ .hero-art { position: relative; min-width: 0; color: var(--accent); background: radial-gradient(ellipse, var(--glow), transparent 69%); }
355
+ .hero-art svg { position: relative; display: block; width: 100%; height: auto; }
356
+ .art-grid { position: absolute; inset: 0; background-image: linear-gradient(var(--grid) 1px, transparent 1px), linear-gradient(90deg, var(--grid) 1px, transparent 1px); background-size: 32px 32px; mask-image: radial-gradient(ellipse, #000 12%, transparent 70%); }
357
+ .art-ghost { fill: var(--surface); stroke: var(--border-strong); stroke-opacity: .55; }
358
+ .art-node-halo { fill: var(--accent-bg); stroke: var(--accent-border); opacity: .65; }
359
+ .art-node { fill: var(--surface); stroke: var(--accent-border); }
360
+ .art-dot { opacity: .7; }
361
+ .art-caption { display: block; text-align: center; color: var(--muted); font-size: 10px; letter-spacing: 4px; margin-top: -12px; }
362
+ .project-metrics { display: grid; grid-template-columns: 1fr 1fr 1.35fr; padding: 23px 0; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
363
+ .project-metrics > div { padding: 0 30px; border-left: 1px solid var(--border); }
364
+ .project-metrics > div:first-child { padding-left: 0; border-left: 0; }
365
+ .metric-label { display: block; color: var(--muted); font-size: 12px; margin-bottom: 8px; }
366
+ .project-metrics strong { font: 500 30px/1.3 "Segoe UI", sans-serif; color: var(--text); margin-right: 12px; font-variant-numeric: tabular-nums; }
367
+ .metric-unit { font-size: 12px; color: var(--muted); }
368
+ .metric-note p { margin: 0 0 2px; color: var(--secondary); font-size: 14px; font-weight: 500; }
369
+ .metric-note p span { color: var(--muted); padding: 0 10px; }
370
+ .business-section { padding-top: 38px; scroll-margin-top: 22px; }
371
+ .section-heading { display: flex; gap: 20px; justify-content: space-between; align-items: flex-end; margin-bottom: 20px; }
372
+ .section-heading .eyebrow { margin-bottom: 6px; font-size: 10px; }
373
+ .section-heading h2 { margin: 0; color: var(--text); font-size: 23px; font-weight: 600; letter-spacing: -.5px; }
374
+ .home-page .status[data-kind="ok"] { color: var(--muted); }
375
+ .home-page .status { white-space: normal; text-align: right; }
376
+ .home-cards { grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); gap: 20px; }
377
+ .business-card { display: flex; flex-direction: column; padding: 26px 28px 20px; border-radius: 13px; min-height: 245px; transition: border-color .18s, box-shadow .18s, transform .18s; overflow-wrap: anywhere; }
378
+ .business-card:hover { border-color: var(--accent-border); box-shadow: var(--shadow); transform: translateY(-3px); }
379
+ .business-card-top { display: flex; align-items: center; justify-content: space-between; margin-bottom: 20px; }
380
+ .business-icon { display: grid; place-items: center; width: 38px; height: 38px; border: 1px solid var(--border); border-radius: 10px; color: var(--accent); background: var(--surface-soft); }
381
+ .business-icon svg { width: 22px; height: 22px; }
382
+ .business-number { font: 12px/1.5 Consolas, monospace; color: var(--muted); }
383
+ .business-card h3 { margin: 0 0 8px; color: var(--text); font-size: 20px; font-weight: 600; }
384
+ .business-card .business-intro { margin: 0 0 24px; color: var(--muted); font-size: 13px; line-height: 1.8; }
385
+ .business-card .chip-row { margin: 0 0 20px; }
386
+ .business-card-footer { display: flex; gap: 16px; justify-content: space-between; margin-top: auto; padding-top: 16px; border-top: 1px solid var(--border); color: var(--muted); font-size: 12px; }
387
+ .business-enter { color: var(--accent); white-space: nowrap; }
388
+ .business-card .business-warning { color: var(--danger); margin: 0 0 16px; padding: 8px 10px; background: var(--danger-bg); border-radius: 6px; font-size: 12px; }
389
+ .loading-copy { color: var(--muted); }
390
+ .empty-state { grid-column: 1 / -1; padding: 35px; border: 1px dashed var(--border-strong); border-radius: 12px; }
391
+ .empty-state h3 { font-size: 17px; margin: 0 0 8px; }
392
+ .empty-state p { color: var(--muted); margin: 0; }
393
+ .home-footer { display: flex; justify-content: space-between; gap: 16px; padding: 28px 0; margin-top: 46px; border-top: 1px solid var(--border); color: var(--muted); font-size: 11px; }
394
+ .page-content { max-width: 1320px; margin: 0 auto; padding: 36px 40px 56px; }
395
+ .read-page .page-content { max-width: 1800px; }
396
+ .top { gap: 32px; margin-bottom: 28px; }
397
+ .top > div { min-width: 0; }
398
+ .top h1 { margin: 14px 0 10px; font-size: 28px; line-height: 1.4; overflow-wrap: anywhere; }
399
+ .top .sub { overflow-wrap: anywhere; }
400
+ .top #repoLine { margin-top: 10px; font-size: 12px; }
401
+ .top .status { white-space: normal; text-align: right; max-width: 34%; flex-shrink: 0; }
402
+ .business-page .cards { gap: 20px; grid-template-columns: repeat(auto-fill, minmax(min(100%, 320px), 1fr)); }
403
+ /* 图卡与首页业务卡同构:内容顶对齐、meta 沉底,同行卡片底部空白齐平。 */
404
+ .business-page .card { display: flex; flex-direction: column; padding: 24px; border-radius: 12px; overflow-wrap: anywhere; }
405
+ .business-page .card .meta { margin-top: auto; padding-top: 10px; }
406
+ .business-page .card h2 { line-height: 1.7; margin-bottom: 10px; }
407
+ .chart-summary { margin: 0 0 18px; }
408
+ /* 汇总行点状态后的定位提示:闪一下目标卡的外框,1.2s 后撤掉(business.js)。 */
409
+ .card.flash { outline: 2px solid var(--accent); outline-offset: 3px; }
410
+
411
+ /* ── 展示页:吸顶格式切换器+星图+球阵 ───────────────────────────── */
412
+ .heading-side { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; }
413
+ .showcase-link {
414
+ display: inline-flex; padding: 7px 14px; border-radius: 8px;
415
+ border: 1px solid var(--accent-border); background: var(--accent-bg); color: var(--accent);
416
+ font-size: 12px; font-weight: 600; white-space: nowrap;
417
+ }
418
+ .showcase-link:hover { background: var(--accent-hover); text-decoration: none; }
419
+ .view-switch {
420
+ position: sticky; top: 0; z-index: 6;
421
+ display: flex; gap: 6px; align-items: center;
422
+ margin: 0 -40px 22px; padding: 10px 40px;
423
+ background: var(--page); border-bottom: 1px solid var(--border);
424
+ }
425
+ .view-switch button[data-view] {
426
+ padding: 7px 16px; border-radius: 8px; border: 1px solid var(--border);
427
+ background: var(--surface); color: var(--secondary); font-size: 13px; cursor: pointer;
428
+ }
429
+ .view-switch button[data-view]:hover { color: var(--text); }
430
+ .view-switch button[data-view][aria-pressed="true"] { border-color: var(--accent-border); background: var(--accent-bg); color: var(--accent); }
431
+ .sphere-start {
432
+ margin-left: auto; padding: 7px 14px; border-radius: 8px;
433
+ border: 1px solid var(--success-border); background: var(--success-bg); color: var(--success);
434
+ font-size: 12px; cursor: pointer;
435
+ }
436
+ .sphere-start:hover { background: var(--success-hover); }
437
+ .view-note { margin: 10px 2px 0; color: var(--muted); font-size: 12px; }
438
+ /* 星图:SVG 星座。主星带光晕并错相闪烁;连线只连真实归属。 */
439
+ .star-box { border: 1px solid var(--border); border-radius: 12px; background: var(--surface-soft); overflow: hidden; }
440
+ .star-svg { display: block; width: 100%; height: auto; }
441
+ .star-svg a { cursor: pointer; }
442
+ .star-line { stroke: var(--accent-border); stroke-width: 1; opacity: .7; }
443
+ .star-glow { fill: var(--glow); animation: star-twinkle 3.2s ease-in-out infinite; }
444
+ .star-business { fill: var(--accent); }
445
+ .star-svg a:hover .star-business { fill: var(--primary); }
446
+ .star-chart { fill: var(--secondary); }
447
+ .star-svg a:hover .star-chart { fill: var(--accent); }
448
+ .star-label { fill: var(--text); font-size: 15px; font-weight: 600; }
449
+ @keyframes star-twinkle { 0%, 100% { opacity: .5; } 50% { opacity: 1; } }
450
+ /* 球阵:节点绝对定位,位移/层序/透明度由 showcase.js 每帧写入。 */
451
+ .sphere-box {
452
+ position: relative; height: 520px; overflow: hidden; border: 1px solid var(--border); border-radius: 12px;
453
+ background: radial-gradient(ellipse at 50% 45%, var(--glow), transparent 70%), var(--surface-soft);
454
+ }
455
+ .sphere-node { position: absolute; display: grid; place-items: center; width: 18px; height: 18px; color: inherit; }
456
+ .sphere-node[data-kind="business"] { width: 34px; height: 34px; }
457
+ .sphere-dot {
458
+ display: block; width: 100%; height: 100%; border-radius: 50%;
459
+ background: var(--accent-bg); border: 1px solid var(--accent-border); box-shadow: 0 0 18px var(--glow);
460
+ }
461
+ .sphere-node[data-kind="chart"] .sphere-dot { background: var(--surface); border-color: var(--border-strong); box-shadow: none; }
462
+ .sphere-node:hover .sphere-dot { border-color: var(--accent); }
463
+ .sphere-label { position: absolute; top: 100%; margin-top: 5px; white-space: nowrap; font-size: 12px; color: var(--text); }
464
+ .sphere-node[data-kind="chart"] .sphere-label { display: none; }
465
+ .badge { font-weight: 500; white-space: normal; }
466
+ .card h2 .badge { font-weight: 500; }
467
+ .versions button { font-family: inherit; }
468
+ .guide, .panel, .details-panel, .evidence-panel { overflow-wrap: anywhere; }
469
+ @media (max-width: 850px) {
470
+ .app-bar { padding: 16px 28px; }
471
+ .home-main, .page-content { padding-left: 28px; padding-right: 28px; }
472
+ .project-hero { gap: 20px; grid-template-columns: 1.4fr 1fr; padding: 42px 0; min-height: 330px; }
473
+ .hero-hint { display: none; }
474
+ .project-metrics { grid-template-columns: 1fr 1fr; }
475
+ .project-metrics .metric-note { display: none; }
476
+ .business-card { padding: 22px; }
477
+ .view-switch { margin: 0 -28px 22px; padding: 10px 28px; }
478
+ }
479
+ @media (max-width: 600px) {
480
+ .app-bar { min-height: 72px; padding: 14px 20px; gap: 12px; }
481
+ .brand-caption { display: none; }
482
+ .brand { font-size: 17px; gap: 10px; }
483
+ .theme-switch button { padding: 5px 8px; }
484
+ .theme-switch button span { display: none; }
485
+ .home-main, .page-content { padding-left: 20px; padding-right: 20px; }
486
+ .project-hero { display: block; min-height: auto; padding: 38px 0 32px; }
487
+ .hero-art { display: none; }
488
+ .project-hero h1 { font-size: 30px; letter-spacing: -.8px; }
489
+ .hero-actions { margin-top: 24px; }
490
+ .project-metrics > div { padding: 0 18px; }
491
+ .project-metrics strong { display: block; margin-bottom: 3px; }
492
+ .business-section { padding-top: 30px; }
493
+ .section-heading { align-items: center; }
494
+ .home-footer { margin-top: 30px; flex-wrap: wrap; }
495
+ .home-footer > span:last-child { display: none; }
496
+ .top { display: block; }
497
+ .top .status { max-width: none; margin-top: 16px; text-align: left; }
498
+ .top h1 { font-size: 24px; }
499
+ .view-switch { margin: 0 -20px 18px; padding: 8px 20px; }
500
+ .sphere-box { height: 400px; }
501
+ }
502
+ @media (prefers-reduced-motion: reduce) {
503
+ html { scroll-behavior: auto; }
504
+ *, *::before, *::after { transition: none !important; animation: none !important; }
505
+ }
506
+
507
+ /* ── 建筑总览页:三维视图+房间目录 ───────────────────────────── */
508
+ .building-layout {
509
+ display: grid; grid-template-columns: minmax(0, 1fr) 400px; gap: 18px;
510
+ align-items: stretch; margin-top: 18px;
511
+ }
512
+ .building-viewport {
513
+ position: relative; min-width: 0; min-height: 560px; height: calc(100vh - 230px);
514
+ border: 1px solid var(--border); border-radius: 14px; overflow: hidden;
515
+ background: radial-gradient(120% 90% at 50% 0%, #eef3ea 0%, #dfe7da 62%, #d3ddce 100%);
516
+ }
517
+ .building-viewport canvas { display: block; width: 100%; height: 100%; touch-action: none; }
518
+ .view-toolbar {
519
+ position: absolute; top: 12px; left: 12px; right: 12px; z-index: 2;
520
+ display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap;
521
+ pointer-events: none;
522
+ }
523
+ .view-toolbar > * { pointer-events: auto; }
524
+ /* 操作行分两段:左边是浏览方式,右边是资料目录开关(目录收起后开关仍在原位,点得回来)。 */
525
+ .toolbar-group { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
526
+ .toolbar-field { font-size: 13px; color: #41504a; }
527
+ .floor-select, .reset-button, .walk-button, .panel-toggle {
528
+ padding: 7px 12px; border-radius: 8px; font-size: 13px; font-family: inherit;
529
+ border: 1px solid #b9c6b2; background: rgba(251, 250, 240, .92); color: #29433a;
530
+ }
531
+ .floor-select:hover, .reset-button:hover, .walk-button:hover, .panel-toggle:hover { border-color: #487465; }
532
+ .walk-button { font-weight: 600; border-color: #7f9c8b; }
533
+ .walk-button[aria-pressed="true"] { background: #487465; border-color: #3d6455; color: #fbfaf0; }
534
+ .walk-button:disabled { cursor: not-allowed; opacity: .55; border-color: #b9c6b2; color: #7d8f81; }
535
+ .preview-toggle {
536
+ display: inline-flex; align-items: center; gap: 8px; cursor: pointer;
537
+ padding: 7px 12px; border-radius: 8px; border: 1px dashed #9db4a4;
538
+ background: rgba(251, 250, 240, .92); color: #29433a; font-size: 13px;
539
+ }
540
+ .preview-toggle small { display: block; font-size: 11px; color: #7d8f81; }
541
+ .preview-banner {
542
+ position: absolute; bottom: 16px; left: 50%; transform: translateX(-50%); z-index: 2;
543
+ margin: 0; padding: 7px 16px; border-radius: 999px; font-size: 13px;
544
+ background: var(--warning-bg); border: 1px solid var(--warning-border); color: var(--warning);
545
+ }
546
+ .scene-hint {
547
+ position: absolute; right: 14px; bottom: 12px; z-index: 1; margin: 0;
548
+ font-size: 12px; color: #6c7d70; pointer-events: none;
549
+ }
550
+ /* 探索模式的操作层:左下角位置提示与方向按钮,按钮按住即走(pointerdown/up)。 */
551
+ .walk-hud {
552
+ position: absolute; left: 12px; bottom: 12px; z-index: 2;
553
+ display: flex; flex-direction: column; align-items: flex-start; gap: 8px;
554
+ }
555
+ /* 进不去探索的说明:和漫游操作层同角(进不去时操作层是隐藏的,不会叠在一起)。 */
556
+ .walk-notice {
557
+ position: absolute; left: 12px; bottom: 12px; z-index: 3; margin: 0;
558
+ max-width: min(460px, calc(100% - 24px)); padding: 8px 14px; border-radius: 10px;
559
+ font-size: 12px; line-height: 1.6;
560
+ background: var(--warning-bg); border: 1px solid var(--warning-border); color: var(--warning);
561
+ }
562
+ .walk-location {
563
+ margin: 0; padding: 6px 14px; border-radius: 999px; font-size: 12px;
564
+ background: rgba(251, 250, 240, .92); border: 1px solid #b9c6b2; color: #29433a;
565
+ }
566
+ .walk-pad { display: grid; grid-template-columns: repeat(3, 38px); gap: 4px; }
567
+ .walk-pad button {
568
+ width: 38px; height: 36px; border-radius: 8px; font-size: 15px; line-height: 1;
569
+ border: 1px solid #b9c6b2; background: rgba(251, 250, 240, .92); color: #2f4a3f;
570
+ touch-action: none; user-select: none;
571
+ }
572
+ .walk-pad button:hover { border-color: #487465; }
573
+ .walk-pad button[data-pressed="true"] { background: #487465; border-color: #3d6455; color: #fbfaf0; }
574
+ .walk-pad [data-walk-key="ArrowUp"] { grid-area: 1 / 2; }
575
+ .walk-pad [data-walk-key="ArrowLeft"] { grid-area: 2 / 1; }
576
+ .walk-pad [data-walk-key="ArrowDown"] { grid-area: 2 / 2; }
577
+ .walk-pad [data-walk-key="ArrowRight"] { grid-area: 2 / 3; }
578
+ .scene-fallback {
579
+ position: absolute; inset: 0; z-index: 3; display: flex; flex-direction: column;
580
+ align-items: center; justify-content: center; gap: 8px; text-align: center; padding: 28px;
581
+ background: color-mix(in srgb, var(--page) 78%, transparent);
582
+ }
583
+ .scene-fallback strong { font-size: 17px; }
584
+ .scene-fallback p { margin: 0; max-width: 46ch; color: var(--secondary); font-size: 13px; }
585
+ .building-directory {
586
+ display: flex; flex-direction: column; gap: 16px; padding: 20px;
587
+ border: 1px solid var(--border); border-radius: 14px; background: var(--surface);
588
+ max-height: calc(100vh - 230px); overflow-y: auto;
589
+ }
590
+ .building-directory .project-block h2 { margin: 8px 0 6px; font-size: 21px; }
591
+ .project-description { margin: 0; color: var(--muted); font-size: 13px; }
592
+ .metrics { margin: 10px 0 0; font-size: 13px; color: var(--secondary); }
593
+ .phase-card {
594
+ display: flex; gap: 12px; align-items: flex-start; padding: 13px 15px;
595
+ border: 1px solid var(--accent-border); background: var(--accent-bg); border-radius: 10px;
596
+ }
597
+ .phase-card .status-dot {
598
+ flex: none; width: 10px; height: 10px; border-radius: 999px; margin-top: 5px;
599
+ background: var(--accent); box-shadow: 0 0 0 4px var(--glow);
600
+ }
601
+ .phase-card strong { font-size: 14px; }
602
+ .phase-card p { margin: 3px 0 0; font-size: 12.5px; color: var(--secondary); }
603
+ .notices details {
604
+ border: 1px solid var(--warning-border); background: var(--warning-bg);
605
+ border-radius: 10px; padding: 10px 14px; font-size: 13px;
606
+ }
607
+ .notices summary { cursor: pointer; color: var(--warning); font-weight: 600; }
608
+ .notices ul { margin: 8px 0 2px; padding-left: 18px; color: var(--secondary); }
609
+ .notices li { margin: 4px 0; }
610
+ .section-label { font-size: 12px; letter-spacing: .12em; color: var(--muted); text-transform: uppercase; }
611
+ .section-label span { text-transform: none; letter-spacing: 0; }
612
+ .rooms { display: flex; flex-direction: column; gap: 12px; }
613
+ .room-card {
614
+ border: 1px solid var(--border); border-radius: 10px; padding: 13px 15px;
615
+ background: var(--surface-soft); cursor: pointer;
616
+ }
617
+ .room-card:hover { border-color: var(--border-strong); background: var(--hover); }
618
+ .room-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
619
+ .room-title { font-weight: 650; font-size: 15px; }
620
+ .room-meta { font-size: 12px; color: var(--muted); }
621
+ .room-intro { margin: 6px 0 0; font-size: 12.5px; color: var(--secondary); }
622
+ .room-entries { list-style: none; margin: 10px 0 0; padding: 0; display: flex; flex-direction: column; gap: 5px; }
623
+ /* 目录卡里的资料入口:按钮(在房内面板里读),不是外链。 */
624
+ .room-entry {
625
+ display: block; width: 100%; text-align: left; font: inherit; cursor: pointer;
626
+ color: var(--text); font-size: 12.5px; padding: 5px 9px; border-radius: 6px;
627
+ border: 1px solid var(--border); background: var(--surface);
628
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
629
+ }
630
+ .room-entry:hover { border-color: var(--accent-border); background: var(--accent-bg); }
631
+ .room-empty { margin: 8px 0 0; font-size: 12px; color: var(--muted); }
632
+ .diagnostics-panel {
633
+ margin-top: 18px; padding: 20px 22px; border: 1px solid var(--danger-border);
634
+ background: var(--danger-bg); border-radius: 14px;
635
+ }
636
+ .diagnostics-panel h2 { margin: 0 0 4px; font-size: 18px; color: var(--danger); }
637
+ .diagnostics-note { margin: 0 0 12px; font-size: 13px; color: var(--secondary); }
638
+ .problem-list { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 8px; }
639
+ .problem-item {
640
+ display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px;
641
+ padding: 9px 12px; border-radius: 8px; background: var(--surface);
642
+ border: 1px solid var(--border); font-size: 13px;
643
+ }
644
+ .problem-item[data-severity="error"] { border-color: var(--danger-border); }
645
+ .problem-item[data-severity="warning"] { border-color: var(--warning-border); }
646
+ .problem-code { flex: none; font-family: ui-monospace, Consolas, monospace; font-size: 12px; color: var(--muted); }
647
+ .problem-message { flex: 1 1 30ch; }
648
+ .problem-path {
649
+ font-family: ui-monospace, Consolas, monospace; font-size: 12px;
650
+ background: var(--code-bg); border: 1px solid var(--border); border-radius: 5px; padding: 1px 6px;
651
+ color: var(--accent);
652
+ }
653
+ @media (max-width: 1080px) {
654
+ .building-layout { grid-template-columns: 1fr; }
655
+ .building-directory { max-height: none; }
656
+ .building-viewport { height: 62vh; min-height: 420px; }
657
+ /* 窄屏上操作层与右下角提示、底部横幅会挤在一起:位置提示挪到提示行上方。 */
658
+ .walk-hud { bottom: 34px; }
659
+ .preview-banner { bottom: 78px; }
660
+ }
661
+
662
+ /* ── 建筑总览页的"全窗口"形态(作者 2026-09-25 提出)────────────────────
663
+ 建筑生成成功后整页切到这一形态:页面不滚动,三维视图占满浏览器窗口,
664
+ 资料目录改成浮在视口右侧的抽屉,点开关收起后视图占满全宽。
665
+ 类由 building.js 在让舞台现身时加到 body 上——没有蓝图、诊断失败、未配置
666
+ 这些页没有舞台、不加这个类,仍是普通滚动文档。 */
667
+ .building-page.building-live { height: 100vh; height: 100dvh; overflow: hidden; display: flex; flex-direction: column; }
668
+ /* 顶栏与页头压成两行,把高度让给视图;工作区行展开时浮在页面上,不把视图挤下去。 */
669
+ .building-page.building-live .app-bar { flex: none; min-height: 60px; padding: 8px 22px; }
670
+ .building-page.building-live .brand { font-size: 16px; }
671
+ .building-page.building-live .brand-mark { width: 28px; height: 28px; font-size: 18px; border-radius: 8px; }
672
+ .building-page.building-live .page-content {
673
+ flex: 1; min-height: 0; width: 100%; max-width: none; padding: 14px 22px 18px;
674
+ display: flex; flex-direction: column;
675
+ /* 正常窗口装得下、页面不滚动;窗口矮到装不下时(视图有最小高度)在这里滚,
676
+ 不让内容被裁掉。 */
677
+ overflow: auto;
678
+ }
679
+ .building-page.building-live .top { flex: none; align-items: baseline; gap: 18px; margin-bottom: 10px; }
680
+ .building-page.building-live .top > div { display: flex; align-items: baseline; gap: 4px 16px; flex-wrap: wrap; }
681
+ .building-page.building-live .top h1 { margin: 0; font-size: 20px; }
682
+ .building-page.building-live .top .crumbs { margin: 0; }
683
+ /* 一句话说明压成一行(窄了截断),不让页头长高。 */
684
+ .building-page.building-live .top .sub {
685
+ flex: 1 1 20ch; min-width: 0; margin: 0; font-size: 12.5px;
686
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
687
+ }
688
+ .building-page.building-live .workspace-details { margin-top: 0; }
689
+ .building-page.building-live .workspace-details p { position: absolute; z-index: 6; max-width: min(80ch, 90vw); box-shadow: var(--shadow); }
690
+ .building-page.building-live .building-layout {
691
+ position: relative; flex: 1; min-height: 0; margin-top: 0;
692
+ display: flex; flex-direction: column;
693
+ /* 抽屉宽度是唯一来源:让位宽度由它算出来(抽屉 + 左右各 12px 间距),两者不会再对不上
694
+ ——按一半宽度让位时,窄窗口上提示会被更宽的抽屉盖住。 */
695
+ --panel-w: min(400px, calc(100% - 24px));
696
+ --dock: calc(var(--panel-w) + 24px);
697
+ }
698
+ .building-page.building-live .building-layout[data-directory="closed"] { --dock: 0px; }
699
+ .building-page.building-live .building-viewport { flex: 1; min-height: 320px; height: auto; }
700
+ .building-page.building-live .preview-banner {
701
+ left: calc((100% - var(--dock)) / 2); bottom: 16px; text-align: center;
702
+ /* 窄窗口上按剩余可见宽度收窄并折行。 */
703
+ max-width: max(120px, calc(100% - var(--dock) - 24px));
704
+ }
705
+ .building-page.building-live .scene-hint {
706
+ /* 提示就在操作行里:常态排布(不再是绝对定位的右下角浮字),窄屏跟着换行、由 --toolbar-h
707
+ 一并算进让位高度——它不会再和底部横幅、左下角方向按钮区抢地方。 */
708
+ position: static; margin: 0; max-width: none;
709
+ font-size: 12px; color: #6c7d70; pointer-events: none;
710
+ }
711
+ /* 抽屉本身:从操作行下方开始(开关那一行始终露在外面),收起时移出右侧并退出命中与焦点。
712
+ 起点按操作行的实际高度算(--toolbar-h 由 building.js 量,含窄屏换行与放大字号),
713
+ 不让抽屉盖住收起开关。 */
714
+ .building-page.building-live .building-directory {
715
+ position: absolute; top: calc(24px + var(--toolbar-h, 34px)); right: 12px; bottom: 12px; z-index: 3;
716
+ width: var(--panel-w); max-height: none;
717
+ box-shadow: var(--shadow);
718
+ transition: transform .18s ease, opacity .18s ease, visibility .18s;
719
+ }
720
+ .building-page.building-live .building-layout[data-directory="closed"] .building-directory {
721
+ transform: translateX(calc(100% + 20px)); opacity: 0; visibility: hidden;
722
+ }
723
+ /* 读资料时目录也让位(面板是浮在视口上的卡片,目录在它后面只露半截):抽屉与它的开关一起
724
+ 收起来,读完关掉面板就回来。这是显示规则,不改作者存的展开/收起选择。 */
725
+ .building-page.building-live .building-layout[data-reading="true"] { --dock: 0px; }
726
+ .building-page.building-live .building-layout[data-reading="true"] .building-directory {
727
+ transform: translateX(calc(100% + 20px)); opacity: 0; visibility: hidden;
728
+ }
729
+ .building-page.building-live .building-layout[data-reading="true"] .panel-toggle { visibility: hidden; }
730
+ /* 读资料时锁住场景交互:卡片四周露出的画布不接拖动、滚轮与点牌子(关掉面板就恢复);
731
+ 屏幕方向按钮同样不生效并变淡(该停的输入一起停,页面那层还有一道闸)。
732
+ 操作提示这时也收起:它介绍的几个动作此刻都做不了。 */
733
+ .building-page.building-live .building-layout[data-reading="true"] .building-viewport canvas { pointer-events: none; }
734
+ .building-page.building-live .building-layout[data-reading="true"] .walk-pad button { opacity: .45; pointer-events: none; }
735
+ .building-page.building-live .building-layout[data-reading="true"] .scene-hint { visibility: hidden; }
736
+ /* 资料卡片顶部让开操作行(含换行后的实际高度),底部让开"完整外观预览"横幅的实际高度
737
+ (窄屏它会折行):两头都不许压住露在外面的东西。面板不是模态,露在外面的控制照常可用。 */
738
+ .building-page.building-live .material-panel {
739
+ inset-block-start: max(clamp(28px, 6vh, 64px), calc(var(--toolbar-h, 34px) + 36px));
740
+ inset-block-end: max(clamp(28px, 6vh, 64px), calc(var(--banner-h, 0px) + 24px));
741
+ }
742
+ /* 窗口窄到抽屉几乎占满整幅(< 600px):并排放不下提示,改成"抽屉让开底部一条带"——
743
+ 横幅按实际高度留在带里(它是如实标注,不许被盖住)。操作提示此刻在操作行里,不受影响。 */
744
+ @media (max-width: 600px) {
745
+ .building-page.building-live .building-layout { --dock: 0px; }
746
+ .building-page.building-live .building-directory {
747
+ bottom: calc(12px + var(--banner-h, 0px) + 16px);
748
+ }
749
+ }
750
+ /* 小窗口漫游时左下角是方向按钮区,横幅与它并排不下:让横幅退场——同一句话在页头状态行上
751
+ 一直都有("完整外观预览 · 不代表当前阶段(…)"),没有丢掉这条如实标注。 */
752
+ @media (max-width: 1080px) {
753
+ .building-page.building-live .building-layout:has(.walk-hud:not([hidden])) .preview-banner { display: none; }
754
+ }
755
+
756
+
757
+ /* ── 房内打开资料:介绍+资料清单+正文/流程图都在这块面板里 ──────────
758
+ 面板是浮在三维视口上的一张卡片:四周留一圈建筑(作者 2026-09-25 验收时提出——
759
+ 全覆盖会让人看不出自己还在房子里),宽屏也不摊满;打开时暂停漫游输入,人留在原地,
760
+ 关闭后位置与视角原样,接着走。 */
761
+ .material-panel {
762
+ position: absolute; inset: clamp(28px, 6vh, 64px) clamp(28px, 4vw, 84px); z-index: 4;
763
+ display: flex; flex-direction: column;
764
+ max-width: 1480px; margin-inline: auto;
765
+ background: color-mix(in srgb, var(--surface) 97%, transparent);
766
+ border: 1px solid var(--border); border-radius: 14px; overflow: hidden;
767
+ /* 卡片压在浅色场景上,用比通用阴影更重的一档,两套主题下都看得出是浮层。 */
768
+ box-shadow: 0 16px 44px rgba(14, 26, 20, .22);
769
+ }
770
+ .material-panel[hidden] { display: none; }
771
+ .material-head {
772
+ flex: none; display: flex; align-items: flex-start; justify-content: space-between; gap: 14px;
773
+ padding: 14px 18px; border-bottom: 1px solid var(--border);
774
+ }
775
+ .material-kind {
776
+ margin: 0; font-size: 11.5px; letter-spacing: .12em; color: var(--muted); text-transform: uppercase;
777
+ }
778
+ .material-heading h2 { margin: 5px 0 0; font-size: 19px; }
779
+ .material-close {
780
+ flex: none; width: 28px; height: 28px; border-radius: 6px; border: 1px solid var(--border);
781
+ background: var(--surface-soft); color: var(--secondary); font-size: 16px; line-height: 1; cursor: pointer;
782
+ }
783
+ .material-close:hover { background: var(--hover); }
784
+ .material-body {
785
+ flex: 1; min-height: 0; display: grid; grid-template-columns: minmax(200px, 280px) minmax(0, 1fr);
786
+ }
787
+ .material-side { padding: 14px 16px; overflow-y: auto; border-right: 1px solid var(--border); }
788
+ .material-intro { margin: 0 0 14px; font-size: 13px; color: var(--secondary); }
789
+ .material-list-label {
790
+ margin: 0; font-size: 11.5px; letter-spacing: .12em; color: var(--muted); text-transform: uppercase;
791
+ }
792
+ .material-list { list-style: none; margin: 10px 0 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
793
+ /* 作者样式里的 display 会盖过 [hidden] 的 UA 规则:这两处显式收起来,别让"没有资料"时
794
+ 还留着一个空清单框(DOM 测试看不见这条,只在浏览器里现形)。 */
795
+ .material-list[hidden] { display: none; }
796
+ .material-item {
797
+ width: 100%; display: block; text-align: left; font: inherit; font-size: 12.5px;
798
+ padding: 6px 10px; border-radius: 6px; cursor: pointer;
799
+ border: 1px solid var(--border); background: var(--surface);
800
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
801
+ }
802
+ .material-item:hover { border-color: var(--accent-border); background: var(--accent-bg); }
803
+ .material-item[aria-current="true"] { border-color: var(--accent); background: var(--accent-bg); color: var(--accent); }
804
+ .material-empty { margin: 10px 0 0; font-size: 12.5px; color: var(--muted); }
805
+ .material-reader { display: flex; flex-direction: column; min-width: 0; min-height: 0; padding: 14px 18px 18px; }
806
+ .material-reader-hint { margin: 0; font-size: 13px; color: var(--muted); }
807
+ .material-reader-title { flex: none; margin: 0 0 8px; font-size: 13px; color: var(--secondary); }
808
+ .material-reader-status {
809
+ flex: none; margin: 0 0 10px; padding: 9px 12px; border-radius: 8px; font-size: 13px;
810
+ background: var(--danger-bg); border: 1px solid var(--danger-border); color: var(--danger);
811
+ overflow-wrap: anywhere;
812
+ }
813
+ .material-reader-status[data-kind="info"] {
814
+ background: var(--surface-soft); border-color: var(--border); color: var(--muted);
815
+ }
816
+ .material-reader-body { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
817
+ .material-doc-heading { margin: 18px 0 8px; font-size: 16px; }
818
+ .material-doc-heading[data-level="1"] { margin-top: 0; font-size: 20px; }
819
+ .material-doc-heading[data-level="2"] { font-size: 17px; }
820
+ .material-doc-paragraph { margin: 0 0 12px; color: var(--secondary); }
821
+ .material-doc-list { margin: 0 0 12px; padding-left: 20px; color: var(--secondary); }
822
+ .material-doc-list li { margin: 4px 0; }
823
+ .material-reader-body code {
824
+ font-family: ui-monospace, Consolas, monospace; font-size: 12.5px;
825
+ background: var(--code-bg); border: 1px solid var(--border); border-radius: 5px; padding: 1px 5px;
826
+ }
827
+ .material-doc-empty { margin: 0; color: var(--muted); }
828
+ .material-reader-frame {
829
+ flex: 1; width: 100%; min-height: 0; border: 1px solid var(--border); border-radius: 10px;
830
+ background: var(--page);
831
+ }
832
+ @media (max-width: 1080px) {
833
+ /* 窄屏上视口本身不高:清单与正文改成上下排,阅读区保住最小高度。 */
834
+ .material-body { grid-template-columns: 1fr; grid-template-rows: auto minmax(0, 1fr); }
835
+ .material-side { border-right: 0; border-bottom: 1px solid var(--border); max-height: 34%; }
836
+ }