/* 布局骨架（B0 冻结）—— 只定义面板网格与挂载点，不定义任何业务组件内部样式。
 * 各 bot 在自己的组件文件里负责自身样式，通过 link 追加进 head 或使用模块级 CSS 变量。
 */

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  font-family: var(--font-ui);
  font-size: 13px;
  color: var(--fg);
  background: var(--bg-app);
}

.mono { font-family: var(--font-mono); }

.hidden { display: none !important; }

/* ---- 模拟数据横幅：醒目且不可关闭 */
#sim-banner {
  display: flex;
  align-items: center;
  gap: var(--gap-md);
  padding: 6px var(--gap-lg);
  background: repeating-linear-gradient(45deg, #7c2d12, #7c2d12 12px, #9a3412 12px, #9a3412 24px);
  color: #fff7ed;
  font-size: 12px;
  letter-spacing: 0.02em;
}
#sim-banner strong { letter-spacing: 0.12em; }
#dataset-stamp { margin-left: auto; opacity: 0.85; }

/* ---- 顶部：KPI 头 + 范围栏 */
#app-header { background: var(--bg-panel); border-bottom: 1px solid var(--border); }
#kpi-header { padding: var(--gap-md) var(--gap-lg); min-height: 64px; }
#scope-bar {
  display: flex;
  align-items: center;
  gap: var(--gap-lg);
  padding: var(--gap-sm) var(--gap-lg);
  border-top: 1px solid var(--border);
}
#breadcrumb { display: flex; align-items: center; gap: var(--gap-sm); flex: 1; }
#breadcrumb .crumb {
  padding: 2px 8px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-panel-2);
  cursor: pointer;
}
#breadcrumb .crumb[aria-current="true"] { border-color: var(--tone-selected); color: #fff; }
#scenario-switch { display: flex; gap: var(--gap-xs); }
#scenario-switch button {
  padding: 3px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-panel-2);
  color: var(--fg);
  cursor: pointer;
  font: inherit;
}
#scenario-switch button[aria-pressed="true"] {
  border-color: var(--tone-selected);
  background: var(--tone-selected);
  color: #fff;
}

/* ---- 外壳：高度由真实 chrome 决定，不用魔法数字 ----
 * 旧写法是 `#app-body{height:calc(100% - 96px)}`，隐含假定「横幅 + 头部」恒为 96px。
 * B3 的时间轴把头撑到 363px 后，右栏整体溢出视口 267px；而 `#data-status` 是
 * `position:fixed;bottom:0`（28px 覆盖层），正好压住右栏第三个面板的起始区 ——
 * 表现就是 browser-smoke 的 panels-not-occluded 在 failure 场景失败
 * （遮挡源在 data-status 与 status-counts 之间来回变，因为它们是同一页脚的父/子元素）。
 *
 * 改成 flex 列：中间栏 `flex:1` 自动吃掉「视口 − 横幅 − 头部 − 页脚」的剩余高度，
 * 无论头部多高都不会溢出；页脚改为流内（视觉等价），从此不可能再遮住内容。
 * 注意：`#map.slot > .map-canvas` 依赖槽位有**明确高度**（见下方注释），
 * flex 解析出的高度是明确的，因此地图画布尺寸不受影响。 */
body {
  display: flex;
  flex-direction: column;
  height: 100%;
}
#sim-banner, #app-header, #data-status { flex: 0 0 auto; }

/* ---- 主体三栏 */
#app-body {
  display: grid;
  grid-template-columns: var(--rail-left-w) 1fr var(--rail-right-w);
  flex: 1 1 auto;
  min-height: 0;
}
#left-rail, #right-rail {
  overflow-y: auto;
  background: var(--bg-panel);
  padding: var(--gap-sm);
}
#left-rail { border-right: 1px solid var(--border); }
#right-rail { border-left: 1px solid var(--border); display: flex; flex-direction: column; gap: var(--gap-sm); }
#map-area { position: relative; min-width: 0; }

/* ---- 挂载点通用外观 */
.slot {
  position: relative;
  border: 1px dashed var(--border);
  border-radius: var(--radius-md);
  min-height: 56px;
  padding: var(--gap-sm);
  background: var(--bg-panel-2);
}
#map.slot { border-radius: 0; border: 0; padding: 0; min-height: 100%; background: #0b1220; }
/* 地图画布必须绝对定位铺满槽位。
 * 槽位自身是 `height:auto` + `min-height:100%`，而 CSS 规定：父级高度不是显式指定时，
 * 子元素的百分比高度退化为 auto —— 于是 `.map-canvas{height:100%}` 被算成 0，
 * Leaflet 视口高度为 0（zoom 掉到 0、画布全空，且不抛任何错）。绝对定位绕开这个退化。 */
#map.slot > .map-canvas { position: absolute; inset: 0; background: #0b1220; }
.pending-chip {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  background: rgba(148, 163, 184, 0.18);
  color: var(--fg-muted);
  font-size: 11px;
}

/* ---- 详情抽屉 */
.drawer {
  position: fixed;
  top: 96px;
  right: 0;
  bottom: 28px;
  width: 420px;
  border-left: 1px solid var(--tone-selected);
  background: var(--bg-panel);
  box-shadow: var(--shadow);
  overflow-y: auto;
  z-index: 900;
}

/* ---- 底部：数据包契约状态（B0） ---- */
/* 页脚改为**流内**（原为 position:fixed 覆盖层）：父级 body 是 flex 列且高度 100%，
 * 页脚作为最后一个 flex item 天然贴在视口底部，视觉等价；而覆盖层会压住右栏内容，
 * 正是 panels-not-occluded 曾经失败的原因。 */
#data-status {
  position: static;
  height: 28px;
  display: flex;
  align-items: center;
  gap: var(--gap-md);
  padding: 0 var(--gap-lg);
  background: #111827;
  border-top: 1px solid var(--border);
  font-size: 11px;
  color: var(--fg-muted);
}
#data-status[data-state="ok"] #status-text { color: var(--tone-good); }
#data-status[data-state="error"] #status-text { color: var(--tone-bad); }
#status-counts { margin-left: auto; }