/* 站点主题:色彩组合 + 排版 + 按钮/链接,以及 **Odoo 片段基座**
 * (间距/字号/网格/背景图那批『模板用了、却从没被定义过』的工具类,见文件下半)。
 *
 * 这里只有**固定规则**,全部以 var(--...) 表达;变量值由 /website/theme.css
 * 动态下发(编辑器画布则由 applyThemeToDoc 注入同名变量)。规则不随主题变,
 * 所以 Go 与 TS 两边都只拼变量值,没有可漂移的生成逻辑。
 *
 * 色彩组合 o_cc1~o_cc5 对标 Odoo:snippet 模板用 class 声明"这一块用哪套配色",
 * 226 处引用散落在 86 个片段里。映射由调色板 --o-color-1..5 推导:
 *   o_cc1 白底深字(最常用,113 处)   o_cc2 浅底深字
 *   o_cc3 主色底浅字                  o_cc4 辅色底浅字
 *   o_cc5 深底浅字(43 处)
 * 每套都完整定义 背景/正文/标题/链接/两种按钮——只定背景不定按钮,片段里的
 * 按钮会退回浏览器默认样式,深色底上直接看不见。
 */

/* ── 正文与排版 ───────────────────────────────────────────────────────── */
body {
  background-color: var(--o-body-bg);
  color: var(--o-body-color);
  font-family: var(--o-font-family);
  /* 字号尺度落在 <html> 上(见下面"全站字号尺度"):写在 body 只放大正文,
     标题与间距用的 rem 一动不动。这里跟随根字号即可。 */
  font-size: 1rem;
}

h1, h2, h3, h4, h5, h6 {
  font-family: var(--o-headings-font-family);
  font-weight: var(--o-headings-font-weight);
  color: inherit;
}

a {
  color: var(--o-link-color);
  text-decoration: var(--o-link-decoration);
}
a:hover {
  text-decoration: var(--o-link-hover-decoration);
}

/* ── 按钮基线 ─────────────────────────────────────────────────────────── */
.btn {
  border-radius: var(--o-btn-radius);
  border-width: var(--o-btn-border-width);
  padding: var(--o-btn-padding-y) var(--o-btn-padding-x);
}

/* 只放一个图标的圆按钮。
   `rounded-circle` 是 `border-radius: 50%`——**元素不是正方形，画出来就是椭圆**。
   页头那颗搜索放大镜实测 50×42（宽由图标 `.fa-stack` 的 2em 决定，高由 `lh-1`
   的行盒决定，两者从来就不相等），页脚的「回到顶部」同理：宽是 `.btn` 的
   padding-x、高是 padding-y，主题里这两个值本来就不一样。
   靠 `aspect-ratio` 也不行——宽高都是 auto 时它只会把高拉到内容宽，按钮跟着长个儿。
   所以直接定死尺寸，图标居中。 */
.o_btn_icon_round {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0 !important;
  line-height: 1;
}

.btn-primary {
  background-color: var(--o-color-1);
  border-color: var(--o-color-1);
  color: var(--o-color-4);
}
.btn-primary:hover {
  filter: brightness(0.92);
  color: var(--o-color-4);
}

.btn-secondary {
  background-color: var(--o-color-2);
  border-color: var(--o-color-2);
  color: var(--o-color-4);
}
.btn-secondary:hover {
  filter: brightness(0.92);
  color: var(--o-color-4);
}

.btn-outline-primary {
  background-color: transparent;
  border-color: var(--o-color-1);
  color: var(--o-color-1);
}
.btn-outline-primary:hover {
  background-color: var(--o-color-1);
  color: var(--o-color-4);
}

/* ── 色彩组合 ─────────────────────────────────────────────────────────── */
/* o_cc1~o_cc5 是片段模板里声明"这一块用哪套配色"的类(226 处引用,散落在 86 个
   片段)。每套的**具体色值**不在这里——由 /website/theme.css 按站点选中的调色板
   下发 --o-ccN-*(44 套 Odoo 内置调色板,见 internal/theme/palettes_gen.go)。

   ★ 为什么不是从 --o-color-1..5 就地推导(这里原来的做法):Odoo 的色彩组合有两层
   语义,推导只能表达第一层。
   ① 缺省映射(cc1 白底、cc2 浅底、cc3 辅色底、cc4 主色底、cc5 深底);
   ② **单套调色板对某个槽位的定点覆盖**——例如 default-1 的主色与深色底对比不足,
      Odoo 在编译期把它的 cc4/cc5 按钮改用 o-color-4、正文改用 o-color-3。44 套里
      有 20 套带这类覆盖。就地推导会把它们统统抹平,表现为"个别主题的深色块上按钮
      看不见",而其余主题完全正常——没人会怀疑到推导公式头上。
   还有一层:正文色与按钮文字色在 Odoo 那边是过 WCAG 对比度择优算出来的(黑还是白),
   不是固定取 o-color-4。这同样只能在生成期算,CSS 里表达不了。

   所以这里只做"槽位 → 变量"的转接,值全部来自调色板。var() 的第二参数是兜底:
   万一某套调色板缺了某个键(生成器有测试守着,理论上不会),退回原来的推导,
   至少不会出现"背景色没定义"这种整块透明的场面。 */
/* 裸 `o_cc`(不带编号)是"这一块参与色彩组合"的记号,基座模板的页脚就是这么写的。
   它自己不带任何槽位值,于是下面那条 `background-color: var(--o-cc-bg)` 在计算期
   无效、整条声明作废。给它一份等同组合 1 的兜底。
   ★ 必须排在 .o_cc1 之前:特异度相同,后来者取胜 —— 放在后面会把编号组合全盖掉。 */
.o_cc {
  --o-cc-bg: var(--o-cc1-bg, var(--o-color-4));
  --o-cc-text: var(--o-cc1-text, var(--o-body-color));
  --o-cc-headings: var(--o-cc-text);
  --o-cc-h2: var(--o-cc-headings);
  --o-cc-h3: var(--o-cc-headings);
  --o-cc-h4: var(--o-cc-headings);
  --o-cc-h5: var(--o-cc-headings);
  --o-cc-h6: var(--o-cc-headings);
  --o-cc-link: var(--o-cc1-link, var(--o-color-1));
  --o-cc-btn-primary-bg: var(--o-cc1-btn-primary, var(--o-color-1));
  --o-cc-btn-primary-border: var(--o-cc-btn-primary-bg);
  --o-cc-btn-primary-text: var(--o-cc1-btn-primary-text, var(--o-color-4));
  --o-cc-btn-secondary-bg: var(--o-cc1-btn-secondary, var(--o-color-2));
  --o-cc-btn-secondary-border: var(--o-cc-btn-secondary-bg);
  --o-cc-btn-secondary-text: var(--o-cc1-btn-secondary-text, var(--o-color-4));
}

.o_cc1 {
  --o-cc-bg: var(--o-cc1-bg, var(--o-color-4));
  --o-cc-text: var(--o-cc1-text, var(--o-body-color));
  --o-cc-headings: var(--o-cc1-headings, var(--o-cc-text));
  --o-cc-h2: var(--o-cc1-h2, var(--o-cc-headings));
  --o-cc-h3: var(--o-cc1-h3, var(--o-cc-headings));
  --o-cc-h4: var(--o-cc1-h4, var(--o-cc-headings));
  --o-cc-h5: var(--o-cc1-h5, var(--o-cc-headings));
  --o-cc-h6: var(--o-cc1-h6, var(--o-cc-headings));
  --o-cc-link: var(--o-cc1-link, var(--o-color-1));
  --o-cc-btn-primary-bg: var(--o-cc1-btn-primary, var(--o-color-1));
  --o-cc-btn-primary-border: var(--o-cc1-btn-primary-border, var(--o-cc-btn-primary-bg));
  --o-cc-btn-primary-text: var(--o-cc1-btn-primary-text, var(--o-color-4));
  --o-cc-btn-secondary-bg: var(--o-cc1-btn-secondary, var(--o-color-2));
  --o-cc-btn-secondary-border: var(--o-cc1-btn-secondary-border, var(--o-cc-btn-secondary-bg));
  --o-cc-btn-secondary-text: var(--o-cc1-btn-secondary-text, var(--o-color-4));
}

.o_cc2 {
  --o-cc-bg: var(--o-cc2-bg, var(--o-color-3));
  --o-cc-text: var(--o-cc2-text, var(--o-body-color));
  --o-cc-headings: var(--o-cc2-headings, var(--o-cc-text));
  --o-cc-h2: var(--o-cc2-h2, var(--o-cc-headings));
  --o-cc-h3: var(--o-cc2-h3, var(--o-cc-headings));
  --o-cc-h4: var(--o-cc2-h4, var(--o-cc-headings));
  --o-cc-h5: var(--o-cc2-h5, var(--o-cc-headings));
  --o-cc-h6: var(--o-cc2-h6, var(--o-cc-headings));
  --o-cc-link: var(--o-cc2-link, var(--o-color-1));
  --o-cc-btn-primary-bg: var(--o-cc2-btn-primary, var(--o-color-1));
  --o-cc-btn-primary-border: var(--o-cc2-btn-primary-border, var(--o-cc-btn-primary-bg));
  --o-cc-btn-primary-text: var(--o-cc2-btn-primary-text, var(--o-color-4));
  --o-cc-btn-secondary-bg: var(--o-cc2-btn-secondary, var(--o-color-2));
  --o-cc-btn-secondary-border: var(--o-cc2-btn-secondary-border, var(--o-cc-btn-secondary-bg));
  --o-cc-btn-secondary-text: var(--o-cc2-btn-secondary-text, var(--o-color-4));
}

.o_cc3 {
  --o-cc-bg: var(--o-cc3-bg, var(--o-color-2));
  --o-cc-text: var(--o-cc3-text, var(--o-color-4));
  --o-cc-headings: var(--o-cc3-headings, var(--o-cc-text));
  --o-cc-h2: var(--o-cc3-h2, var(--o-cc-headings));
  --o-cc-h3: var(--o-cc3-h3, var(--o-cc-headings));
  --o-cc-h4: var(--o-cc3-h4, var(--o-cc-headings));
  --o-cc-h5: var(--o-cc3-h5, var(--o-cc-headings));
  --o-cc-h6: var(--o-cc3-h6, var(--o-cc-headings));
  --o-cc-link: var(--o-cc3-link, var(--o-color-1));
  --o-cc-btn-primary-bg: var(--o-cc3-btn-primary, var(--o-color-1));
  --o-cc-btn-primary-border: var(--o-cc3-btn-primary-border, var(--o-cc-btn-primary-bg));
  --o-cc-btn-primary-text: var(--o-cc3-btn-primary-text, var(--o-color-4));
  --o-cc-btn-secondary-bg: var(--o-cc3-btn-secondary, var(--o-color-3));
  --o-cc-btn-secondary-border: var(--o-cc3-btn-secondary-border, var(--o-cc-btn-secondary-bg));
  --o-cc-btn-secondary-text: var(--o-cc3-btn-secondary-text, var(--o-color-5));
}

.o_cc4 {
  --o-cc-bg: var(--o-cc4-bg, var(--o-color-1));
  --o-cc-text: var(--o-cc4-text, var(--o-color-4));
  --o-cc-headings: var(--o-cc4-headings, var(--o-cc-text));
  --o-cc-h2: var(--o-cc4-h2, var(--o-cc-headings));
  --o-cc-h3: var(--o-cc4-h3, var(--o-cc-headings));
  --o-cc-h4: var(--o-cc4-h4, var(--o-cc-headings));
  --o-cc-h5: var(--o-cc4-h5, var(--o-cc-headings));
  --o-cc-h6: var(--o-cc4-h6, var(--o-cc-headings));
  --o-cc-link: var(--o-cc4-link, var(--o-color-5));
  --o-cc-btn-primary-bg: var(--o-cc4-btn-primary, var(--o-color-5));
  --o-cc-btn-primary-border: var(--o-cc4-btn-primary-border, var(--o-cc-btn-primary-bg));
  --o-cc-btn-primary-text: var(--o-cc4-btn-primary-text, var(--o-color-4));
  --o-cc-btn-secondary-bg: var(--o-cc4-btn-secondary, var(--o-color-3));
  --o-cc-btn-secondary-border: var(--o-cc4-btn-secondary-border, var(--o-cc-btn-secondary-bg));
  --o-cc-btn-secondary-text: var(--o-cc4-btn-secondary-text, var(--o-color-5));
}

.o_cc5 {
  --o-cc-bg: var(--o-cc5-bg, var(--o-color-5));
  --o-cc-text: var(--o-cc5-text, var(--o-color-4));
  --o-cc-headings: var(--o-cc5-headings, var(--o-color-4));
  --o-cc-h2: var(--o-cc5-h2, var(--o-cc-headings));
  --o-cc-h3: var(--o-cc5-h3, var(--o-cc-headings));
  --o-cc-h4: var(--o-cc5-h4, var(--o-cc-headings));
  --o-cc-h5: var(--o-cc5-h5, var(--o-cc-headings));
  --o-cc-h6: var(--o-cc5-h6, var(--o-cc-headings));
  --o-cc-link: var(--o-cc5-link, var(--o-color-1));
  --o-cc-btn-primary-bg: var(--o-cc5-btn-primary, var(--o-color-1));
  --o-cc-btn-primary-border: var(--o-cc5-btn-primary-border, var(--o-cc-btn-primary-bg));
  --o-cc-btn-primary-text: var(--o-cc5-btn-primary-text, var(--o-color-4));
  --o-cc-btn-secondary-bg: var(--o-cc5-btn-secondary, var(--o-color-3));
  --o-cc-btn-secondary-border: var(--o-cc5-btn-secondary-border, var(--o-cc-btn-secondary-bg));
  --o-cc-btn-secondary-text: var(--o-cc5-btn-secondary-text, var(--o-color-5));
}

/* 片段模板里 o_cc1~o_cc5 常常不带基类 o_cc(Odoo 用 SCSS 展开),
   这里补上等价声明,免得改动 226 处模板。 */
.o_cc, .o_cc1, .o_cc2, .o_cc3, .o_cc4, .o_cc5 {
  background-color: var(--o-cc-bg);
  color: var(--o-cc-text);
}
.o_cc h1, .o_cc1 h1, .o_cc2 h1, .o_cc3 h1, .o_cc4 h1, .o_cc5 h1 { color: var(--o-cc-headings); }
.o_cc h2, .o_cc1 h2, .o_cc2 h2, .o_cc3 h2, .o_cc4 h2, .o_cc5 h2 { color: var(--o-cc-h2); }
.o_cc h3, .o_cc1 h3, .o_cc2 h3, .o_cc3 h3, .o_cc4 h3, .o_cc5 h3 { color: var(--o-cc-h3); }
.o_cc h4, .o_cc1 h4, .o_cc2 h4, .o_cc3 h4, .o_cc4 h4, .o_cc5 h4 { color: var(--o-cc-h4); }
.o_cc h5, .o_cc1 h5, .o_cc2 h5, .o_cc3 h5, .o_cc4 h5, .o_cc5 h5 { color: var(--o-cc-h5); }
.o_cc h6, .o_cc1 h6, .o_cc2 h6, .o_cc3 h6, .o_cc4 h6, .o_cc5 h6 { color: var(--o-cc-h6); }
.o_cc a:not(.btn), .o_cc1 a:not(.btn), .o_cc2 a:not(.btn), .o_cc3 a:not(.btn),
.o_cc4 a:not(.btn), .o_cc5 a:not(.btn) {
  color: var(--o-cc-link);
}
.o_cc .btn-primary, .o_cc1 .btn-primary, .o_cc2 .btn-primary, .o_cc3 .btn-primary,
.o_cc4 .btn-primary, .o_cc5 .btn-primary {
  background-color: var(--o-cc-btn-primary-bg);
  border-color: var(--o-cc-btn-primary-border);
  color: var(--o-cc-btn-primary-text);
}
.o_cc .btn-secondary, .o_cc1 .btn-secondary, .o_cc2 .btn-secondary, .o_cc3 .btn-secondary,
.o_cc4 .btn-secondary, .o_cc5 .btn-secondary {
  background-color: var(--o-cc-btn-secondary-bg);
  border-color: var(--o-cc-btn-secondary-border);
  color: var(--o-cc-btn-secondary-text);
}


/* ═════════════════════════════════════════════════════════════════════════
   Odoo 片段基座 —— 模板里用了、却从来没有人定义过的那批类。

   片段模板是从 Odoo 19 逐份移植的,而 Odoo 的这批工具类是 **SCSS 编译期生成**
   的(@each/@for 循环出 pt0…pt256、hN-fs、bg-o-color-N …),在 .scss 源码里根本
   不长成规则的样子 —— tools/build_snippet_css.py 编 s_*.scss 时一条也没带出来。

   症状不是报错,是**没有间距、没有字号层级、没有底色**:每个块紧贴上一个块
   (`pt64 pb64` 无效),`<h2 class="h3-fs">` 按 h2 出,`s_number display-1-fs`
   的大数字跟正文一样大,`bg-o-color-1` 的图标圈是透明的,主题首页的封面图
   (`oe_img_bg`)干脆不显示。没有任何一处会报错,所以从来没人往这儿查。

   清点(2026-08-19,扫 modules/*/view/**.xml 的 class 属性,与本目录全部 css
   的选择器对账):间距类 805 处、字号类 318 处、网格摆放 ~500 处、
   调色板类 71 处、背景图/滤镜 ~110 处。

   ★ 这几段与上半部分的分工:上半是"主题变量 → 规则",这里是"Odoo 的编译期产物
   → 规则"。两者放同一份文件是因为**它们必须一起到达**:基座缺席时主题变量再准
   也看不出来(间距为 0 的页面换什么调色板都一样难看),而基座里的字号/间距本身
   又要能被主题缩放(--o-headings-scale / --o-spacing-scale)。
   ═════════════════════════════════════════════════════════════════════════ */

/* ── 字号层级 ─────────────────────────────────────────────────────────────
   `hN-fs` / `display-N-fs` 是 Odoo 的"只改字号、不改语义"类:`<h2 class="h3-fs">`
   要的是 h2 的语义 + h3 的大小。值与 Bootstrap 5.3 的标题一致(含 RFS 流体字号:
   1200px 以下按 vw 插值),乘以 --o-headings-scale 让主题能整体放大/收紧标题。

   带 !important:片段自带样式里有 `.s_xxx h2{font-size:…}` 这类 (0,1,1) 的规则,
   不加就赢不了它 —— Odoo 那边这批类也是经 utilities API 生成的,同样带 important。 */
h1 { font-size: calc((1.375rem + 1.5vw) * var(--o-headings-scale, 1)); }
h2 { font-size: calc((1.325rem + 0.9vw) * var(--o-headings-scale, 1)); }
h3 { font-size: calc((1.3rem + 0.6vw) * var(--o-headings-scale, 1)); }
h4 { font-size: calc((1.275rem + 0.3vw) * var(--o-headings-scale, 1)); }
h5 { font-size: calc(1.25rem * var(--o-headings-scale, 1)); }
h6 { font-size: calc(1rem * var(--o-headings-scale, 1)); }
@media (min-width: 1200px) {
  h1 { font-size: calc(2.5rem * var(--o-headings-scale, 1)); }
  h2 { font-size: calc(2rem * var(--o-headings-scale, 1)); }
  h3 { font-size: calc(1.75rem * var(--o-headings-scale, 1)); }
  h4 { font-size: calc(1.5rem * var(--o-headings-scale, 1)); }
}

.h1-fs { font-size: calc((1.375rem + 1.5vw) * var(--o-headings-scale, 1)) !important; }
.h2-fs { font-size: calc((1.325rem + 0.9vw) * var(--o-headings-scale, 1)) !important; }
.h3-fs { font-size: calc((1.3rem + 0.6vw) * var(--o-headings-scale, 1)) !important; }
.h4-fs { font-size: calc((1.275rem + 0.3vw) * var(--o-headings-scale, 1)) !important; }
.h5-fs { font-size: calc(1.25rem * var(--o-headings-scale, 1)) !important; }
.h6-fs { font-size: calc(1rem * var(--o-headings-scale, 1)) !important; }
@media (min-width: 1200px) {
  .h1-fs { font-size: calc(2.5rem * var(--o-headings-scale, 1)) !important; }
  .h2-fs { font-size: calc(2rem * var(--o-headings-scale, 1)) !important; }
  .h3-fs { font-size: calc(1.75rem * var(--o-headings-scale, 1)) !important; }
  .h4-fs { font-size: calc(1.5rem * var(--o-headings-scale, 1)) !important; }
}

.display-1-fs { font-size: calc((1.625rem + 4.5vw) * var(--o-headings-scale, 1)) !important; }
.display-2-fs { font-size: calc((1.575rem + 3.9vw) * var(--o-headings-scale, 1)) !important; }
.display-3-fs { font-size: calc((1.525rem + 3.3vw) * var(--o-headings-scale, 1)) !important; }
.display-4-fs { font-size: calc((1.475rem + 2.7vw) * var(--o-headings-scale, 1)) !important; }
.display-5-fs { font-size: calc((1.425rem + 2.1vw) * var(--o-headings-scale, 1)) !important; }
.display-6-fs { font-size: calc((1.375rem + 1.5vw) * var(--o-headings-scale, 1)) !important; }
@media (min-width: 1200px) {
  .display-1-fs { font-size: calc(5rem * var(--o-headings-scale, 1)) !important; }
  .display-2-fs { font-size: calc(4.5rem * var(--o-headings-scale, 1)) !important; }
  .display-3-fs { font-size: calc(4rem * var(--o-headings-scale, 1)) !important; }
  .display-4-fs { font-size: calc(3.5rem * var(--o-headings-scale, 1)) !important; }
  .display-5-fs { font-size: calc(3rem * var(--o-headings-scale, 1)) !important; }
  .display-6-fs { font-size: calc(2.5rem * var(--o-headings-scale, 1)) !important; }
}

.base-fs { font-size: 1rem !important; }
.o_small-fs, .o_small { font-size: 0.875rem !important; }

/* ── 调色板直取 ───────────────────────────────────────────────────────────
   `bg-o-color-1` 这类是"我就要调色板的第 N 号色",与色彩组合(o_ccN)无关 ——
   片段里的图标圈、装饰条、强调字用它。71 处引用,此前全是透明/继承色。 */
.bg-o-color-1 { background-color: var(--o-color-1) !important; }
.bg-o-color-2 { background-color: var(--o-color-2) !important; }
.bg-o-color-3 { background-color: var(--o-color-3) !important; }
.bg-o-color-4 { background-color: var(--o-color-4) !important; }
.bg-o-color-5 { background-color: var(--o-color-5) !important; }
.text-o-color-1 { color: var(--o-color-1) !important; }
.text-o-color-2 { color: var(--o-color-2) !important; }
.text-o-color-3 { color: var(--o-color-3) !important; }
.text-o-color-4 { color: var(--o-color-4) !important; }
.text-o-color-5 { color: var(--o-color-5) !important; }
.border-o-color-1 { border-color: var(--o-color-1) !important; }
.border-o-color-2 { border-color: var(--o-color-2) !important; }
.border-o-color-3 { border-color: var(--o-color-3) !important; }
.border-o-color-4 { border-color: var(--o-color-4) !important; }
.border-o-color-5 { border-color: var(--o-color-5) !important; }

/* ── 背景图与滤镜 ─────────────────────────────────────────────────────────
   封面/视差块的结构是三层:`.oe_img_bg` 铺图 → `.o_we_bg_filter` 盖一层半透明
   → 容器放文字。缺 oe_img_bg 的 cover/no-repeat 时,`background-image` 只会在
   左上角平铺原始尺寸;缺 o_we_bg_filter 的绝对定位时,那层滤镜变成文档流里一个
   0 高度的 div,深色底上的白字直接压在照片上看不清。 */
.oe_img_bg {
  background-size: cover;
  background-repeat: no-repeat;
  background-position: center;
}
.o_bg_img_center { background-position: center center !important; }
.o_we_bg_filter {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.bg-black-25 { background-color: rgba(0, 0, 0, .25) !important; }
.bg-black-50 { background-color: rgba(0, 0, 0, .5) !important; }
.bg-black-75 { background-color: rgba(0, 0, 0, .75) !important; }
.bg-white-25 { background-color: rgba(255, 255, 255, .25) !important; }
.bg-white-50 { background-color: rgba(255, 255, 255, .5) !important; }
.bg-white-75 { background-color: rgba(255, 255, 255, .75) !important; }

/* 视差层。`.parallax` 是"这一块有视差背景"的标记,图铺在内层的
   `<span class="s_parallax_bg oe_img_bg">` 上,所以本体必须是定位面 —— 缺了它,
   inset:0 相对整页解算,那张封面图会盖满全屏。`s_parallax_no_overflow_hidden`
   是片段自己声明的例外(形状装饰要溢出到块外)。 */
.parallax { position: relative; overflow: hidden; }
.s_parallax_no_overflow_hidden { overflow: visible; }
.s_parallax_bg {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}
/* `is_fixed` 的语义是"滚动时背景不动"。运行时(website_runtime.js 的 parallax)
   对 ratio=1 算出的位移恰好是 0,所以这里不必再写 background-attachment ——
   写了反而在 iOS 上失效并触发一次重绘。 */

/* 滤镜层与封面块同理:滤镜是 inset:0 的绝对定位,父级不定位就盖满全屏。
   `:has()` 兜住那些没有 .parallax 标记却带滤镜层的块(浏览器不认 :has 时
   只是回到现状,不会让整段样式失效 —— 无法解析的选择器只丢弃它自己那条)。 */
.s_cover { position: relative; }
section:has(> .o_we_bg_filter) { position: relative; }

/* ── 网格摆放(o_grid_mode)─────────────────────────────────────────────────
   Odoo 19 的新片段用**绝对网格**排版:行是 `.row.o_grid_mode`,子项 `.o_grid_item`
   自带内联 `grid-area: 行起 / 列起 / 行止 / 列止`。缺这条容器规则时 `grid-area`
   落在一个 flex 容器上被完全忽略 —— 块不会散架(子项还留着 col-lg-N 兜底),但
   重叠、错位、跨行这些"看起来最像 2025 年网站"的版式统统退化成普通栅格,
   而这正是新片段与老片段唯一的区别。

   与建站器自己那套 `.o_we_grid` 是两码事:那是新拖进去的块在画布里的网格
   (grid.css),这是**模板自带**的网格。两边行高都取 Odoo 的 50px。 */
@media (min-width: 992px) {
  .row.o_grid_mode {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    grid-auto-rows: 50px;
    row-gap: 0 !important;
    column-gap: 0 !important;
    --bs-gutter-x: 0;
    --bs-gutter-y: 0;
  }
  .row.o_grid_mode > .o_grid_item {
    /* col-* 的 "flex:0 0 auto;width:25%" 在网格里会把子项缩成格子的 1/4 */
    width: 100% !important;
    max-width: none !important;
    margin: 0 !important;
    float: none !important;
    min-width: 0;
    padding: var(--grid-item-padding-y, 10px) var(--grid-item-padding-x, 10px);
  }
  /* 跨列/跨行的**声明式**写法。模板里那 197 个格子全都自带内联 grid-area,
     所以这两组类眼下决定不了任何版式 —— 定义它们是为了建站器:用户在画布里
     新拖一个格子时写出来的就是这两组类,没有规则的话新格子恒占 1×1。 */
  .g-col-lg-1 { grid-column: span 1; }
  .g-col-lg-2 { grid-column: span 2; }
  .g-col-lg-3 { grid-column: span 3; }
  .g-col-lg-4 { grid-column: span 4; }
  .g-col-lg-5 { grid-column: span 5; }
  .g-col-lg-6 { grid-column: span 6; }
  .g-col-lg-7 { grid-column: span 7; }
  .g-col-lg-8 { grid-column: span 8; }
  .g-col-lg-9 { grid-column: span 9; }
  .g-col-lg-10 { grid-column: span 10; }
  .g-col-lg-11 { grid-column: span 11; }
  .g-col-lg-12 { grid-column: span 12; }
  .g-height-1 { grid-row: span 1; }
  .g-height-2 { grid-row: span 2; }
  .g-height-3 { grid-row: span 3; }
  .g-height-4 { grid-row: span 4; }
  .g-height-5 { grid-row: span 5; }
  .g-height-6 { grid-row: span 6; }
  .g-height-7 { grid-row: span 7; }
  .g-height-8 { grid-row: span 8; }
  .g-height-9 { grid-row: span 9; }
  .g-height-10 { grid-row: span 10; }
  .g-height-11 { grid-row: span 11; }
  .g-height-12 { grid-row: span 12; }
  .g-height-13 { grid-row: span 13; }
  .g-height-14 { grid-row: span 14; }
  .g-height-15 { grid-row: span 15; }
  .g-height-16 { grid-row: span 16; }
  .g-height-17 { grid-row: span 17; }
  .g-height-18 { grid-row: span 18; }
  .g-height-19 { grid-row: span 19; }
  .g-height-20 { grid-row: span 20; }
  .g-height-21 { grid-row: span 21; }
  .g-height-22 { grid-row: span 22; }
  .g-height-23 { grid-row: span 23; }
  .g-height-24 { grid-row: span 24; }
}

/* 图片格子:图片撑满自己那片格子并裁切,否则原始比例会把行高顶开 */
.o_grid_item_image { overflow: hidden; }
.o_grid_item_image > img,
.o_grid_item_image > a > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ── 色彩组合的嵌套与例外 ─────────────────────────────────────────────────
   `o_colored_level` 是 Odoo 给"里面还会再套一层配色"的容器的标记:它自己不定
   颜色,只是让子级的 o_ccN 覆盖在本层之上时不被本层的 background 挡住。
   `s_col_no_bgcolor` 反过来:这一列显式不要底色(整块有底色、其中一列要透出)。 */
.o_colored_level { background-color: transparent; }
.s_col_no_bgcolor { background-color: transparent !important; }

/* ── 社交链接块(s_social_media)───────────────────────────────────────────
   模板给的是 `<a class="s_social_media_facebook"><i class="fa fa-facebook
   rounded-circle shadow-sm"/></a>` —— 圆角类、阴影类都在,唯独**没有尺寸、没有
   底色**,于是那一排图标是几个裸字形挤在一起,`rounded-circle` 圈的是一个宽度
   等于字形的"圆"。页脚里几乎每套版式都有这一块。

   `no_icon_color` 是片段自己的开关:去掉品牌色、跟随本层文字色(深色页脚上
   一排品牌色方块会很吵)。 */
.s_social_media > a {
  display: inline-block;
  text-decoration: none;
}
.s_social_media .fa {
  width: 2em;
  height: 2em;
  line-height: 2em;
  text-align: center;
  font-size: 1.1em;
}
.s_social_media_title { margin-bottom: .5rem; }
/* 品牌色。`no_icon_color` 时整段不生效 —— 用 :not() 而不是再写一遍覆盖规则,
   免得"覆盖回什么颜色"又要猜一次(答案是 currentColor,也就是什么都不写)。 */
.s_social_media:not(.no_icon_color) .s_social_media_facebook .fa { background-color: #1877F2; color: #fff; }
.s_social_media:not(.no_icon_color) .s_social_media_twitter .fa { background-color: #000000; color: #fff; }
.s_social_media:not(.no_icon_color) .s_social_media_linkedin .fa { background-color: #0A66C2; color: #fff; }
.s_social_media:not(.no_icon_color) .s_social_media_instagram .fa { background-color: #E4405F; color: #fff; }
.s_social_media:not(.no_icon_color) .s_social_media_youtube .fa { background-color: #FF0000; color: #fff; }
.s_social_media:not(.no_icon_color) .s_social_media_github .fa { background-color: #181717; color: #fff; }
.s_social_media:not(.no_icon_color) .s_social_media_tiktok .fa { background-color: #000000; color: #fff; }
.s_social_media:not(.no_icon_color) .s_social_media_discord .fa { background-color: #5865F2; color: #fff; }

/* ── 引文(s_blockquote_quote)─────────────────────────────────────────────
   评价/引用类片段里那段引文。Odoo 给的是稍大一号、行高松一点的正文,不是斜体
   ——写成斜体的话中文引文会被浏览器合成假斜体,糊成一片。 */
.s_blockquote_quote {
  font-size: 1.125rem;
  line-height: 1.7;
}

/* ── 零碎工具类 ───────────────────────────────────────────────────────────
   都是 Odoo 用 utilities API 生成、模板里直接用的。逐个补,因为漏一个的症状
   就是那一个片段的某处布局不对,而它不会报错。 */
.w-0 { width: 0 !important; }
.h-0 { height: 0 !important; }
.z-index-1 { z-index: 1 !important; }
@media (min-width: 992px) {
  .w-lg-100 { width: 100% !important; }
  .position-lg-sticky { position: sticky !important; }
}
/* Odoo 的 .o_container_small —— 与 .container 同款、更窄的一档。
   模板里它与 container / container-fluid 三选一（页头「内容宽度」、片段的
   「内容宽度」都是这三档），而编译产物 snippets.css 里跟它同名的规则全是**片段内的
   辅助规则**（floating_blocks 的高度、image_gallery 的溢出），一条宽度都没有 ——
   于是选了「窄」跟没选一模一样，而且没有任何办法自证。
   断点值取 Bootstrap 的 md 档（720px），与 .container 在 lg 以上的 960/1140 拉开差距。 */
.o_container_small {
  width: 100%;
  max-width: 720px;
  padding-right: calc(var(--bs-gutter-x, 1.5rem) * .5);
  padding-left: calc(var(--bs-gutter-x, 1.5rem) * .5);
  margin-right: auto;
  margin-left: auto;
}

/* 数字块:字号已由 display-N-fs 给出,这里只收紧行高 —— 三个数字并排时
   行高不一致会让它们的基线错开半行。 */
.s_number { display: inline-block; line-height: 1.1; }

/* 时间线的圆点与竖线。尺寸变量 --o-timeline-dot-size / --o-dot-left /
   --o-dot-line-left 由 snippets.css 的 .s_timeline_list 给出(那份是编出来的),
   消费它们的 .o_dot / .o_dot_line 却没编出来 —— 于是圆点是个 0×0 的透明 span。 */
.s_timeline_list .o_dot {
  width: var(--o-timeline-dot-size, 24px);
  height: var(--o-timeline-dot-size, 24px);
  /* 兜底与 snippets.css 里 .s_timeline_list 的定义一致 —— 那份是编出来的,
     这份不能依赖它一定在(片段样式表按需裁剪时会漏)。 */
  left: var(--o-dot-left, calc(var(--o-timeline-dot-size, 24px) * 0.5));
  background-color: currentColor;
}
.s_timeline_list .o_dot_line {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--o-dot-line-left, calc(var(--o-timeline-dot-size, 24px) * 0.5));
  border-left: 1px solid currentColor;
  opacity: .35;
}

/* ═════════════════════════════════════════════════════════════════════════
   主题能改到的地方 —— 第二批。

   起因是"换主题看不出区别":此前主题能动的只有 5 个调色板色 + 页头/页脚版式,
   排版、圆角、按钮形状、页头页脚配色四样全是写死的,于是 7 套主题除了颜色之外
   长得一模一样。下面这几段把它们接到变量上。
   ═════════════════════════════════════════════════════════════════════════ */

/* ── Bootstrap 变量桥 ─────────────────────────────────────────────────────
   Bootstrap 5.3 自己的组件全部读 --bs-*(圆角、链接色、正文底色、移动抽屉…)。
   把 --o-* 接过去,一处映射就让 card / form-control / dropdown / offcanvas /
   list-group 这些**没被本文件逐个点名**的组件也跟着主题走 —— 逐个写选择器是
   写不完的,漏掉的那些表现为"整站换了主题,唯独表单控件还是老样子"。 */
:root {
  --bs-body-bg: var(--o-body-bg);
  --bs-body-color: var(--o-body-color);
  --bs-body-font-family: var(--o-font-family);
  --bs-heading-color: inherit;
  --bs-link-color: var(--o-link-color);
  --bs-link-hover-color: var(--o-link-color);
  --bs-border-radius: var(--o-radius);
  --bs-border-radius-sm: calc(var(--o-radius) * 0.75);
  --bs-border-radius-lg: calc(var(--o-radius) * 1.5);
  --bs-border-radius-xl: calc(var(--o-radius) * 2);
  --bs-border-radius-xxl: calc(var(--o-radius) * 3);
}

/* ── 全站字号尺度 ─────────────────────────────────────────────────────────
   ★ 落在 <html> 而不是 <body>:rem 是相对根元素算的,写在 body 上只放大正文,
   标题/间距/组件(它们全用 rem)纹丝不动 —— 表现为"字体大小这一项调了几乎没用"。

   ★ 默认值是 **100%** 而不是 16px:百分比相对浏览器的默认字号,把"我把浏览器
   字体调大了"这件事保留下来;写死 px 会把有阅读障碍的访客的设置直接吃掉。
   要绝对值时填 `18px` 也一样收下 —— 这一格是自由文本。 */
html { font-size: var(--o-font-size-base); }

/* ── 标题排版 ─────────────────────────────────────────────────────────── */
h1, h2, h3, h4, h5, h6 {
  letter-spacing: var(--o-headings-letter-spacing);
}

/* ── 按钮排版 ─────────────────────────────────────────────────────────────
   字重/大写/字距是按钮"性格"的全部 —— 圆角一样、颜色一样的两个按钮,一个
   `600 uppercase .08em` 一个 `400 none normal`,看起来完全是两个网站。 */
.btn {
  font-weight: var(--o-btn-font-weight);
  text-transform: var(--o-btn-text-transform);
  letter-spacing: var(--o-btn-letter-spacing);
}

/* ── 页头 ─────────────────────────────────────────────────────────────────
   基座模板把页头写成 `<header id="top" class="o_cc o_cc1">`,也就是**永远是
   色彩组合 1**。主题因此改不动页头配色,而页头是访客最先看到的一条。

   这里只接管 `o_cc1` 那一档:用户在建站器里把页头换成别的组合(o_cc3/o_cc5)时
   选择器不再匹配,组合本身生效 —— 主题给默认值,用户的显式选择仍然赢。

   --o-header-* 的出厂值由调色板的 MenuCC 推出(见 theme_css.go themeBaseVars),
   Odoo 那 44 套里有 6 套的页头不是组合 1。 */
#top.o_cc1 {
  --o-cc-bg: var(--o-header-bg);
  --o-cc-text: var(--o-header-color);
  --o-cc-headings: var(--o-header-color);
  --o-cc-h2: var(--o-header-color);
  --o-cc-h3: var(--o-header-color);
  --o-cc-h4: var(--o-header-color);
  --o-cc-h5: var(--o-header-color);
  --o-cc-h6: var(--o-header-color);
  --o-cc-link: var(--o-header-link);
}
/* 导航条自己走 --bs-navbar-*(bootstrap 5.3 的口径),不接上的话 `navbar-light`
   会把链接钉死成"深色文字",深色页头上等于看不见。 */
#top .navbar {
  --bs-navbar-color: var(--o-header-link);
  --bs-navbar-hover-color: var(--o-header-color);
  --bs-navbar-active-color: var(--o-header-color);
  --bs-navbar-brand-color: var(--o-header-color);
  --bs-navbar-brand-hover-color: var(--o-header-color);
  --bs-navbar-disabled-color: var(--o-header-link);
}

/* ── 页脚 ─────────────────────────────────────────────────────────────────
   基座模板给的是 `class="bg-light o_footer"` —— 一个写死的浅灰。换任何主题、
   任何调色板,页脚都是同一块 #f8f9fa,而页脚占了首屏之外最大的一片。

   `!important` 是必须的:bootstrap 的 `.bg-light` 自带 !important。

   ★ 排除条件必须逐个点名 o_cc1..o_cc5,**不能写成 `:not([class*="o_cc"])`** ——
   基座模板给页脚的实际类是 `bg-light o_footer o_colored_level o_cc`,带一个
   **裸 o_cc 标记**(它只是"这一块参与色彩组合"的记号,不指定第几套)。子串匹配
   把裸标记也算成"显式指定了组合",于是本规则从不匹配,页脚永远是那块 #f8f9fa。
   2026-08-19 真栈量出来的:--o-footer-bg 下发的是 #f6f5f4,渲染出来仍是 #f8f9fa。 */
footer#bottom.o_footer:not(.o_cc1):not(.o_cc2):not(.o_cc3):not(.o_cc4):not(.o_cc5) {
  background-color: var(--o-footer-bg) !important;
  color: var(--o-footer-color);
}
footer#bottom.o_footer:not(.o_cc1):not(.o_cc2):not(.o_cc3):not(.o_cc4):not(.o_cc5) h1,
footer#bottom.o_footer:not(.o_cc1):not(.o_cc2):not(.o_cc3):not(.o_cc4):not(.o_cc5) h2,
footer#bottom.o_footer:not(.o_cc1):not(.o_cc2):not(.o_cc3):not(.o_cc4):not(.o_cc5) h3,
footer#bottom.o_footer:not(.o_cc1):not(.o_cc2):not(.o_cc3):not(.o_cc4):not(.o_cc5) h4,
footer#bottom.o_footer:not(.o_cc1):not(.o_cc2):not(.o_cc3):not(.o_cc4):not(.o_cc5) h5,
footer#bottom.o_footer:not(.o_cc1):not(.o_cc2):not(.o_cc3):not(.o_cc4):not(.o_cc5) h6 { color: inherit; }
footer#bottom.o_footer:not(.o_cc1):not(.o_cc2):not(.o_cc3):not(.o_cc4):not(.o_cc5) a:not(.btn) { color: var(--o-footer-link); }
/* 深色页脚上的 .text-muted 是 bootstrap 的固定灰,几乎读不出来;改成"跟着本层
   文字色、淡一点",深浅两种页脚都成立。 */
footer#bottom.o_footer .text-muted { color: inherit !important; opacity: .7; }
/* 版权条:模板里有 .o_footer_copyright 而样式一直缺席,于是它和页脚正文糊成
   一片。一条细分隔线就够,颜色跟着本层文字走。 */
.o_footer_copyright {
  border-top: 1px solid currentColor;
  border-color: color-mix(in srgb, currentColor 18%, transparent);
  font-size: .875rem;
}

/* ── 间距工具类(pt/pb/mt/mb + 像素值)─────────────────────────────────────
   片段模板里 805 处引用,此前一条也没有定义 —— 每个块的上下留白全是 0,页面
   从头到尾一坨。这是"所有拖进来的块看起来都不对"里占比最大的一条。

   Odoo 那边是 SCSS 的 @for 循环生成(0、4,以及 8 到 256 每 8 一档),
   带 !important(经 utilities API 生成)。这里逐条列出,值与 Odoo 一致。

   ★ 乘 --o-spacing-scale:主题的"松紧"。默认 1 时与 Odoo 逐像素相同,
   0.85 是紧凑版式、1.25 是宽松版式 —— 同一批片段换个尺度就是另一个网站,
   而这一档不需要任何新片段、新模板。
   ★ pt0/pb0/mt0/mb0 不参与缩放:0 乘任何数还是 0,但写成 calc 会让"显式归零"
   这件事看起来像是可以被主题改掉的,而它不能。
   ★★ 倍率一律写 `var(--x, 1)` 而不是 `var(--x)`:变量表(/website/theme.css)没到
   的场合 —— 建站器的片段预览、离线兜底文档、那张表 404 —— 无兜底的 calc() 在
   计算期整条作废,间距变 0、字号回落到浏览器默认,**页面塌成一坨**。颜色变量缺了
   只是"颜色不对",倍率缺了是版面没了,不是一回事,所以只给这两个兜底。 */
.pt0{padding-top:0 !important}.pb0{padding-bottom:0 !important}.mt0{margin-top:0 !important}.mb0{margin-bottom:0 !important}
.pt4{padding-top:calc(4px * var(--o-spacing-scale, 1)) !important}.pb4{padding-bottom:calc(4px * var(--o-spacing-scale, 1)) !important}.mt4{margin-top:calc(4px * var(--o-spacing-scale, 1)) !important}.mb4{margin-bottom:calc(4px * var(--o-spacing-scale, 1)) !important}
.pt8{padding-top:calc(8px * var(--o-spacing-scale, 1)) !important}.pb8{padding-bottom:calc(8px * var(--o-spacing-scale, 1)) !important}.mt8{margin-top:calc(8px * var(--o-spacing-scale, 1)) !important}.mb8{margin-bottom:calc(8px * var(--o-spacing-scale, 1)) !important}
.pt16{padding-top:calc(16px * var(--o-spacing-scale, 1)) !important}.pb16{padding-bottom:calc(16px * var(--o-spacing-scale, 1)) !important}.mt16{margin-top:calc(16px * var(--o-spacing-scale, 1)) !important}.mb16{margin-bottom:calc(16px * var(--o-spacing-scale, 1)) !important}
.pt24{padding-top:calc(24px * var(--o-spacing-scale, 1)) !important}.pb24{padding-bottom:calc(24px * var(--o-spacing-scale, 1)) !important}.mt24{margin-top:calc(24px * var(--o-spacing-scale, 1)) !important}.mb24{margin-bottom:calc(24px * var(--o-spacing-scale, 1)) !important}
.pt32{padding-top:calc(32px * var(--o-spacing-scale, 1)) !important}.pb32{padding-bottom:calc(32px * var(--o-spacing-scale, 1)) !important}.mt32{margin-top:calc(32px * var(--o-spacing-scale, 1)) !important}.mb32{margin-bottom:calc(32px * var(--o-spacing-scale, 1)) !important}
.pt40{padding-top:calc(40px * var(--o-spacing-scale, 1)) !important}.pb40{padding-bottom:calc(40px * var(--o-spacing-scale, 1)) !important}.mt40{margin-top:calc(40px * var(--o-spacing-scale, 1)) !important}.mb40{margin-bottom:calc(40px * var(--o-spacing-scale, 1)) !important}
.pt48{padding-top:calc(48px * var(--o-spacing-scale, 1)) !important}.pb48{padding-bottom:calc(48px * var(--o-spacing-scale, 1)) !important}.mt48{margin-top:calc(48px * var(--o-spacing-scale, 1)) !important}.mb48{margin-bottom:calc(48px * var(--o-spacing-scale, 1)) !important}
.pt56{padding-top:calc(56px * var(--o-spacing-scale, 1)) !important}.pb56{padding-bottom:calc(56px * var(--o-spacing-scale, 1)) !important}.mt56{margin-top:calc(56px * var(--o-spacing-scale, 1)) !important}.mb56{margin-bottom:calc(56px * var(--o-spacing-scale, 1)) !important}
.pt64{padding-top:calc(64px * var(--o-spacing-scale, 1)) !important}.pb64{padding-bottom:calc(64px * var(--o-spacing-scale, 1)) !important}.mt64{margin-top:calc(64px * var(--o-spacing-scale, 1)) !important}.mb64{margin-bottom:calc(64px * var(--o-spacing-scale, 1)) !important}
.pt72{padding-top:calc(72px * var(--o-spacing-scale, 1)) !important}.pb72{padding-bottom:calc(72px * var(--o-spacing-scale, 1)) !important}.mt72{margin-top:calc(72px * var(--o-spacing-scale, 1)) !important}.mb72{margin-bottom:calc(72px * var(--o-spacing-scale, 1)) !important}
.pt80{padding-top:calc(80px * var(--o-spacing-scale, 1)) !important}.pb80{padding-bottom:calc(80px * var(--o-spacing-scale, 1)) !important}.mt80{margin-top:calc(80px * var(--o-spacing-scale, 1)) !important}.mb80{margin-bottom:calc(80px * var(--o-spacing-scale, 1)) !important}
.pt88{padding-top:calc(88px * var(--o-spacing-scale, 1)) !important}.pb88{padding-bottom:calc(88px * var(--o-spacing-scale, 1)) !important}.mt88{margin-top:calc(88px * var(--o-spacing-scale, 1)) !important}.mb88{margin-bottom:calc(88px * var(--o-spacing-scale, 1)) !important}
.pt96{padding-top:calc(96px * var(--o-spacing-scale, 1)) !important}.pb96{padding-bottom:calc(96px * var(--o-spacing-scale, 1)) !important}.mt96{margin-top:calc(96px * var(--o-spacing-scale, 1)) !important}.mb96{margin-bottom:calc(96px * var(--o-spacing-scale, 1)) !important}
.pt104{padding-top:calc(104px * var(--o-spacing-scale, 1)) !important}.pb104{padding-bottom:calc(104px * var(--o-spacing-scale, 1)) !important}.mt104{margin-top:calc(104px * var(--o-spacing-scale, 1)) !important}.mb104{margin-bottom:calc(104px * var(--o-spacing-scale, 1)) !important}
.pt112{padding-top:calc(112px * var(--o-spacing-scale, 1)) !important}.pb112{padding-bottom:calc(112px * var(--o-spacing-scale, 1)) !important}.mt112{margin-top:calc(112px * var(--o-spacing-scale, 1)) !important}.mb112{margin-bottom:calc(112px * var(--o-spacing-scale, 1)) !important}
.pt120{padding-top:calc(120px * var(--o-spacing-scale, 1)) !important}.pb120{padding-bottom:calc(120px * var(--o-spacing-scale, 1)) !important}.mt120{margin-top:calc(120px * var(--o-spacing-scale, 1)) !important}.mb120{margin-bottom:calc(120px * var(--o-spacing-scale, 1)) !important}
.pt128{padding-top:calc(128px * var(--o-spacing-scale, 1)) !important}.pb128{padding-bottom:calc(128px * var(--o-spacing-scale, 1)) !important}.mt128{margin-top:calc(128px * var(--o-spacing-scale, 1)) !important}.mb128{margin-bottom:calc(128px * var(--o-spacing-scale, 1)) !important}
.pt136{padding-top:calc(136px * var(--o-spacing-scale, 1)) !important}.pb136{padding-bottom:calc(136px * var(--o-spacing-scale, 1)) !important}.mt136{margin-top:calc(136px * var(--o-spacing-scale, 1)) !important}.mb136{margin-bottom:calc(136px * var(--o-spacing-scale, 1)) !important}
.pt144{padding-top:calc(144px * var(--o-spacing-scale, 1)) !important}.pb144{padding-bottom:calc(144px * var(--o-spacing-scale, 1)) !important}.mt144{margin-top:calc(144px * var(--o-spacing-scale, 1)) !important}.mb144{margin-bottom:calc(144px * var(--o-spacing-scale, 1)) !important}
.pt152{padding-top:calc(152px * var(--o-spacing-scale, 1)) !important}.pb152{padding-bottom:calc(152px * var(--o-spacing-scale, 1)) !important}.mt152{margin-top:calc(152px * var(--o-spacing-scale, 1)) !important}.mb152{margin-bottom:calc(152px * var(--o-spacing-scale, 1)) !important}
.pt160{padding-top:calc(160px * var(--o-spacing-scale, 1)) !important}.pb160{padding-bottom:calc(160px * var(--o-spacing-scale, 1)) !important}.mt160{margin-top:calc(160px * var(--o-spacing-scale, 1)) !important}.mb160{margin-bottom:calc(160px * var(--o-spacing-scale, 1)) !important}
.pt168{padding-top:calc(168px * var(--o-spacing-scale, 1)) !important}.pb168{padding-bottom:calc(168px * var(--o-spacing-scale, 1)) !important}.mt168{margin-top:calc(168px * var(--o-spacing-scale, 1)) !important}.mb168{margin-bottom:calc(168px * var(--o-spacing-scale, 1)) !important}
.pt176{padding-top:calc(176px * var(--o-spacing-scale, 1)) !important}.pb176{padding-bottom:calc(176px * var(--o-spacing-scale, 1)) !important}.mt176{margin-top:calc(176px * var(--o-spacing-scale, 1)) !important}.mb176{margin-bottom:calc(176px * var(--o-spacing-scale, 1)) !important}
.pt184{padding-top:calc(184px * var(--o-spacing-scale, 1)) !important}.pb184{padding-bottom:calc(184px * var(--o-spacing-scale, 1)) !important}.mt184{margin-top:calc(184px * var(--o-spacing-scale, 1)) !important}.mb184{margin-bottom:calc(184px * var(--o-spacing-scale, 1)) !important}
.pt192{padding-top:calc(192px * var(--o-spacing-scale, 1)) !important}.pb192{padding-bottom:calc(192px * var(--o-spacing-scale, 1)) !important}.mt192{margin-top:calc(192px * var(--o-spacing-scale, 1)) !important}.mb192{margin-bottom:calc(192px * var(--o-spacing-scale, 1)) !important}
.pt200{padding-top:calc(200px * var(--o-spacing-scale, 1)) !important}.pb200{padding-bottom:calc(200px * var(--o-spacing-scale, 1)) !important}.mt200{margin-top:calc(200px * var(--o-spacing-scale, 1)) !important}.mb200{margin-bottom:calc(200px * var(--o-spacing-scale, 1)) !important}
.pt208{padding-top:calc(208px * var(--o-spacing-scale, 1)) !important}.pb208{padding-bottom:calc(208px * var(--o-spacing-scale, 1)) !important}.mt208{margin-top:calc(208px * var(--o-spacing-scale, 1)) !important}.mb208{margin-bottom:calc(208px * var(--o-spacing-scale, 1)) !important}
.pt216{padding-top:calc(216px * var(--o-spacing-scale, 1)) !important}.pb216{padding-bottom:calc(216px * var(--o-spacing-scale, 1)) !important}.mt216{margin-top:calc(216px * var(--o-spacing-scale, 1)) !important}.mb216{margin-bottom:calc(216px * var(--o-spacing-scale, 1)) !important}
.pt224{padding-top:calc(224px * var(--o-spacing-scale, 1)) !important}.pb224{padding-bottom:calc(224px * var(--o-spacing-scale, 1)) !important}.mt224{margin-top:calc(224px * var(--o-spacing-scale, 1)) !important}.mb224{margin-bottom:calc(224px * var(--o-spacing-scale, 1)) !important}
.pt232{padding-top:calc(232px * var(--o-spacing-scale, 1)) !important}.pb232{padding-bottom:calc(232px * var(--o-spacing-scale, 1)) !important}.mt232{margin-top:calc(232px * var(--o-spacing-scale, 1)) !important}.mb232{margin-bottom:calc(232px * var(--o-spacing-scale, 1)) !important}
.pt240{padding-top:calc(240px * var(--o-spacing-scale, 1)) !important}.pb240{padding-bottom:calc(240px * var(--o-spacing-scale, 1)) !important}.mt240{margin-top:calc(240px * var(--o-spacing-scale, 1)) !important}.mb240{margin-bottom:calc(240px * var(--o-spacing-scale, 1)) !important}
.pt248{padding-top:calc(248px * var(--o-spacing-scale, 1)) !important}.pb248{padding-bottom:calc(248px * var(--o-spacing-scale, 1)) !important}.mt248{margin-top:calc(248px * var(--o-spacing-scale, 1)) !important}.mb248{margin-bottom:calc(248px * var(--o-spacing-scale, 1)) !important}
.pt256{padding-top:calc(256px * var(--o-spacing-scale, 1)) !important}.pb256{padding-bottom:calc(256px * var(--o-spacing-scale, 1)) !important}.mt256{margin-top:calc(256px * var(--o-spacing-scale, 1)) !important}.mb256{margin-bottom:calc(256px * var(--o-spacing-scale, 1)) !important}


/* ---------------------------------------------------------------------------
   自由放置的**定位面**（印章、角标、水印这类要压在别人身上的块）。

   ★★ 为什么这条规则必须在这里，而不是由建站器在客户端加：
   建站器存回的是可编辑区的 **innerHTML** —— 区域元素**自身不在里面**。客户端给
   区域加的 position:relative 一保存就丢，重渲后绝对定位改为相对整页解算，块跳到
   页顶（2026-08-08 报表那边真机实证过一次，网站这半当时没跟上）。

   ★ 前台也要，不只是编辑器：访客看到的位置必须和编辑时一样。建站器画布是
   srcdoc iframe，about:srcdoc 继承父页面 base URL，这份样式表在画布里同样生效，
   所以编辑态与访客态不可能对不上。

   ★ 只匹配显式带属性的那三处（模板里的 main / #header / #footer），**不要**写成
   通配的 [data-free-surface]：position:relative 会让该元素成为绝对定位的参照，
   给不相干的容器加上会把片段内部原本相对别处定位的装饰元素挪位。
   --------------------------------------------------------------------------- */
main[data-free-surface],
#header[data-free-surface],
#footer[data-free-surface] { position: relative; }
