/*
 * bubble-diver 主题。
 *
 * 两件事，分得很清楚：
 *
 * ① **令牌覆盖**（`--gs-*`）——换皮只动第一段，**绝不覆盖 `.gs-*` 选择器**。
 *    覆盖组件的选择器会把 44×44 触控下限、安全区、焦点环一起改坏，
 *    而这三样都不会在手机上被肉眼发现。
 * ② **本作自己的结构类**（`.bd-*`）——分区容器、洞窟舞台、氧气竖条、
 *    潜标网格、记录卡这些组件库里没有的形态。它们是新增，不是覆盖。
 *
 * 版式只有一套：手机竖屏。视口比手机宽时由共用库末尾的「手机画布锁定」
 * 把 `#app` 收成 540×960 居中，桌面玩到的就是手机上验收过的那一屏。
 * 所以本文件里**没有任何不带 `max-height` 的 `@media (min-width: …)`**。
 * 手机横屏那一档统一写成 `(orientation: landscape) and (max-height: 560px)`，
 * 560 这个数的唯一真值是 `shared/phone-canvas.json`。
 *
 * **分区的几何不在这里。** 每一屏的 `zones` 由 `game.config.json`（从
 * `art/SCREEN_SPEC.json` 机械同步）给出，`ui.mjs` 按百分比写成内联定位——
 * 把 16 屏 × 2 朝向的矩形手抄进 CSS 等于开第二处真相，抄错一个小数点
 * 运行时会照着做出一个越界的布局，而闸门验的是 SPEC 那一份，两边各自自洽。
 *
 * 配色取自 S2 冻结的 `shared_conventions.palette`（13 色）与 `cave_tints`：
 * 深色一侧（abyss / water-deep / ink）只做底，霓虹一侧只做**可操作或可得分的东西**
 * ——画面里会发光的，就是玩家能按的或能拿的；岩石与海胆一律留在 rock-* 的哑光区间。
 */

:root {
  /* ══════════ ① 令牌覆盖 ══════════ */
  --gs-ink: #e6fbff;                       /* foam */
  --gs-ink-soft: rgba(230, 251, 255, 0.74);
  --gs-ink-dim: rgba(190, 222, 236, 0.5);
  --gs-ink-on-light: #04121f;              /* abyss */

  --gs-surface: rgba(10, 42, 69, 0.9);     /* water-deep */
  /* 次级按钮与分段控件的底色。**必须够不透明**：半透明底压在满屏插画上时，
     未选中的那几段会变得几乎读不出来——而「读不出来的选项」等于没有这个选项。 */
  --gs-surface-raised: rgba(11, 52, 82, 0.97);  /* water-mid，压暗一档保对比度 */
  --gs-surface-sunken: rgba(5, 10, 20, 0.7);    /* ink */
  --gs-hairline: rgba(75, 242, 228, 0.34);      /* neon-cyan */

  --gs-accent: #4bf2e4;                    /* neon-cyan */
  --gs-accent-2: #16688f;                  /* water-near */
  --gs-gold: #ffc94a;                      /* pearl-gold */
  --gs-danger: #ff4d6a;                    /* alarm-red */

  --gs-glow-accent: 0 0 0 1px rgba(75, 242, 228, 0.55), 0 0 26px rgba(75, 242, 228, 0.32);
  --gs-glow-gold: 0 0 26px rgba(255, 201, 74, 0.5);
  --gs-shadow-card: 0 20px 44px rgba(4, 18, 31, 0.58);
  --gs-shadow-button: 0 6px 0 rgba(3, 12, 22, 0.44), 0 14px 26px rgba(4, 18, 31, 0.48);
  --gs-shadow-press: 0 2px 0 rgba(3, 12, 22, 0.44), 0 6px 12px rgba(4, 18, 31, 0.48);

  --gs-cta: linear-gradient(135deg, #4bf2e4, #3fe0a8 52%, #16688f);
  /* 四张 bg-*-far 的主体（光井 / 岩缝）都在中上部，正中取景会切掉它。 */
  --gs-bg-focus: 50% 38%;

  /* 底部安全区**至少留 24px**（平台基线「底部按钮不要贴到屏幕最下沿」）。
     没有刘海的机器上 `env(safe-area-inset-bottom)` 是 0，分区会一直贴到屏幕最下沿。
     只覆盖变量，不覆盖 `.gs-*` 选择器。 */
  --gs-safe-bottom: max(env(safe-area-inset-bottom, 0px), 24px);

  /* ══════════ 本作的绘图令牌：画布与 DOM 共用同一份来源 ══════════
     `render.mjs` 用 getComputedStyle 读它们，所以换洞窟只改一组变量，
     画布和 HUD 不会各说各话。13 个色名与 SCREEN_SPEC 的 palette 逐字对应。 */
  --bd-abyss: #04121f;
  --bd-water-deep: #0a2a45;
  --bd-water-mid: #0f4468;
  --bd-water-near: #16688f;
  --bd-foam: #e6fbff;
  --bd-neon-cyan: #4bf2e4;
  --bd-neon-magenta: #ff5fc4;
  --bd-neon-lime: #9cf56b;
  --bd-pearl-gold: #ffc94a;
  --bd-coral: #ff7a5c;
  --bd-rock-violet: #2b2447;
  --bd-rock-slate: #3a4a63;
  --bd-alarm-red: #ff4d6a;
  --bd-ink: #050a14;

  /* 当前洞窟的三个色（由 `ui.mjs` 在 `<html>` 上按 data-cave 切换，见下）。 */
  --bd-cave-water: #1b7f7a;
  --bd-cave-accent: #ff8a5b;
  --bd-cave-rim: #4bf2e4;

  /* 当前潜水服的两个色（纯外观，**不改任何数值与判定**）。 */
  --bd-skin: #ff7a5c;
  --bd-skin-rim: #ffc0ae;

  /* ══════════ 字号下限：SCREEN_SPEC 的 type_scale_min_css_px ══════════
     这是**最小值**。正文一律 ≥14 CSS px；`caption` 的 12 只给版本行这一类
     不影响游玩的信息。HUD 的四个数字用 num-sm 起跳——它们要在 360 CSS px 宽的
     画布上、在一条 16% 宽的竖条里读得出来。 */
  --bd-display-xl: 44px;
  --bd-display-lg: 38px;
  --bd-title-lg: 30px;
  --bd-title-md: 24px;
  --bd-title-sm: 19px;
  --bd-lead-lg: 20px;
  --bd-body-md: 16px;
  --bd-body-sm: 14px;
  --bd-caption: 12px;
  --bd-num-xl: 56px;
  --bd-num-gold-md: 26px;
  --bd-num-gold-sm: 15px;
  --bd-num-sm: 18px;
}

/* 四个洞窟的色调。切洞窟只换这三个变量，舞台与界面一起跟着变。 */
:root[data-cave='reef'] { --bd-cave-water: #1b7f7a; --bd-cave-accent: #ff8a5b; --bd-cave-rim: #4bf2e4; }
:root[data-cave='bluehole'] { --bd-cave-water: #123e86; --bd-cave-accent: #4bf2e4; --bd-cave-rim: #7fb4ff; }
:root[data-cave='rift'] { --bd-cave-water: #2c1b4a; --bd-cave-accent: #ff5fc4; --bd-cave-rim: #a97bff; }
:root[data-cave='undertow'] { --bd-cave-water: #07231d; --bd-cave-accent: #9cf56b; --bd-cave-rim: #3fe0a8; }

/* 五套潜水服。**只换色**，不提供任何数值奖励（§5.3）。 */
:root[data-skin='coral'] { --bd-skin: #ff7a5c; --bd-skin-rim: #ffc0ae; }
:root[data-skin='mint'] { --bd-skin: #6ff0c2; --bd-skin-rim: #d3fff0; }
:root[data-skin='violet'] { --bd-skin: #a97bff; --bd-skin-rim: #e0cdff; }
:root[data-skin='gold'] { --bd-skin: #ffc94a; --bd-skin-rim: #fff0c2; }
:root[data-skin='midnight'] { --bd-skin: #2b2447; --bd-skin-rim: #7fb4ff; }

/* 本作自己的元素一律 border-box。分区是按**百分比**定位的，内边距若算在宽度之外，
   一条 16% 宽的 HUD 会变成 16% + 16px——横竖两个方向都会挤到隔壁分区上去，
   而打包走查判的正是「分区互不压住」。 */
.bd-screen *,
.bd-screen *::before,
.bd-screen *::after { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  background: var(--bd-ink);
  color: var(--gs-ink);
  font-family: 'Avenir Next', 'Segoe UI', system-ui, -apple-system, sans-serif;
  /* 按住气泡不许被当成选择或放大（§10.6 风险表 / A39）。 */
  -webkit-text-size-adjust: 100%;
  overscroll-behavior: none;
}

/*
 * 手机画布的根容器。**`position: fixed; inset: 0` 是共用库那套锁定的前提**
 * （`ui.css` 末尾「手机画布锁定」逐字写着三份 theme.css 都把它钉成这个形状）：
 * 宽视口下它再用 `width: min(…, 540px)` + `margin: auto` 把画布收窄居中。
 * 这里写成 `position: relative` 的话 `#app` 高度会塌成 0，
 * 里面每一屏的 `inset: 0` 于是量出 390×0——页面不报错，就是什么都不显示。
 */
#app {
  position: fixed;
  inset: 0;
  overflow: hidden;
  background: radial-gradient(120% 90% at 50% 10%, var(--bd-water-mid) 0%, var(--bd-water-deep) 45%, var(--bd-abyss) 100%);
}

/* ══════════ 屏幕与分区 ══════════ */

.bd-screen {
  position: absolute;
  inset: 0;
  z-index: 1;
}

/* 浮层盖在场景之上；它自己的遮罩由 `.bd-scrim` 出，`trapFocus` 负责焦点与模态语义。 */
.bd-screen[data-kind='overlay'] { z-index: 3; }

.bd-scrim {
  position: absolute;
  inset: 0;
  background: rgba(4, 18, 31, 0.72);
  backdrop-filter: blur(6px);
}

/*
 * 分区层：`inset` 就是安全区，里面的每个分区按 `zones` 的 0~1 比例定位。
 * 百分比由 `ui.mjs` 写成内联样式（唯一真值在 SCREEN_SPEC），这里只给盒模型。
 */
.bd-zones {
  position: absolute;
  top: var(--gs-safe-top);
  right: var(--gs-safe-right);
  bottom: var(--gs-safe-bottom);
  left: var(--gs-safe-left);
}

.bd-zone {
  position: absolute;
  display: flex;
  flex-direction: column;
  /* 分区高度是**按比例定死的**，内容却按自己的大小排。默认贴顶排的话，
     一个只有 200px 内容的 340px 分区下面就空出 140px——十六屏加起来，
     整个游戏看上去就是「每一屏都空了一大块」。所以默认竖向居中。 */
  justify-content: safe center;
  gap: var(--gs-space-2);
  padding-inline: var(--gs-space-2);
  min-width: 0;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
}

/* 内容比分区高时分区内部自己滚，**绝不把主按钮挤出分区**。
   能滚的分区必须贴顶排：居中会让第一屏内容被滚动容器截掉上半截。 */
.bd-zone[data-scroll='y'] {
  overflow-y: auto;
  overflow-x: hidden;
  justify-content: flex-start;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
  overscroll-behavior: contain;
}

.bd-zone--center { align-items: center; text-align: center; }
.bd-zone--actions { justify-content: safe flex-end; gap: var(--gs-tap-gap); }
.bd-zone[data-zone-name='topbar'] { align-items: flex-end; }
.bd-loading-bubbles { position: absolute; inset: 0; pointer-events: none; }
.bd-loading-bubbles img { position: absolute; left: calc(12% + var(--i) * 8%); top: calc(61% - var(--i) * 4%); width: calc(70px - var(--i) * 8px); height: auto; }

/* 满屏插画背景。**每一屏都有一张**（`game.config.json.backgrounds`，从 SPEC 机械同步）：
   少了它，十六屏会一起退化成同一块通用深色面板——那正是上一款游戏翻车的样子。 */
.bd-bg {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;   /* 背景永远不吃点击 */
  z-index: 0;
}

.bd-bg__layer {
  position: absolute;
  inset: -4%;
  width: 108%;
  height: 108%;
  object-fit: cover;
  object-position: var(--gs-bg-focus, 50% 50%);
}

/* 压暗层：`dim` 由 SPEC 逐屏给，保证前景文字在任何插画上都读得清。 */
.bd-bg__scrim {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(4, 18, 31, 0.72) 0%, rgba(4, 18, 31, 0.18) 34%,
      rgba(4, 18, 31, 0.42) 70%, rgba(4, 18, 31, 0.86) 100%),
    rgba(4, 18, 31, var(--bd-dim, 0.4));
}

/* ══════════ 洞窟舞台（画布控件）══════════ */

/*
 * 洞窟舞台。**不在这里写 `position: absolute`**：游玩屏的舞台由 `mountZones`
 * 按分区比例写内联定位，而每日预览用的是同一个类、却是普通的块级子元素——
 * 给它绝对定位会让它收缩成「按内容定宽」，里面 `width: 100%` 的画布随之塌掉，
 * 预览就变成一块纯色渐变加一条线。
 */
.bd-stage {
  position: relative;
  /* 后果画在画布上：走查靠 DOM 指纹看不见画布，所以容器声明 data-canvas-driven。
     没有这一条，气泡热区会被报成假控件（PROJECT_DECISIONS §13）。 */
  touch-action: none;                    /* iOS 上按住不被当成选择/放大（A39） */
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  overflow: hidden;
  /* 舞台**齐着分区边缘**，不留圆角内缩：圆角会在四边露出一圈底色，
     看上去像洞窟被装在一个框里，而设计稿上它是满出血的。 */
  background: linear-gradient(180deg, var(--bd-cave-water) 0%, var(--bd-water-deep) 55%, var(--bd-abyss) 100%);
}

.bd-stage canvas {
  display: block;
  width: 100%;
  height: 100%;
  touch-action: none;
}

/*
 * 嵌在分区里的那种舞台（每日洞窟预览）。**必须给它一个真实高度**：
 * 它的画布是 `height: 100%`，而父元素高度若是 auto，这个百分比解析成 auto，
 * 画布退回默认的 300×150，于是预览要么塌掉、要么和容器对不齐。
 */
.bd-stage--inline {
  flex: 1 1 auto;
  width: 100%;
  min-height: 120px;
  border-radius: var(--gs-radius-md);
  box-shadow: inset 0 0 0 1px var(--gs-hairline);
}

/* ══════════ 氧气条：本作唯一一条会归零的进度条（§6.4）══════════ */

.bd-air {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--gs-space-1);
}

.bd-air__track {
  position: relative;
  flex: 1 1 auto;
  width: min(30px, 62%);
  min-height: 60px;
  border-radius: var(--gs-radius-pill);
  background: var(--gs-surface-sunken);
  box-shadow: inset 0 0 0 1px var(--gs-hairline);
  overflow: hidden;
}

/*
 * 氧气条的液面。比例走 CSS 变量 `--bd-air`，**不是由 JS 直接写 height**：
 * 竖屏它是高度、横屏它是宽度，同一句 `style.height = …` 在横屏下会留下一个
 * 空心外框——数值写着 100，条子里却什么都没有。
 */
.bd-air__fill {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: calc(var(--bd-air, 1) * 100%);
  background: linear-gradient(180deg, var(--bd-neon-cyan), var(--bd-water-near));
  transition: height var(--gs-fast) linear, width var(--gs-fast) linear;
}

/* 低氧：**颜色 + 脉冲 + 数字同色**三通道，不只靠颜色（辨色障碍玩家读不到）。 */
.bd-air[data-low='true'] .bd-air__fill {
  background: linear-gradient(180deg, var(--bd-alarm-red), #8e1d33);
  animation: bd-air-pulse 833ms ease-in-out infinite;   /* 1.2 Hz（§10.5） */
}
.bd-air[data-low='true'] .bd-air__value { color: var(--bd-alarm-red); }

.bd-air__value {
  font-size: var(--bd-num-sm);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--gs-ink);
}

.bd-air__label {
  font-size: var(--bd-caption);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gs-ink-dim);
}

@keyframes bd-air-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.55; }
}

/* 减少动态：去掉动，**留下读数与颜色**（§10.5 明令不许拿掉信息本身）。 */
:root[data-reduced-motion='on'] .bd-air[data-low='true'] .bd-air__fill { animation: none; }
@media (prefers-reduced-motion: reduce) {
  .bd-air[data-low='true'] .bd-air__fill { animation: none; }
}

/* ══════════ HUD 的图标数值行 ══════════ */

.bd-stats {
  display: flex;
  flex-direction: column;
  gap: var(--gs-space-2);
  align-items: center;
}

.bd-stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  line-height: 1.1;
}

.bd-stat__icon {
  width: 18px;
  height: 18px;
  filter: var(--gs-icon-tint-accent);
}

.bd-stat__value {
  font-size: var(--bd-num-sm);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

.bd-stat__label {
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--gs-ink-dim);
}

/* 暂停 / 恢复里的三条整宽读数行。 */
.bd-statlines { display: flex; flex-direction: column; gap: var(--gs-space-2); width: 100%; }
.bd-statline {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: var(--gs-space-3);
  width: 100%;
  padding: var(--gs-space-2) var(--gs-space-3);
  border-radius: var(--gs-radius-md);
  background: var(--gs-surface-sunken);
  box-shadow: inset 0 0 0 1px var(--gs-hairline);
}
.bd-statline__label { flex: 1 1 auto; font-size: var(--bd-body-md); color: var(--gs-ink-soft); }
.bd-statline__value {
  font-size: var(--bd-title-sm);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.bd-statline[data-role-kind='combo'] .bd-statline__value { color: var(--bd-neon-magenta); }

/* 连击是**数字 + 环形脉冲**，不是条——走到 0 不会让玩家输，做成条就会被误读（§6.4）。 */
.bd-stat[data-role-kind='combo'] .bd-stat__value { color: var(--bd-neon-magenta); }
.bd-stat[data-pulse='true'] .bd-stat__value { animation: bd-combo-pop 220ms var(--gs-ease-out); }

@keyframes bd-combo-pop {
  0% { transform: scale(1); }
  45% { transform: scale(1.2); }
  100% { transform: scale(1); }
}

:root[data-reduced-motion='on'] .bd-stat[data-pulse='true'] .bd-stat__value { animation: none; }
@media (prefers-reduced-motion: reduce) {
  .bd-stat[data-pulse='true'] .bd-stat__value { animation: none; }
}

/* 横屏：HUD 从左侧竖条变成顶部横条，氧气条跟着转 90°（screen-19 那张稿）。
   这一档是**手机的一个朝向**，不是桌面：出口高度 560px 的唯一真值在
   `shared/phone-canvas.json`，本文件里每一条 @media 都只用这一个数。 */
@media (orientation: landscape) and (max-height: 560px) {
  /* 竖屏时 hud 是左侧一条竖栏，横屏时它是顶部一条横栏——**同一套版式的两个朝向**，
     所以只翻转主轴，不新增任何组件、不改信息层级。 */
  .bd-zone[data-zone='hud'] {
    flex-direction: row;
    align-items: center;
    gap: var(--gs-space-4);
  }
  .bd-stats { flex-direction: row; gap: var(--gs-space-4); }
  .bd-air { flex-direction: row; align-items: center; gap: var(--gs-space-2); }
  .bd-air__track { width: auto; flex: 1 1 auto; height: 22px; min-height: 22px; min-width: 80px; }
  /* 横屏：液面从左往右长，所以比例落在**宽度**上。 */
  .bd-air__fill {
    top: 0;
    bottom: 0;
    right: auto;
    height: auto;
    width: calc(var(--bd-air, 1) * 100%);
    background: linear-gradient(90deg, var(--bd-water-near), var(--bd-neon-cyan));
  }
  .bd-air[data-low='true'] .bd-air__fill {
    background: linear-gradient(90deg, #8e1d33, var(--bd-alarm-red));
  }
}

/* ══════════ 品牌与标题 ══════════ */

.bd-brand { display: flex; flex-direction: column; align-items: center; gap: var(--gs-space-2); }
.bd-brand__mark { width: min(96px, 26%); height: auto; filter: drop-shadow(0 0 18px rgba(75, 242, 228, 0.5)); }

.bd-title {
  margin: 0;
  font-size: var(--bd-display-lg);
  font-weight: 900;
  letter-spacing: 0.01em;
  line-height: 1.05;
  color: var(--bd-foam);
  text-shadow: 0 0 22px rgba(75, 242, 228, 0.45), 0 3px 0 rgba(4, 18, 31, 0.6);
}

.bd-title--xl { font-size: var(--bd-display-xl); }

.bd-page-title {
  margin: 0;
  font-size: var(--bd-title-md);
  font-weight: 800;
  color: var(--bd-foam);
}

.bd-overlay-title { margin: 0; font-size: var(--bd-title-md); font-weight: 800; }
.bd-overlay-title--lg { font-size: var(--bd-title-lg); }
.bd-section-title {
  margin: var(--gs-space-3) 0 var(--gs-space-1);
  font-size: var(--bd-title-sm);
  font-weight: 800;
  color: var(--bd-neon-cyan);
}

.bd-lead { margin: 0; font-size: var(--bd-lead-lg); line-height: 1.4; color: var(--gs-ink); }
.bd-body { margin: 0; font-size: var(--bd-body-md); line-height: 1.5; color: var(--gs-ink-soft); }
.bd-small { margin: 0; font-size: var(--bd-body-sm); line-height: 1.45; color: var(--gs-ink-soft); }
.bd-caption { margin: 0; font-size: var(--bd-caption); color: var(--gs-ink-dim); }
.bd-gold { color: var(--bd-gold, var(--gs-gold)); }

.bd-list { margin: 0; padding-left: 1.15em; display: flex; flex-direction: column; gap: var(--gs-space-2); }
.bd-list li { font-size: var(--bd-body-md); line-height: 1.45; color: var(--gs-ink-soft); }

.bd-table { width: 100%; border-collapse: collapse; font-size: var(--bd-body-md); }
.bd-table th,
.bd-table td { text-align: left; padding: var(--gs-space-2) var(--gs-space-1); border-bottom: 1px solid var(--gs-hairline); }
.bd-table th { color: var(--bd-neon-cyan); font-size: var(--bd-body-sm); text-transform: uppercase; letter-spacing: 0.06em; }
.bd-table td:last-child { text-align: right; font-variant-numeric: tabular-nums; color: var(--gs-gold); font-weight: 700; }

/* ══════════ 面板与卡 ══════════ */

/* 面板**填满它的分区**并把内容摊开。定高分区里放一块按内容收缩的卡，
   会在卡内上下各留一大块空——十六屏加起来就是「整个游戏都空了一块」。 */
.bd-panel {
  background: var(--gs-surface);
  border: 1px solid var(--gs-hairline);
  border-radius: var(--gs-radius-lg);
  box-shadow: var(--gs-shadow-card);
  padding: var(--gs-space-4);
  display: flex;
  flex-direction: column;
  justify-content: space-evenly;
  gap: var(--gs-space-3);
  width: 100%;
  height: 100%;
  min-height: 0;
}

/* 面板里的内容比面板高时**它自己滚**，而不是把底下的按钮顶出分区。 */
.bd-panel[data-scroll='y'] {
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}

/* `align-content` 必须是 start：内容比容器高时 `center` 会让它**同时往上溢出**，
   而上面那一截在可滚容器里是**滚不回去的**——潜标屏的第一行就是这么被吃掉的。
   竖向居中由分区自己的 `justify-content` 负责，那一层不会溢出。 */
/* `flex: 0 0 auto` 是必需的：网格在弹性列里默认会被**压缩到比内容还矮**，
   于是每张卡的最后一行被自己的边框切掉（潜标屏实测）。让它保持自然高度，
   装不下就由分区自己滚——滚是可以的，切掉不行。 */
.bd-grid {
  display: grid;
  gap: var(--gs-tap-gap);
  width: 100%;
  flex: 0 0 auto;
  align-content: start;
}
.bd-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.bd-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }

/* `.bd-row` 是**横排**。少了 `flex-direction: row` 的后果不是「样式差一点」：
   `.bd-zone` 把主轴定成了 column，于是每一处「一行三个读数」「返回键 + 标题」
   都竖着堆起来——暂停页的三项数据挤成左上角一小条，返回键跑到标题上面去。 */
.bd-row {
  display: flex;
  flex-direction: row;
  gap: var(--gs-tap-gap);
  align-items: center;
  flex: 0 0 auto;
}
.bd-row--wrap { flex-wrap: wrap; }
.bd-row--between { justify-content: space-between; width: 100%; }
.bd-row--spread { justify-content: space-around; width: 100%; }

/* 选择卡：洞窟、记录、潜标共用同一个形态。锁着的**照样显示**，只是灰掉并写出门槛。 */
.bd-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-height: var(--gs-tap-min);
  padding: var(--gs-space-3);
  border-radius: var(--gs-radius-md);
  border: 1px solid var(--gs-hairline);
  background: var(--gs-surface-raised);
  color: var(--gs-ink);
  text-align: left;
  font: inherit;
  cursor: pointer;
}

.bd-card[aria-pressed='true'],
.bd-card[data-selected='true'] {
  border-color: var(--bd-cave-rim);
  box-shadow: var(--gs-glow-accent);
}

.bd-card[data-unlocked='false'] { opacity: 0.58; }
.bd-card__name { font-size: var(--bd-title-sm); font-weight: 800; }
.bd-card__meta { font-size: var(--bd-body-sm); color: var(--gs-ink-soft); }
.bd-card__lock { position: absolute; top: var(--gs-space-2); right: var(--gs-space-2); width: 18px; height: 18px; filter: var(--gs-icon-tint-ink); opacity: 0.7; }

/* 卡面上的插画。它在文字**底下**，压暗之后仍然要让卡名读得清。
   `overflow: hidden` **只给带插画的卡**：加在所有卡上会把长条件文案的最后一行剪掉
   （潜标屏实测「1 of 1」被卡底拦腰切断）。 */
.bd-card--art { overflow: hidden; }
.bd-card__art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.55;
  z-index: 0;
}
.bd-card__name,
.bd-card__meta { position: relative; z-index: 1; text-shadow: 0 1px 6px rgba(4, 18, 31, 0.9); }

/* ══════════ 结算页的三个大数字 ══════════ */

.bd-heroes { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--gs-space-2); }
.bd-hero { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.bd-hero__value {
  font-size: var(--bd-num-xl);
  font-weight: 900;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--bd-foam);
  text-shadow: 0 0 20px rgba(75, 242, 228, 0.4);
}
.bd-hero__label { font-size: var(--bd-body-sm); color: var(--gs-ink-soft); text-align: center; }
.bd-hero__best { font-size: var(--bd-num-gold-sm); font-weight: 700; color: var(--gs-gold); font-variant-numeric: tabular-nums; }

.bd-best { font-size: var(--bd-num-gold-md); font-weight: 800; color: var(--gs-gold); font-variant-numeric: tabular-nums; }

.bd-banner {
  align-self: center;
  padding: var(--gs-space-2) var(--gs-space-4);
  border-radius: var(--gs-radius-pill);
  background: linear-gradient(120deg, #ffc94a, #fff0c2 50%, #ffc94a);
  color: var(--bd-ink);
  font-weight: 900;
  font-size: var(--bd-title-sm);
  box-shadow: var(--gs-glow-gold);
}

/*
 * 结算页的解锁横条（screen-13）。**inline-bar**：嵌在 extra 分区里，
 * 没有遮罩、不圈焦点、不进弹窗栈——结构上就做不成模态。
 */
.bd-unlock-bar {
  display: flex;
  align-items: center;
  gap: var(--gs-space-3);
  padding: var(--gs-space-2) 0;
  border-top: 1px solid var(--gs-hairline);
  border-bottom: 1px solid var(--gs-hairline);
  min-height: 0;
}
.bd-unlock-bar__icon { width: 34px; height: 34px; filter: var(--gs-icon-tint-gold); flex: 0 0 auto; }
.bd-unlock-bar__text { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1 1 auto; }
.bd-unlock-bar__title { font-size: var(--bd-title-sm); font-weight: 800; }
.bd-unlock-bar__sub { font-size: var(--bd-body-sm); color: var(--gs-ink-soft); }

/* 「这台设备暂时存不了进度」那一条（§10.4）。**非阻塞**：没有遮罩、不圈焦点、
   不挡任何按钮，只是一行看得见的实话。存档正常时它根本不渲染。 */
.bd-storage-note {
  display: flex;
  align-items: center;
  gap: var(--gs-space-2);
  padding: var(--gs-space-1) var(--gs-space-2);
  border-radius: var(--gs-radius-sm);
  border: 1px solid var(--gs-hairline);
  background: var(--gs-surface-sunken, rgba(0, 0, 0, 0.28));
  flex: 0 0 auto;
  min-height: 0;
}
.bd-storage-note__icon { width: 18px; height: 18px; flex: 0 0 auto; filter: var(--gs-icon-tint-ink); }

/* ══════════ 潜标 / 潜水服 / 记录 ══════════ */

/* 潜标卡：**高度跟着文字走**。定高的后果是条件文案压到下一张卡上、最后一行被容器裁掉。 */
.bd-marker { gap: 3px; height: auto; min-height: 0; padding: var(--gs-space-2); }
.bd-marker__icon { width: 26px; height: 26px; }
.bd-marker[data-unlocked='true'] { border-color: var(--bd-cave-rim); box-shadow: var(--gs-glow-accent); }
.bd-marker[data-unlocked='false'] .bd-marker__icon { filter: grayscale(1) brightness(0.7); }
.bd-marker .bd-card__name { font-size: var(--bd-body-md); }
.bd-marker__cond { font-size: var(--bd-caption); color: var(--gs-ink-soft); line-height: 1.3; }
.bd-marker__track { height: 6px; border-radius: var(--gs-radius-pill); background: var(--gs-surface-sunken); overflow: hidden; }
.bd-marker__bar { height: 100%; background: var(--bd-neon-cyan); }
.bd-marker__count { font-size: var(--bd-body-sm); color: var(--gs-gold); font-variant-numeric: tabular-nums; }

/* 五套潜水服**一行摆完**：折成 4+1 会让最后一套看起来像另一类东西。
   每一列等宽，文字在列内换行，所以窄机上是字变窄，不是排版塌掉。 */
.bd-swatches {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: var(--gs-tap-gap);
  width: 100%;
  align-items: start;
}
.bd-swatch {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  max-width: 64px;
  min-width: var(--gs-tap-min);
  min-height: var(--gs-tap-min);
  border-radius: 50%;
  border: 2px solid var(--gs-hairline);
  background: var(--gs-surface-raised);
  padding: 0;
  cursor: pointer;
  overflow: hidden;
}
.bd-swatch img { width: 100%; height: 100%; object-fit: cover; display: block; }
.bd-swatch[data-selected='true'] { border-color: var(--bd-cave-rim); box-shadow: var(--gs-glow-accent); }
.bd-swatch[data-unlocked='false'] { opacity: 0.55; }
.bd-swatch__lock { position: absolute; inset: 0; margin: auto; width: 20px; height: 20px; filter: var(--gs-icon-tint-ink); }
.bd-swatch-row {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  min-width: 0;
  text-align: center;
}
/* 解锁条件在列内换行，**不横向溢出**——溢出会把左右两端的圆片裁掉。 */
.bd-swatch-row .bd-caption { overflow-wrap: anywhere; line-height: 1.2; }

.bd-portrait { width: min(180px, 52%); height: auto; border-radius: 50%; border: 2px solid var(--bd-skin-rim); box-shadow: var(--gs-glow-accent); }
.bd-portrait--sm { width: 56px; border-width: 1px; box-shadow: none; }
:root[data-skin='mint'] .bd-portrait { filter: hue-rotate(125deg); }
:root[data-skin='violet'] .bd-portrait { filter: hue-rotate(255deg); }
:root[data-skin='gold'] .bd-portrait { filter: hue-rotate(35deg); }
:root[data-skin='midnight'] .bd-portrait { filter: hue-rotate(190deg) brightness(.65); }
.bd-help-step { display: flex; align-items: center; gap: 12px; }
.bd-help-step__art { width: 56px; height: 56px; object-fit: contain; flex: 0 0 56px; }
.bd-hero__icon { width: 44px; height: 44px; object-fit: contain; }
.bd-marker__icon { width: 56px; height: 56px; object-fit: contain; }
.bd-record { min-height: 150px; flex-wrap: wrap; }
.bd-record > .bd-caption { flex: 0 0 100%; }
.bd-record .bd-record__grid { position: relative; }
.bd-zone--actions > * { flex-shrink: 0; }
.bd-panel[data-scroll='y'] { justify-content: flex-start; }

.bd-record { display: flex; flex-direction: row; gap: var(--gs-space-3); align-items: center; }
.bd-record__grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--gs-space-1) var(--gs-space-3); flex: 1 1 auto; }

/* 筛选行：每一组一个标签 + 一排分段。三组竖着叠，组之间留够间距，
   **不许和下面的记录卡叠在一起**（分区是互斥的，视觉上也要互斥）。 */
/* 三组筛选要塞进一条 12% 高的分区里，所以每组是**一行**：标签在左、分段在右。
   竖着堆的话三组要 180px，而分区只有约 115px——溢出的那一截会被滚动容器切掉，
   看上去就是「第三组筛选不见了、第二组被下面的卡压住半截」。 */
.bd-filter {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: var(--gs-space-2);
  width: 100%;
  flex: 0 0 auto;
}
.bd-filter__label {
  flex: 0 0 auto;
  min-width: 3.2em;
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gs-ink-dim);
}
/* 只给组件**在本布局里的伸缩**，不碰它自己的字号、内边距与触控下限——
   覆盖 `.gs-*` 的样式会把 44×44 下限和焦点环一起改坏，而那三样都不会在手机上被肉眼发现。
   `records-filter-zone-too-short` 这条矛盾已由 S2 裁决：筛选分区从 0.12 抬到 0.26
   （SCREEN_SPEC 是唯一真值，`game.config.json` 的 zones 由 `s3_sync_zones.mjs` 机械搬运）。
   最窄档 360×640 因此是 160 CSS px，三行 44px + 两道 8px 间距共 148px 装得下，
   **「这一区可滚」不再是三组都够得着的前提**；留着 `data-scroll='y'` 只是给
   某些语言标签换行之后的长内容兜底，触控下限一格不让。 */
.bd-filter .gs-segmented { flex: 1 1 auto; }

/* HUD 那一条竖栏很窄（竖屏只有 16% 宽），左右各留一点，读数不会贴到画布边上。 */
.bd-zone[data-zone='hud'] { padding-inline: var(--gs-space-1); }

/* 按钮里的图标。它是**纯装饰**，可读名称一直由按钮自己的文字提供。 */
.bd-btn__icon { width: 20px; height: 20px; flex: 0 0 auto; filter: var(--gs-icon-tint-ink); }
.gs-btn--primary .bd-btn__icon { filter: brightness(0) saturate(100%); }

/* ══════════ 教学气泡：非模态，自动躲开它指的那颗泡 ══════════ */

.bd-coach {
  position: absolute;
  max-width: 62%;
  padding: var(--gs-space-2) var(--gs-space-3);
  border-radius: var(--gs-radius-md);
  background: rgba(5, 10, 20, 0.86);
  border: 1px solid var(--bd-neon-cyan);
  color: var(--bd-foam);
  font-size: var(--bd-body-sm);
  line-height: 1.35;
  /* **绝不拦输入**：玩家可以无视它继续玩（§7.1）。 */
  pointer-events: none;
  z-index: 2;
}

.bd-coach__dots { display: flex; gap: 4px; margin-top: 4px; }
.bd-coach__dot { width: 6px; height: 6px; border-radius: 50%; background: var(--gs-ink-dim); }
.bd-coach__dot[data-on='true'] { background: var(--bd-neon-cyan); }

/* ══════════ 加载 / 错误 / 分享 ══════════ */

.bd-progress { width: 100%; height: 14px; border-radius: var(--gs-radius-pill); background: var(--gs-surface-sunken); overflow: hidden; box-shadow: inset 0 0 0 1px var(--gs-hairline); }
.bd-progress__fill { height: 100%; background: linear-gradient(90deg, var(--bd-neon-cyan), var(--bd-water-near)); transition: width var(--gs-fast) linear; }

.bd-share-card { width: 100%; height: auto; border-radius: var(--gs-radius-md); display: block; box-shadow: var(--gs-shadow-card); }
.bd-error-art { width: min(160px, 46%); height: auto; }

/* ══════════ 设置开关 ══════════ */

.bd-toggle {
  display: flex;
  align-items: center;
  gap: var(--gs-space-3);
  width: 100%;
  min-height: var(--gs-tap-min);
  padding: var(--gs-space-2) var(--gs-space-3);
  border: 1px solid var(--gs-hairline);
  border-radius: var(--gs-radius-md);
  background: var(--gs-surface-raised);
  color: var(--gs-ink);
  font: inherit;
  font-size: var(--bd-body-md);
  cursor: pointer;
}
.bd-toggle__icon { width: 20px; height: 20px; filter: var(--gs-icon-tint-ink); flex: 0 0 auto; }
.bd-toggle__label { flex: 1 1 auto; text-align: left; }
.bd-toggle__knob {
  flex: 0 0 auto;
  width: 44px;
  height: 24px;
  border-radius: var(--gs-radius-pill);
  background: var(--gs-surface-sunken);
  box-shadow: inset 0 0 0 1px var(--gs-hairline);
  position: relative;
}
.bd-toggle__knob::after {
  content: '';
  position: absolute;
  top: 3px;
  left: 3px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--gs-ink-dim);
  transition: transform var(--gs-fast) var(--gs-ease-out), background var(--gs-fast) linear;
}
.bd-toggle[aria-pressed='true'] .bd-toggle__knob::after { transform: translateX(20px); background: var(--bd-neon-cyan); }

/* 局内只读的潮汐分段控件（§5.3：局内改难度会让分数口径中途变化）。 */
[data-role='tide'][aria-disabled='true'] { opacity: 0.55; }

/* ══════════ 横屏那一档：唯一允许的第二档，出口高度 560px ══════════ */

@media (orientation: landscape) and (max-height: 560px) {
  .bd-title { font-size: var(--bd-title-lg); }
  .bd-hero__value { font-size: var(--bd-title-lg); }
  .bd-heroes { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .bd-portrait { width: min(120px, 60%); }
  .bd-brand__mark { width: min(64px, 20%); }
}
