/* ==========================================================================
   env.css —— 「环境叠加样式」（**通用 · 进版本库 · 生产与沙箱同一份**）
   --------------------------------------------------------------------------
   设计依据：OPS-SANDBOX-001 §5.6.4（前端仅切样式）· §6.4（前端强提示体系）

   ★ 核心机制（**零沙箱分支 · 零部署差异**）
     · 本文件在**两种环境加载同一份**（`index.html` 一行 <link>）
       ⇒ **不存在"沙箱专用前端构建/部署"** ⇒ 与 §5.5「版本先行」天然协同 ✅
     · 是否显示演练提示，**由 `html[data-sandbox="1"]` 决定**：
         该属性由 `src/stores/user.ts` 依【当前仓库是否为演练仓库】写入（**数据事实**，
         不是 `if (沙箱)` 逻辑）⇒ 生产**不设**该属性 ⇒ **规则整体不生效 ⇒ 零污染** ✅
     · 「当前路由」由 `src/router/index.ts` 的 `afterEach` 写入 `html[data-route]`
       （**与沙箱无关的通用钩子**，生产也在用）⇒ P 类页语义切换亦为**纯 CSS** ✅

   ★ 约束（§6.4.5 · 防"提示过度"）
     1. 全部覆盖层 `pointer-events:none` ⇒ **绝不拦截**点击/输入/拖拽 🔴
     2. 水印 `opacity ≤ 0.10` + `background-size` 足够大 ⇒ 阅读与截图仍清晰
     3. 只读操作不加确认（本文件不做 L3 弹窗；L3/L4 见决策 D17）
   ========================================================================== */

/* ---------- 顶层变量（无 data-sandbox 时全部规则不匹配，等于空文件） ---------- */
html[data-sandbox='1'] {
  --sbx-banner-h: 36px;
  --sbx-warn: #f56c6c; /* 演练（业务库）— 红 */
  --sbx-real: #e6a23c; /* 真实平台数据 — 橙 */
}

/* ==========================================================================
   L1 · 全屏背景水印 + 大 mark（覆盖全站，含弹窗；纯 CSS 伪元素）
   ========================================================================== */
html[data-sandbox='1'] body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 9998;
  pointer-events: none; /* 🔴 绝不挡点击 */
  opacity: 0.06; /* 🔴 ≤ 0.10：阅读/截图仍清晰 */
  background-repeat: repeat;
  background-size: 320px 320px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='320' height='320'%3E%3Cg fill='%23000000' font-family='sans-serif'%3E%3Ctext x='14' y='52' font-size='22' transform='rotate(-30 14 52)'%3E演练环境 · 数据不保留%3C/text%3E%3Ctext x='120' y='300' font-size='22' transform='rotate(-30 120 300)'%3E仅供参考 · 不可信%3C/text%3E%3Ctext x='160' y='190' text-anchor='middle' font-size='60' font-weight='bold'%3E演练%3C/text%3E%3C/g%3E%3C/svg%3E");
}

/* ==========================================================================
   L2 · 顶部常驻横幅（不可关闭 · 全站）
   ========================================================================== */
html[data-sandbox='1'] #app::before {
  /* ★ L1(b)：`--wm-user` / `--wm-date` 由 stores/user.ts 注入（生产不定义 ⇒ 不显示）
     ⇒ 截图可追溯【操作人 + 日期】（D12 要求）· 纯 CSS，零额外 DOM ✅ */
  /* 🔴 2026-09-22 修复（**横幅变"灰色空白"的真因**）：
     原写法 `content: '…' var(--wm-user, '') '…'` ⇒ **`--wm-user` 是【裸用户名】（如 `admin`）**，
     `var()` 替换后变成 `content: '…' admin '…'` —— **`admin` 是 ident、不是字符串** 🔴
     ⇒ 整条 `content` **invalid at computed-value time** ⇒ `content: normal`
     ⇒ **伪元素【根本不生成】** ⇒ 只剩 `#app { padding-top:36px }` 的**灰色空白**（无文字、无颜色）🔴
     ⚠️ 该缺陷**一直被浏览器 `immutable` 缓存掩盖**（固定 URL 无 hash）⇒ `?v=` 破缓存后**才暴露** ✅
     ✅ 改用 **`attr()`**：属性缺失时返回**空串**（**永不失效**）✅
     📌 `--wm-user` / `--wm-date` **仍保留**（`useExcelExport` 的**导出盖章**读取它，见 §5.6.8）*/
  content: '⚠️ 演练环境 ｜ ' attr(data-wm-user) ' ｜ ' attr(data-wm-date) ' ｜ 数据不保留、不可信，请勿录入真实业务数据';
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: var(--sbx-banner-h);
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--sbx-warn);
  color: #fff;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.5px;
  /* 🔴 2026-09-22 修复：原 `z-index: 9999` ⇒ **压住 ElMessage 弹窗**（错误提示被横幅盖住）🔴
     Element Plus 的覆盖层 z-index **从 2000 起**（`useZIndex`），且 `ElMessage` **出现在顶部居中**
     ⇒ 与横幅**位置重叠** ⇒ 9999 会**完全遮住错误消息** 🔴
     ✅ 现降为 **1990**（< 2000）⇒ **消息/弹窗一律渲染在横幅之上** ✅
     ⚠️ 边界：普通内容若 z-index > 1990（如自定义浮层）会盖住横幅 —— 属可接受（横幅是"常驻提示"）。 */
  z-index: 1990;
  pointer-events: none; /* 🔴 不挡操作 */
}

/* 为横幅让出高度 —— 避免遮挡页面顶部操作区
   🔴 关键（2026-09-22 实测教训）：
     布局里 `.sidebar` / `.layout-container` 是 **`position:fixed; top:0; height:100vh`**
     ⇒ 只给 `#app` 加 `padding-top` **对 fixed 元素无效** ⇒ 横幅会**盖住左侧菜单** 🔴
     ⇒ 必须**同时**把 fixed 容器整体下移，并扣掉横幅高度（否则底部溢出 100vh）✅ */
html[data-sandbox='1'] #app {
  padding-top: var(--sbx-banner-h);
}
html[data-sandbox='1'] .sidebar,
html[data-sandbox='1'] .layout-container {
  top: var(--sbx-banner-h);
  height: calc(100vh - var(--sbx-banner-h));
}
html[data-sandbox='1'] .main-content {
  height: calc(100vh - var(--sbx-banner-h));
}

/* ==========================================================================
   P 类页 · 平台数据页（`deiniuplatform` · **操作真实生效**）—— 提示【切换语义】
   --------------------------------------------------------------------------
   🔴 必须让「本库 admin」知晓：本类页改动**与正式环境完全等价**（平台库共享真实数据）
   🔴 判定方式 = **路由精确白名单**（依据「该页数据源来自 deiniuplatform」），
      **不是**前缀匹配、**不是**按角色/权限判定 —— 见 §6.4.2
      ⚠️ 反例：`/system/dictionary`（系统字典）数据源是 `t_node`（**业务库**）
         ⇒ **属演练数据**，**必须不在**本白名单内
   ========================================================================== */

/* ① 隐藏「演练/数据不保留」水印 —— 该表述在本类页**不成立**（数据会保留、立即生效） */
html[data-sandbox='1'][data-route='/system/user'] body::before,
html[data-sandbox='1'][data-route='/system/dept'] body::before,
html[data-sandbox='1'][data-route='/system/role'] body::before,
html[data-sandbox='1'][data-route='/system/role-emp'] body::before,
html[data-sandbox='1'][data-route='/system/role-auth'] body::before,
html[data-sandbox='1'][data-route='/system/auth'] body::before,
html[data-sandbox='1'][data-route='/profile'] body::before {
  display: none;
}

/* ② 横幅换文案：仍标识"沙箱会话"，但**不得**再写"数据不保留" */
html[data-sandbox='1'][data-route='/system/user'] #app::before,
html[data-sandbox='1'][data-route='/system/dept'] #app::before,
html[data-sandbox='1'][data-route='/system/role'] #app::before,
html[data-sandbox='1'][data-route='/system/role-emp'] #app::before,
html[data-sandbox='1'][data-route='/system/role-auth'] #app::before,
html[data-sandbox='1'][data-route='/system/auth'] #app::before,
html[data-sandbox='1'][data-route='/profile'] #app::before {
  /* ⚠️ 同 L2 主横幅：**必须用 `attr()`**，不可用 `var()`（裸 ident ⇒ content 失效 ⇒ 横幅不生成）🔴 */
  content: '⚠️ 沙箱会话 ｜ ' attr(data-wm-user) ' ｜ 本页为【真实平台数据】—— 与正式环境等价，请谨慎操作';
  background: var(--sbx-real);
}

/* ③ 改密码页（普通用户唯一可达的 platform 操作）—— 专文提示 */
html[data-sandbox='1'][data-route='/profile'] #app::before {
  content: '⚠️ 此处修改的是【真实】账号口令 —— 与正式环境等价，请勿在演练中随意更改';
  background: var(--sbx-real);
}

/* ④ ★ 2026-09-22 新增：【计费与对账】`/billing/*`（**去沙箱标志** · 与 P 类页同口径）
   --------------------------------------------------------------------------
   🔴 用户报告：「沙箱 billing 计费与对账模块下的数据也是操作 platform 的，需去除沙箱标志」✅
   🔴 该模块 **8 页**数据源**全部**为 `deiniuplatform`：
      `bills` 账单管理 · `warehouse` 仓库列表 · `profiles` 客户画像 · `rules` 订阅变更 ·
      `configs` 计费配置 · `plans` 套餐维护 · `reconcile` 费用对账 · `tenant` 客户中心
      （`t_tenant_bill` / `t_tenant_bill_detail` / `t_tenant_billing_rule` / `t_tenant_customer_profile`
       / `t_tenant_usage_monthly` / `t_billing_config` / `t_billing_plan` / `t_tenant` · 视图 `v_tenant_overview`）
      ⇒ **与 P 类页判据（§6.4.2「数据源来自 deiniuplatform」）完全一致** ✅
   🎯 实证：沙箱在平台库确有计费数据 —— `t_tenant_billing_rule` **44 行** ·
      账单 `id=6 · BI-10999-202608 · 833.33 元/月`（§P1-C）⇒ **操作真实生效** 🔴
   ⚠️ 修正前：未列入白名单 ⇒ 该页被误打「演练环境 · 数据不保留」水印 + 红色 L2 横幅，
      与实际"写真实平台库"矛盾（且违背 §5.1.1 推论 1）🔴
   📌 用**属性前缀** `[data-route^='/billing/']` 一次覆盖 8 页**及将来新增子页** ——
      整个命名空间皆 platform 数据源，**不存在** `/system/dictionary` 式"同前缀但属演练数据"的反例 ✅ */

/* ④-1 隐藏「演练/数据不保留」水印（该表述在本类页**不成立**：数据会保留、立即生效） */
html[data-sandbox='1'][data-route^='/billing/'] body::before,
html[data-sandbox='1'][data-route='/billing'] body::before {
  display: none;
}

/* ④-2 横幅换文案（仍标识"沙箱会话"，但**不得**再写"数据不保留"） */
html[data-sandbox='1'][data-route^='/billing/'] #app::before,
html[data-sandbox='1'][data-route='/billing'] #app::before {
  /* ⚠️ 必须用 `attr()`（`var()` 注裸值 ⇒ content 失效 ⇒ 横幅不生成）—— 同上方 L2 注释 🔴 */
  content: '⚠️ 沙箱会话 ｜ ' attr(data-wm-user) ' ｜ 本页为【真实平台数据】—— 与正式环境等价，请谨慎操作';
  background: var(--sbx-real);
}
