:root {
  --sal: env(safe-area-inset-left);
  --sar: env(safe-area-inset-right);
  --sat: env(safe-area-inset-top);
  --sab: env(safe-area-inset-bottom);
}

* {
  /* 遊戲全畫面必備的 UI 鎖定 */
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}

/* 唯一不吃上面那組鎖的東西：文字輸入欄。
   `*` 的 user-select/touch-callout 也會套到 @pixi/ui 在 focus 時丟進
   document.body 的隱藏 <input>（見 libs/pixi-text-field 的 TextField）以及各個 DOM overlay 表單，
   長按因此不會進入選字模式 → 手機端完全叫不出「貼上」氣泡。

   只放行真的會打字的型別：checkbox / radio / button / file 沒有可選取的文字，
   解鎖它們只是白白把手勢還給瀏覽器。`:not([type])` 不可少——@pixi/ui 的
   `document.createElement("input")` 不帶 type，TextField 也只在
   fieldOptions.type 有值時才補，所以擷取欄可能整場都沒有 type 屬性。

   注意這裡**不動 `touch-action`**：長按選字與拖曳選取把手不需要它，而在 iOS
   上 `touch-action: auto` 會替欄位開回雙指／雙擊縮放——那正是「輸入模式下頁面
   尺寸變更」的另一條路徑。已在 Android 模擬器（Chrome 109）實測 touch-action:
   none 之下長按選單、Select all、拖曳選取把手（[0,11] → [0,4]）與
   Copy→Paste 往返全部正常。 */
input:is(
    :not([type]),
    [type="text"],
    [type="tel"],
    [type="password"],
    [type="number"],
    [type="email"],
    [type="search"],
    [type="url"]
  ),
textarea {
  -webkit-user-select: auto;
  user-select: auto;
  -webkit-touch-callout: default;
}

/* iOS Safari 對「focus 當下 computed font-size < 16px」的欄位會自動放大整頁
   ——那就是「輸入模式下頁面尺寸變更」在 iOS 上的形態。`@pixi/ui` 的
   Input.createInputField 只寫 position/size/opacity/border/background，從不設
   font-size，所以它建立的擷取用 <input> 吃 UA 預設約 13.3px。

   必須是 CSS 不能是 JS：createInputField 在 `document.body.appendChild(input)`
   之後**同步**呼叫 `input.focus()`，而且要到 focus 之後才 `this.input = input`
   ——所以 TextField._startEditing 拿到元素時已經太遲，寫 inline style 補不回來。
   規則放在樣式表，元素一 append 就是 16px。

   `body > input` 精準命中「直接掛在 body 的隱藏輔助 input」：@pixi/ui 的擷取欄、
   idPictureRow 的 display:none 檔案選取器。promo / wallet deposit /
   personal-data 的可見欄位都包在各自的 root 容器內，不受影響。
   ⚠ 這是「魔法路徑」，相依於 @pixi/ui 把 input append 到 body。TextField.test.ts
   有一則測試守住這個前提，升版改了結構會先炸在那裡。真的炸了怎麼辦：
   1. 先看新版有沒有給 class/id——**目前沒有**（createInputField 只寫 inline
      style，不碰 className/id），所以今天沒有比這更穩的鉤子；有了就換過去。
   2. 都沒有的話，TextField 可以自己覆寫 createInputField() 接管建立流程，但
      連 focus 時序也得一起承擔（focus 是在 append 之後同步發生的）。 */
body > input {
  font-size: 16px;
}

/* TextField 編輯中顯示的是真的 <input>（Pixi 字藏起來），但密碼欄的 type 故意
   留 text——`type="password"` 會引來 Chrome 的「要更新密碼嗎？」提示（見
   TextField._startEditing）。遮罩改由 CSS 做，`data-secure` 跟著 `secure`／
   眼睛切換。Firefox 138 起才支援 -webkit-text-security；本專案手機端只有
   Safari／Chrome。 */
input[data-secure] {
  -webkit-text-security: disc;
}

/* 有內容的密碼欄不給選取。選取工具列與右鍵選單只有在「有選取內容」時才會給
   「複製／剪下」，所以有值時關掉 user-select，那兩顆就不會出現；空欄位維持可選，
   長按才叫得出「貼上」氣泡——那正是上面那條 `input:is(…)` 規則存在的理由。
   `data-has-value` 由 TextField._startEditing 跟著值同步（見該處註解）。

   為什麼不直接用原生 `type="password"`（瀏覽器自己就不給密碼欄複製）：那會把
   Chrome 密碼管理員的「要更新密碼嗎?」提示帶回來，而且換不到任何好處——`@pixi/ui`
   的 input 是 focus 才建、blur 就丟，帳密兩欄不並存，Chrome 無從配對憑證，存了也
   不會回填。詳見 tasks/active/app-ops-infrastructure-260805.md。

   ⚠ 這條只擋得掉**長按進選字模式**那條路。2026-09-17 在 Pixel 3a（Android 13、
   Chrome 109）實測：長按只剩 Paste / Select all，但按下 Select all 選取照樣成立，
   Cut / Copy / Paste / Read aloud 全部回來——IME 的 Select all 指令不看 user-select。
   那條路由 `libs/pw-guards` 的 select 守衛收合選取來擋，兩者缺一不可。

   `libs/pw-guards` 也照擋 copy/cut/dragstart 事件，職責不重複：事件守衛管
   「按下去拿不到東西」，這條與 select 守衛管「按鈕不要出現」。

   代價：欄位已經有字時沒辦法長按貼上覆蓋，要先清空。 */
input[data-password][data-has-value] {
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

html,
body {
  overflow: hidden !important;
  height: 100% !important;
  margin: 0;
  padding: 0;
  background-color: #000000;
  position: fixed;
}

/* 頁面托底：海島橫版底圖鋪滿整個視窗，canvas 直接壓在上面。
   直版欄以外的區域(桌機上是左右兩條)本來是 renderer 的清除色，現在改成透出這張圖。

   用登入頁的橫版底圖，跟大廳直版的 `Background_Straightl01.png`（2026-09-23 起
   MainScreen 也改吃這張共用檔，原本獨立的 `BG_Lobby.png` 已移除）是同一個海島
   場景(沙灘＋木棧道)，所以側邊看起來像同一個畫面延伸出去，而不是另一張不相干的圖。

   兩個前提，缺一就看不到：
   1. `engine.init` 必須帶 `backgroundAlpha: 0`(見 src/main.ts)——canvas 是滿版的，
      不透明的 renderer 會整片蓋住這裡。
   2. 手機直版下畫布本來就填滿螢幕，這張圖不會露出來；這是桌機/寬視窗才看得到的裝飾。

   ⚠ **這條路徑已經無聲斷過兩次，不是假設性的風險。** `assets/**` 是 AssetPack 從
   `raw-assets/` 產生的(public/assets 在 .gitignore 裡)：素材一旦改名或搬家，不會有
   任何建置錯誤或主控台訊息，只會靜默變回純黑底。

   2026-09-16 `3cb0d5fb`(整併 raw-assets 目錄)把這張圖從 `sprites/login/` 搬到
   `sprites/background/`，Pixi 那邊毫髮無傷——程式用的是 `Texture.from("檔名.png")`
   這種 bare-filename alias，跟路徑無關；只有這裡的 CSS 斷掉。

   2026-09-17：這裡曾經寫成**帶開頭斜線的絕對路徑**(`/assets/...`)。dev/正式站是每個
   版本各自一個子資料夾(`index.html` 用 `<base href="./<version>/">` 指過去)，帶開頭
   斜線的路徑會蓋掉 base、直接打站台根目錄，該版本子資料夾底下的檔案就 404。**這裡必須
   用不帶開頭斜線的相對路徑**——CSS 的 `url()` 是相對這份 style.css 自己的位置解析，不受
   `<base href>` 影響，跟著版本子資料夾走才會對。

   所以動 `raw-assets/sprites/background/Background_Horizontal01.png` 的位置或檔名時，
   **必須一起改這裡**；改這裡的路徑寫法時，**不要加開頭斜線**。真的想根治，就得把托底
   改成 Pixi 的滿版 sprite(用 bare alias，找不到會直接報錯)，代價是它就不再是「網頁的
   背景」而是 app 內容的一部分。 */
body {
  /* 兩層：上層是壓暗用的漸層，下層才是圖。
     漸層是橢圓放射狀、中央最深往外淡出——中央那塊正好被直版畫布蓋住，所以實際看到的
     是「緊貼畫布邊緣最暗、往螢幕兩側逐漸變亮」的霧化黑邊，同時整張圖的亮度整體被壓下去，
     不會跟畫布裡的內容搶目光。

     三個 alpha 就是全部的調整鈕：0.28＝貼齊畫布處、0.22＝中段、0.16＝螢幕最外緣。
     數字越大越暗。三個一起加減＝整體亮度；只動第一個＝霧化黑邊的濃度。
     (2026-09-16 由使用者用即時滑桿實際拉出來的值，不是估的。)
     22% 那個位置停點大致對齊直版欄的邊緣(1280px 寬時欄寬約 500px)，但欄寬會隨視窗變，
     所以它是近似值不是精準對齊——這是裝飾用的托底，不需要也做不到跟著欄寬跑。 */
  background-image:
    radial-gradient(
      ellipse 70% 90% at 50% 50%,
      rgba(0, 0, 0, 0.28) 22%,
      rgba(0, 0, 0, 0.22) 42%,
      rgba(0, 0, 0, 0.16) 100%
    ),
    url("assets/sprites/background/Background_Horizontal01.webp");
  /* 兩個值＝兩層，順序對應上面的 background-image(漸層在前、圖在後)。

     漸層層 `100% 100%` + `center center`：固定貼齊視窗，霧化黑邊的中心才會落在畫布
     中央。**不能讓它跟著圖一起放大**，否則暗環中心被推到視窗下方。

     圖層 `auto 120%` + `center top`：高度放大到視窗的 1.2 倍並靠上對齊，等於只取原圖
     上緣約 83%——木棧道落到視窗外，只留天空、雲與一線海平面。120 越大天空佔比越高。
     (原圖 1920×1080，木棧道約在 81% 高度處開始。)

     ⚠ 用 `auto 150%` 而不是 `cover`：`cover` 永遠會讓某一邊剛好貼齊，一般桌機比例下
     貼齊的是高度，於是整張圖(含木棧道)一定全露、`background-position` 也就完全沒有
     可位移的空間。代價是超寬螢幕(寬高比 > 2.67)兩側會露出 body 的黑底。 */
  background-position:
    center center,
    center top;
  background-size:
    100% 100%,
    auto 120%;
  background-repeat: no-repeat;
}

/* 主畫面卡片陰影(`#game-shadow`,index.html)。真的 CSS box-shadow,由
   MainScreen.resize() 把它的 left/top/width/height 對齊 Pixi §0 design canvas
   的方框(取代原本 Pixi 端每幀重跑一次 GPU 高斯模糊的 BlurFilter 做法——box-shadow
   由瀏覽器 compositor 處理,只有這個 div 的幾何值真的變動(即 resize 當下)才會
   重算,不是每幀)。

   `#pixi-container > canvas` 的 `position: relative` 不是多餘的——canvas 預設
   `position: static`,而 CSS 疊層順序(CSS2.1 附錄 E)規定:任何「有定位」元素
   (position 非 static,即使 z-index 是 auto)一定畫在所有「無定位、正常流」元素
   之上,不管 DOM 先後。`#game-shadow` 要疊在 canvas 下面,勢必得是「有定位」
   元素(box-shadow 才能貼著任意矩形位置),那就只能讓 canvas 也加入「有定位」
   這一組,兩者才會回到用 DOM 順序(`#game-shadow` 排在 `#pixi-container` 前面)
   決定疊層。這裡沒有加 top/left,對版面沒有任何位移影響。 */
#pixi-container > canvas {
  position: relative;
}

#game-shadow {
  position: absolute;
  left: 0;
  top: 0;
  width: 0;
  height: 0;
  display: none;
  pointer-events: none;
  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
}

/* Webview iframe — overlaid on PixiJS canvas */
#webview-iframe {
  position: fixed;
  left: 0;
  width: 100%;
  border: none;
  z-index: 10;
  touch-action: auto;
  -webkit-user-select: auto;
  user-select: auto;
}

/* ── Boot splash: instant pre-Pixi loading screen (see src/app/bootSplash.ts) ── */
#boot-splash {
  position: fixed;
  inset: 0;
  z-index: 5; /* above the static canvas; below #webview-iframe (z-index 10) */
  display: flex;
  align-items: center;
  justify-content: center;
  /* ⚠ 這裡原本寫「MATCHES the engine clear color so handoff doesn't shift」——那句
     已經不成立。engine 現在是 `backgroundAlpha: 0`(見 src/main.ts)，清除色不再被畫
     出來，canvas 背後是 body 的天空托底，所以交接會是「深灰 → 淡出 → 藍天」，有一次
     看得見的顏色跳動。2026-09-16 經使用者裁定**維持現狀**：不為了無縫而把 splash 也
     鋪成天空(黃色徽章壓在亮藍天上可讀性會變差)。要改的話見 style.css 的 body 托底。 */
  background: #1e1e1e;
  /* The fill has already reached 100% by the time this runs (bootSplash.ts waits
     for it), so the fade only has to get out of the way. */
  transition: opacity 300ms ease;
}
#boot-splash.is-hidden {
  opacity: 0;
  pointer-events: none;
}
.boot-splash__inner {
  position: relative;
  /* matched to the Pixi LoadScreen logo (built from this same <img>, 200×93 at native size);
     keep the aspect ratio — bootWave.ts stretches the logo to this box.
     2026-10-16: height is the fixed part, width follows the image's own aspect
     (`.boot-logo` below), so a logo with another aspect (e.g. the CG badge,
     ~1.4:1) is not stretched into a 200px-wide box. 200×93 art gives the same
     200×93 box as before. */
  width: max-content;
  height: 93px;
  transform-origin: center;
}
/* The DIM badge. Dimmed here (no JS) so the first painted frame already shows
   the logo — .boot-fill then paints the LIT part on top. See app/bootWave.ts. */
.boot-logo {
  display: block;
  width: auto;
  height: 93px;
  opacity: 0.22;
}
/* Carries the liquid AND the percentage. The canvas covers the logo box and then
   hangs 44px BELOW it for the readout (PCT_STRIP_H in app/bootWave.ts — keep the
   two in sync); the logo box itself stays centred, so the handoff to the Pixi
   LoadScreen does not shift. Styling lives in app/bootWave.ts. */
.boot-fill {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: calc(100% + 44px);
}
