@property --ga {
  syntax: '<angle>';
  inherits: false;
  initial-value: 160deg;
}
@view-transition {
  navigation: auto;
}
::view-transition-group(*) {
  animation-duration: .55s;
  animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
/* 換頁的淡入淡出:舊頁整段留在底下當底,新頁在它上面淡入。正常混色下合成權重恆為 1
   (α·新 + (1-α)·舊),中途既不透出底色也不會亮度相加,也就是一般說的溶接。
   瀏覽器預設是兩張快照同時淡入淡出、而且都掛 mix-blend-mode: plus-lighter —— 亮度相加。
   首頁那串金色大獎數字疊在陳列室的彩色封面上會比它在首頁本身還亮,看到的是重影不是淡出;
   金庫頁夠暗才勉強遮得住,所以同一套預設在「到陳列室」與「到金庫」兩條路上看起來不一樣。
   animation 簡寫會一併蓋掉 UA 那條 plus-lighter 動畫,不必另外寫 mix-blend-mode。
   時長取 --t 的 .55s,跟上面的群組動畫對齊。只動透明度,減動偏好下照跑(見檔尾那段)。 */
@keyframes vt-fade-out {
  to { opacity: 0; }
}
@keyframes vt-fade-in {
  from { opacity: 0; }
}
::view-transition-old(*) {
  animation: vt-fade-out .55s cubic-bezier(0.4, 0, 0.2, 1) both;
}
::view-transition-new(*) {
  animation: vt-fade-in .55s cubic-bezier(0.4, 0, 0.2, 1) both;
}
/* 底下那張整頁快照不淡出。兩張都在中途半透明的話,底色會從縫隙透出來變成一段黑場 ——
   兩個暗頁之間看不出來,新頁一亮就變成「先黑掉再硬切」,同一套規則兩種手感。
   留著舊頁當底,新頁蓋上去,任何亮度組合都是同一條溶接曲線。
   上面那條 (*) 仍然必要:首頁七道分類門各有具名群組,到陳列室時沒有新元素配對,
   舊快照不淡出就會浮在新頁上面。 */
::view-transition-old(root) {
  animation: none;
  opacity: 1;
}
/* 標誌是唯一維持 plus-lighter 的。三頁的 .brand 位置與畫素完全一樣,相加剛好補成一張
   完整的圖,換頁時它就穩穩停在原地不閃;走正常混色的話兩張各半,中途會暗掉四分之一,
   看起來像閃了一下。一定要寫在 (*) 後面:同名選擇器打平時由原始碼順序決勝。 */
::view-transition-old(brand),
::view-transition-new(brand) {
  mix-blend-mode: plus-lighter;
}
:root {
  --bg: #0a0806;
  --bg2: #0f0c08;
  --surface: #121008;
  --line: rgba(212, 175, 55, .26);
  --line-soft: rgba(212, 175, 55, .13);
  --gold: #d4af37;
  --gold-hi: #f3df9a;
  --gold-dim: #8a6d1f;
  --ink: #e9e2d0;
  --ink-dim: #9a917c;
  --ink-faint: #847a66;
  --ok: #3fae5a;
  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  --t-fast: .35s;
  --t: .55s;
  --t-slow: .7s;
  --serif: 'Cormorant Garamond', 'Songti SC', 'STSong', 'SimSun', ui-serif, Georgia, serif;
  --sans: 'Jost', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', system-ui, sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, 'SF Mono', Consolas, monospace;
}
* {
  box-sizing: border-box;
}
html {
  scroll-behavior: auto;
  /* 全站只有一套深色。宣告出來,原生介面才知道要畫哪一套:
     未勾選的核取方塊不再是白底方塊(accent-color 只管勾選態)、搜尋框的清除鈕、
     捲軸、文字選取、以及 Chrome 自動填入時那塊淡藍底 —— 手機上自動填入是常態,
     那塊底色打在近黑的欄位上最刺眼。.sel 那條原本就有,這裡是把它提到根節點。 */
  color-scheme: dark;
  /* iOS Safari 轉到橫向時會自己把內文放大(text autosizing),站上的字級全是量過的,
     放大之後行長與卡片高度整組跑掉。100% 是「照寫的大小算」,不是關掉縮放手勢。 */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  /* 點擊高亮整個關掉。行動瀏覽器會照元素的邊界盒畫一個矩形色塊,而站上的鍵
     不少是靠 ::after 撐開可點範圍、或是像語言鍵那樣無框的 —— 那個矩形跟看得見的
     鍵對不上,點下去像是憑空多出一個框。回饋改由元素自己給:.btn-gold / .btn-ghost
     有 :active,語言鍵有 [aria-expanded="true"],不靠瀏覽器代畫。 */
  -webkit-tap-highlight-color: transparent;
}
html:has(body[data-page="home"]) {
  scroll-snap-type: none;
}
body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-weight: 300;
  font-size: 15px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
h1, h2, h3, h4, p, ul, ol, figure {
  margin: 0;
}
ul, ol {
  padding: 0;
  list-style: none;
}
a {
  color: inherit;
  text-decoration: none;
}
button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}
img {
  max-width: 100%;
}
::selection {
  background: var(--gold);
  color: #0a0806;
}
:focus-visible {
  outline: 1px solid var(--gold);
  outline-offset: 3px;
}
/* 跳到主要內容:頂欄加側欄一共 13 個停留點才碰得到內文,鍵盤使用者每頁都要重走一次。
   平常收在畫面外,只有 Tab 到才滑下來。 */
.skip {
  position: fixed;
  top: 0;
  left: 50%;
  z-index: 100;
  transform: translate(-50%, -110%);
  padding: 12px 26px;
  font-size: 11px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--gold-hi);
  background: var(--bg2);
  border: 1px solid var(--gold);
  transition: transform var(--t-fast) var(--ease);
}
/* 落在頂欄下緣而不是壓在頂欄上:top:0 時這塊正好蓋掉置中的品牌標,
   「HERCULES」被切成「HERC…303」,看起來像破圖。60px = .bar 的高度。 */
.skip:focus-visible {
  transform: translate(-50%, 60px);
}
/* 跳過去之後焦點落在 <main tabindex="-1">,整塊套一圈金框沒有意義 */
main[tabindex]:focus {
  outline: none;
}
/* 全站共用:視覺隱藏但留在無障礙樹裡。不能用 display:none / visibility:hidden ——
   那會把節點整個移出無障礙樹,auth 的 live region 不會念、lobby 的 <h1> 會消失。
   目前用戶:auth.html #auth-say、lobby.html #lobby-title、lobby.html #count、
   index.html 三段 .ch-head。 */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.bar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 40;
  height: 60px;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 16px;
  padding: 0 clamp(16px, 3vw, 40px);
  /* 橫放時感測器區塊(瀏海 / 挖孔)會壓在畫面側邊,viewport-fit=cover 之後版面
     會鋪到那底下。max() 取「原本的內距」與「安全區」較大者:沒有安全區的裝置
     env() 是 0,算出來跟上一行完全一樣,只有真的有瀏海時才往內收。
     背景與毛玻璃仍然整寬鋪滿,收的只有內容。 */
  padding-left: max(clamp(16px, 3vw, 40px), env(safe-area-inset-left));
  padding-right: max(clamp(16px, 3vw, 40px), env(safe-area-inset-right));
  background: rgba(10, 8, 6, .74);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line-soft);
}
.bar-nav {
  display: flex;
  gap: clamp(14px, 2vw, 30px);
}
.bar-nav a, .bar .back {
  font-size: 11px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--ink-dim);
  transition: color var(--t-fast) var(--ease);
}
.bar-nav a:hover, .bar .back:hover {
  color: var(--gold);
}
.bar .back {
  display: inline-flex;
  align-items: center;
  gap: .7em;
  justify-self: start;
}
.brand {
  display: inline-flex;
  align-items: center;
  view-transition-name: brand;
  position: relative;
  isolation: isolate;
}
.brand::before {
  content: "";
  position: absolute;
  inset: 4% -15%;
  pointer-events: none;
  background: radial-gradient(ellipse, rgba(212, 175, 55, .34), rgba(212, 175, 55, 0) 70%);
  opacity: .16;
  transform: scale(.86);
  transition: opacity .55s cubic-bezier(.16, 1, .3, 1), transform .55s cubic-bezier(.16, 1, .3, 1);
  animation: brand-halo 5.2s 1s cubic-bezier(.4, 0, .2, 1) infinite;
}
/* 外發光在這裡打,不在素材裡。素材用的是 wordmark.svg —— 同一組字標,但沒有
   lockup-horizontal.svg 那個烘進檔案的 feGaussianBlur;那個模糊是照 1176 寬的畫布
   算的,縮到頂欄的 56px 高時整圈糊邊跟著縮不動,筆畫本身就霧掉了。
   drop-shadow 只糊 alpha 再畫在字標後面,字緣仍然是原本的向量邊,所以是「清楚的字
   加一圈光」而不是「糊掉的字」。三層由內而外:4px 貼著筆畫當亮邊,14px 是主要的
   光暈,34px 是散在頂欄底色上的餘光。三層一起加亮、加寬,散得比原本遠約五成。
   放大模糊半徑不會回頭糊到筆畫 —— drop-shadow 糊的是複製出去的 alpha,原圖照畫在
   上面,所以邊緣落差跟沒有發光時是同一個數。 */
.brand img {
  display: block;
  width: auto;
  height: clamp(42px, 5vw, 56px);
  position: relative;
  z-index: 1;
  transform-origin: 50% 50%;
  filter:
    drop-shadow(0 0 4px rgba(212, 175, 55, .72))
    drop-shadow(0 0 14px rgba(212, 175, 55, .42))
    drop-shadow(0 0 34px rgba(212, 175, 55, .2));
  animation: brand-arrive 1.05s cubic-bezier(.16, 1, .3, 1) both;
  transition: transform .55s cubic-bezier(.16, 1, .3, 1), filter .55s cubic-bezier(.16, 1, .3, 1);
}
.brand:hover::before {
  opacity: .58;
  transform: scale(1.16);
}
.brand:hover img {
  transform: translateY(-1px) scale(1.025);
  /* 游標停上去光就旺一點 —— 跟 .brand::before 那圈底光是同一個動作的兩半 */
  filter:
    drop-shadow(0 0 4px rgba(212, 175, 55, .85))
    drop-shadow(0 0 17px rgba(212, 175, 55, .55))
    drop-shadow(0 0 42px rgba(212, 175, 55, .3));
}
@keyframes brand-arrive {
  from { opacity: 0; transform: translateY(-5px) scale(.95); }
  to { opacity: 1; transform: none; }
}
@keyframes brand-halo {
  0%, 100% { opacity: .16; transform: scale(.86); }
  50% { opacity: .34; transform: scale(1.06); }
}
.bar-end {
  display: flex;
  align-items: center;
  gap: 12px;
  justify-self: end;
}
.sel {
  appearance: none;
  -webkit-appearance: none;
  background: transparent url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5'%3E%3Cpath d='M0 0l4 5 4-5z' fill='%239a917c'/%3E%3C/svg%3E") no-repeat right 10px center;
  border: 1px solid var(--line-soft);
  color: var(--ink-dim);
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: .1em;
  padding: 7px 26px 7px 12px;
  cursor: pointer;
  transition: border-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.sel:hover {
  border-color: var(--line);
  color: var(--ink);
}
/* 收起來的樣子本來就對了,難看的是展開那張清單 —— 那是作業系統畫的,一般 CSS 碰不到,
   所以在黑金頁面上跳出一塊白底加藍色高亮。分兩層處理:
   1) color-scheme 是唯一能影響原生清單的標準屬性,四端瀏覽器都認。至少讓它變成深色清單;
      iOS/Android 的原生滾輪也一起變深 —— 手機那套介面本來就不該自己重畫,原生的最好用。
   2) Chrome/Edge 135+ 有 appearance: base-select,清單會變成可以完全接手的 ::picker(select),
      這條路才畫得出金線邊框和燙金選取態。用 @supports 圍住,不支援的瀏覽器只吃第 1 層。 */
.sel {
  color-scheme: dark;
}
@supports (appearance: base-select) {
  .sel,
  .sel::picker(select) {
    appearance: base-select;
  }
  /* base-select 的按鈕寬度只跟著「目前選中那項」走,舊行為是取最寬的一項。
     實測(當時 #lang 還是 <select>)從穩定的 137px 變成 81~136px 浮動 —— 一換整條頂欄就跟著抖,
     行高也從 normal 被改成 17.6px(高度 32→33.6)。兩個都釘回舊行為量到的值。
     用 min-inline-size 不用 width:以後選項變長還能自己撐開,不會裁字。
     行高寫死 px 不寫 normal:base-select 底下 normal 會算成 17px,舊行為是 16px,差那 1px
     整顆按鈕就會長高、在頂欄裡的垂直位置也跟著偏。 */
  .sel {
    min-inline-size: var(--sel-w);
    line-height: 16px;
  }
  #prov {
    --sel-w: 124px;
  }
  /* base-select 會自己補一個下拉箭頭,但 .sel 的背景本來就畫了一個,不關掉會變兩個 */
  .sel::picker-icon {
    display: none;
  }
  .sel::picker(select) {
    background: var(--bg2);
    border: 1px solid var(--line);
    border-radius: 0;
    padding: 4px 0;
    margin-top: 6px;
    box-shadow: 0 18px 40px rgba(0, 0, 0, .6);
    /* 開合用站上同一組時間與曲線。overlay/display 要 allow-discrete,
       不然 popover 一關就直接消失,淡出那半段根本跑不到。 */
    opacity: 0;
    translate: 0 -6px;
    transition: opacity var(--t-fast) var(--ease), translate var(--t-fast) var(--ease),
                overlay var(--t-fast) allow-discrete, display var(--t-fast) allow-discrete;
  }
  .sel::picker(select):popover-open {
    opacity: 1;
    translate: 0 0;
  }
  @starting-style {
    .sel::picker(select):popover-open {
      opacity: 0;
      translate: 0 -6px;
    }
  }
  .sel option {
    background: transparent;
    color: var(--ink-dim);
    font-family: var(--sans);
    font-size: 11px;
    letter-spacing: .1em;
    padding: 9px 16px;
    transition: color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
  }
  /* 選中狀態沿用側欄 .rl.on 那套(金色左邊條 + 右淡的金光),站上已經有這個語彙了 */
  .sel option:checked {
    color: var(--gold-hi);
    background: linear-gradient(90deg, rgba(212, 175, 55, .1), transparent 75%);
    box-shadow: inset 2px 0 var(--gold);
  }
  .sel option::checkmark {
    display: none;
  }
  .sel option:hover {
    color: var(--ink);
    background: rgba(212, 175, 55, .06);
  }
}
/* ── 語言鍵 ────────────────────────────────────────────────────────
   自己畫的下拉,不是 <select>。理由寫在 app.js 那一段:原生清單的面板是作業系統
   畫的,iOS/Safari 一律開成一張跟畫面同寬、貼在底部的滾輪,CSS 一個字都碰不到。
   收合的鍵沿用 .sel 那套語彙(同一個字級、字距、灰金、細框、右邊一個小箭頭),
   換掉的只有展開之後那張面板 —— 現在它跟站上其餘的浮層是同一種黑金,
   而且寬度由內容決定,四端一模一樣。#prov 仍是原生 <select>:大廳那顆是遊戲商
   篩選,清單在頁面中段展開、選項是專有名詞,原生的滾輪在手機上反而好用。 */
.lang {
  position: relative;
}
/* 語言鍵寬窄同一顆:字母、地球、箭頭,不畫框。字母是狀態(現在是哪一國語言),地球說明
   這是語言,箭頭說明按下去會展開 —— 由近而遠,讀的順序跟理解的順序一樣。
   原本寬屏是帶框的全名鍵,跟旁邊的登入 / 註冊同一個量級,但它遠不是同一個量級的東西;
   拿掉框、收成縮寫,它退回成一個標記,兩顆按鈕自己站出來。
   可點範圍:min-height 直接寫 44px,整顆量到 50x44,WCAG 2.5.8 的 24x24 與本站的 44 高都在。
   min-width 50px:四個縮寫寬度不一(EN 最寬 48px),不釘住的話換語言整條 .bar-end 會挪;
   釘 min-width 不釘 width,日後多一個語系、縮寫更寬時它自己還撐得開。
   字靠右貼著地球;字距歸零(一兩個字排不出字距的作用);字級 13px ——「简 / 繁」筆畫多,
   再小橫豎就糊成一團;地球 15px 跟字一起長才不會一大一小。
   鍵盤焦點不受影響 —— 全站的 :focus-visible 是外框線不是這裡的 border。 */
.lang-btn {
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  min-width: 50px;
  min-height: 44px;
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  background-image:
    url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='15' height='15' viewBox='0 0 24 24' fill='none' stroke='%239a917c' stroke-width='1.7'%3E%3Ccircle cx='12' cy='12' r='9.2'/%3E%3Cpath d='M2.8 12h18.4M12 2.8c4.6 5 4.6 13.4 0 18.4-4.6-5-4.6-13.4 0-18.4'/%3E%3C/svg%3E"),
    url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='9' height='5'%3E%3Cpath d='M0 0l4.5 5L9 0z' fill='%239a917c'/%3E%3C/svg%3E");
  background-repeat: no-repeat, no-repeat;
  background-position: right 11px center, right 0 center;
  border: 1px solid transparent;
  color: var(--ink-dim);
  font-family: var(--sans);
  font-size: 13px;
  letter-spacing: 0;
  padding: 0 30px 0 0;
  cursor: pointer;
  transition: color var(--t-fast) var(--ease);
}
/* 面板開著的時候鍵維持在 hover 的樣子。行動端沒有游標,展開中的鍵本來就該看得出
   是它把面板叫出來的 —— 這也是拿掉點擊高亮之後留給觸控的回饋。 */
.lang-btn:hover {
  color: var(--ink);
}
.lang-btn[aria-expanded="true"] {
  color: var(--gold-hi);
}
/* 面板貼著鍵的右緣往下開:頂欄右側本來就滿了,往左長才不會掉出畫面。
   min-width 跟鍵一樣寬,內容更長時自己撐開 —— 寬度由最長那一項決定,不多不少。 */
.lang-list {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 60;
  min-width: 100%;
  margin: 0;
  padding: 4px 0;
  list-style: none;
  background: var(--bg2);
  border: 1px solid var(--line);
  box-shadow: 0 18px 40px rgba(0, 0, 0, .6);
  /* 開合跟站上其餘浮層同一組時間與曲線 */
  opacity: 0;
  translate: 0 -6px;
  transition: opacity var(--t-fast) var(--ease), translate var(--t-fast) var(--ease);
}
.lang-list.on {
  opacity: 1;
  translate: 0 0;
}
.lang-list li {
  white-space: nowrap;
  color: var(--ink-dim);
  font-size: 12px;
  letter-spacing: .1em;
  padding: 10px 18px;
  cursor: pointer;
  transition: color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
/* 選中狀態沿用側欄 .rl.on 那套(金色左邊條 + 右淡的金光),站上已經有這個語彙了 */
.lang-list li[aria-selected="true"] {
  color: var(--gold-hi);
  background: linear-gradient(90deg, rgba(212, 175, 55, .1), transparent 75%);
  box-shadow: inset 2px 0 var(--gold);
}
.lang-list li:hover {
  color: var(--ink);
  background: rgba(212, 175, 55, .06);
}
.btn-gold {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .8em;
  /* .22em 字距 + 窄頂欄,實測 390px 下「註冊」會被拆成兩行。 */
  white-space: nowrap;
  background: linear-gradient(160deg, var(--gold-hi), var(--gold));
  background: linear-gradient(var(--ga), var(--gold-hi), var(--gold));
  color: #0a0806;
  font-weight: 500;
  font-size: 11px;
  letter-spacing: .22em;
  text-transform: uppercase;
  padding: .85em 1.9em;
  border: 1px solid var(--gold);
  transition: --ga var(--t) var(--ease), transform var(--t-fast) var(--ease), box-shadow var(--t) var(--ease);
}
.btn-gold:hover {
  --ga: 280deg;
  transform: translateY(-2px);
  box-shadow: 0 14px 34px -14px rgba(212, 175, 55, .45);
}
.btn-gold:active {
  transform: translateY(0) scale(.98);
}
.btn-ghost {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .8em;
  /* .22em 字距 + 窄頂欄,實測 390px 下「註冊」會被拆成兩行。 */
  white-space: nowrap;
  color: var(--ink);
  font-size: 11px;
  letter-spacing: .22em;
  text-transform: uppercase;
  padding: .85em 1.9em;
  border: 1px solid var(--line);
  transition: border-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.btn-ghost:hover {
  border-color: var(--gold);
  color: var(--gold-hi);
  transform: translateY(-2px);
}
.btn-ghost:active {
  transform: translateY(0) scale(.98);
}
/* 兩顆按鈕自己宣告了 display,會蓋掉 UA 的 [hidden] { display: none }。
   頂欄那顆「登入 / VIP 金庫」靠 hidden 二選一,注冊靠 hidden 只給沒登入的人看,
   不補這條 hidden 就形同虛設。 */
.btn-ghost[hidden], .btn-gold[hidden] {
  display: none;
}
.bar .btn-gold, .bar .btn-ghost {
  padding: .6em 1.4em;
}
.spine {
  position: fixed;
  right: 22px;
  right: max(22px, env(safe-area-inset-right));
  top: 50%;
  transform: translateY(-50%);
  z-index: 30;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 16px;
}
.spine a {
  width: 18px;
  height: 1px;
  padding: 7px 0;
  box-sizing: content-box;
  background: var(--ink-faint);
  background-clip: content-box;
  transition: width var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease);
}
.spine a.on {
  width: 36px;
  background: var(--gold);
}
/* 這條線本體只有 18×15,按不準。跟 .bar .back / .pnl-more 同一招:
   撐一個透明的 ::after 出來當點擊面積,畫面上什麼都沒有變。
   高度只給 30 不給 44 —— 相鄰兩條的間距是 15+16=31px,給到 44 會互相搶點擊。 */
.spine a {
  position: relative;
}
.spine a::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 44px;
  height: 30px;
  transform: translate(-50%, -50%);
}
.ch {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  /* 內容一超過 100vh,center 會讓它上下對稱溢出 —— 標題就被推到固定頂欄底下
     (實測 390px 下 #hall 標題頂端 64.1px,頂欄底端 60px,只差 4.1px 且蓋在毛玻璃後面)。
     safe 只在溢出時退回 flex-start,沒溢出的板塊跟 center 一模一樣。
     不認得 safe 的瀏覽器會整條丟掉,留在上一行的 center,也就是現在的行為。 */
  justify-content: safe center;
  /* 上下原本共用同一條 clamp(90px, 11vh, 150px)。vh 係數會跟著視窗高度長,
     810x1258 這種窄而高的畫面實測頂距 138.4px —— 是 60px 頂欄的兩倍多,
     一整段空白把面板往下推。拆成上下兩條,只把上緣的係數從 11vh 收到 8vh、
     上限從 150px 收到 120px:810x1258 量到 138.4px 降到 100.6px,
     1920x1080 從 118.8px 降到 86.4px。下緣一個數字沒動,底部留白與卡片高度不變。 */
  padding-block: clamp(64px, 8vh, 120px) clamp(90px, 11vh, 150px);
  padding-inline: clamp(20px, 6vw, 120px);
  padding-left: max(clamp(20px, 6vw, 120px), env(safe-area-inset-left));
  padding-right: max(clamp(20px, 6vw, 120px), env(safe-area-inset-right));
  scroll-snap-align: start;
  scroll-margin-top: 60px;
}
@media (min-width: 1800px) {
  .ch {
    padding-left: max(6vw, calc((100vw - 1720px) / 2));
    padding-right: max(6vw, calc((100vw - 1720px) / 2));
  }
}
/* 進場動畫是 app.js 的 gsap.from(opacity: 0),但那要等 JS 跑完才會把元素設成透明,
   實測(4x CPU 節流)是第 236ms —— 在那之前元素已經整個畫在畫面上了。
   重新整理時瀏覽器會還原捲動位置,使用者剛好正對著某個板塊,看到的就是
   「內容先出現 → 整個消失 → 再淡入」,這就是那些一閃而過的殘影。
   這裡在第一次繪製就先藏好,等 app.js 掛完時間軸再加 .anim-ready 把控制權交回去;
   GSAP 之後寫的是行內樣式,權重比這裡高,所以交還之後這條規則不會再干擾動畫。
   前綴 .js 讓沒有 JS 的環境完全不受影響,index.html 另有一道 1.5s 的保險絲,
   萬一 data.js/gsap 被廣告攔截器擋掉、app.js 提早 return,畫面也不會一直空著。 */
.js:not(.anim-ready) .ch:not(.ch-opening) :is(.ch-head, .door, .g-card, .ledger-col, .rails li, .pots li, .invite, .vip, .prov-wall .sub-title, .prov-wall li, .foot),
/* 板塊 1 沒有進場動畫,但它的文字全是 data-i18n(HTML 裡是空的)、大數字也是 app.js 才生出來,
   所以 20~175ms 之間畫面上是半成品:一個孤零零的「· AURUM」、空按鈕、沒有數字。
   一起藏到 app.js 填完再現形;大數字本來就要等 JS 才存在,這樣不會拖慢主視覺出現的時間。
   藏子元素不藏 .hero-inner 本身:app.js 有一條 scrub 的 gsap.to('.hero-inner', {autoAlpha}),
   autoAlpha 會把 visibility 一起讀進去當起始值,先藏本體會被它記成「起始就是隱形」,
   之後整個主視覺就再也不會出現(實測過,anim-ready 加上去了還是 hidden)。 */
/* auth.html 的每一句文字都是 data-i18n(HTML 裡是空的),區號清單與語言選單也要等 JS 才生出來,
   ?mode=register 的面板切換同樣是 JS 做的 —— 在那之前畫面上是一張沒有字的登入卡:
   輸入框剩三條線、按鈕是一塊金磚、卡片高度只有成品的一半(註冊態 448 對 949),
   等 app.js 填完字整個彈開,這就是重新整理時那一瞬間的殘影。
   跟首頁同一招:第一次繪製就先藏好,initAuth() 把面板、字、區號全部備妥再加 .anim-ready。
   .bar 也要藏 —— 返回鍵的文字與語言選單一樣是空的。 */
.js:not(.anim-ready) body[data-page="auth"] :is(.bar, .auth),
/* 首頁的頂欄也要藏。這一頁進場動畫是最後一支腳本才蓋上來的,在那之前 i18n.js、data.js
   與兩支 gsap 都還在下載,頂欄卻早就畫好了 —— 左上角商標先閃一下、等簾幕落下才消失,
   正是「開場前有東西先出現」的那一下。
   這裡認 .intro-pending 而不是 .anim-ready:.anim-ready 中途會被 app.js 加上一次
   (它要解開章節的預先隱藏),intro.js 得等下一次網路往返才收得回去,實測那個縫是 42ms,
   商標照樣閃得到。.intro-pending 是頁首那支行內腳本第一行就掛上的,一路蓋到動畫收工。 */
.js.intro-pending body[data-page="home"] .bar,
.js:not(.anim-ready) .hero-inner > * {
  /* 用 opacity 不用 visibility:visibility:hidden 會把元素從 Tab 順序和無障礙樹裡
     整個拿掉,螢幕閱讀器連標題都讀不到。透明度的畫面結果完全一樣。 */
  opacity: 0;
}
.ch-head {
  margin-bottom: clamp(24px, 3.6vh, 52px);
}
.ch-title {
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(2.1rem, 4.6vw, 4.2rem);
  line-height: 1.08;
  letter-spacing: .02em;
  text-wrap: balance;
}
.sub-title {
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(1.3rem, 2vw, 1.7rem);
  letter-spacing: .04em;
  margin-bottom: 16px;
}
.gold-text {
  background: linear-gradient(105deg, var(--gold-dim) 0%, var(--gold) 30%, var(--gold-hi) 50%, var(--gold) 70%, var(--gold-dim) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.ch-opening {
  align-items: center;
  justify-content: center;
  text-align: center;
  /* 橫向照舊切齊 —— 320 的大數字會超出板塊。縱向改成不切:右下那道光的圓心壓在
     板塊的下緣上,有一半本來就在板塊外面,切掉會在接縫處留一條橫線。
     clip 配 visible 是允許的組合;hidden 配 visible 會被瀏覽器改寫成 auto,
     那等於多開一個捲動容器。 */
  overflow-x: clip;
}
/* 全站只有兩個地方有環境光:首頁第一屏,以及登入後面板的第一段。兩處都是「門面」,
   其餘九頁與其餘板塊一律純 --bg。光鋪滿全站的版本試過了 —— 每一頁都亮著同一組角落光,
   它就不再是重點,只是背景噪音;而且那層是 fixed,捲過任何一道板塊接縫都要另外拿
   不透明底去擋,擋光層自己又在接縫處露出邊。收成一屏一層,兩個問題一起消失。
   兩道:大的在右上,中的在左下。對角線上一盞主光一盞補光,另外兩角留空 ——
   角落點得越多越像一個對稱的框,空著才看得出光是有來向的。左上原本還有一盞
   最小的(11vw + 7vh、濃度 .06),拿掉了:它離右上那盞太近,兩圈在上緣接在一起,
   反而把「一盞主光」讀成「一條沿著上緣的亮帶」。
   兩道都是正圓,不是橢圓。半徑寫 circle 加一個長度,不寫百分比 —— 百分比在
   radial-gradient 裡是分別對著層的寬與高解析的,兩軸不同就必然拉成橢圓,
   而橢圓看起來是被壓扁的光斑,不是一盞燈。
   半徑用 calc(Nvw + Mvh):單一個 vw 在窄高的手機上會縮到看不見,單一個 vh 在寬扁的
   桌機上會漲到滿版,兩軸各出一份才在 320 到 1920 之間都是同一個相對大小。
   大小刻意拉開,半徑約 2 : 1,面積約 4 : 1;右上那盞的濃度也比左下高一截
   (.15 對 .085),它是主光,左下是補光:
     右上 可見半徑 29.6vw + 20.3vh(1440x900 量到 609px),偏白的 --gold-hi,
          濃度 .15,衰減收在 78%。圓心不貼死在角上,往左往下各退 3vw + 2vh
          (1440x900 是 61px,約可見半徑的一成):光斑整個離開直角,亮處落在角內側,
          看起來是一盞掛在牆上的燈而不是從畫布邊緣漏進來的。半徑、濃度、衰減
          都沒動,形狀跟原本一模一樣,只是位置換了;
     左下 14.8vw + 9.8vh(301px),偏深的 --gold,濃度 .085,衰減收在 82%。
   兩個衰減不一樣,邊界不會收在同一個半徑上;兩盞之間隔著一整段暗帶,
   看得出是兩盞不同的燈,不是一片鋪滿的底色。
   光畫在偽元素上不畫在板塊的 background 上:background 只會畫在邊框盒裡,
   溢不出板塊;而左下那道的圓心就壓在板塊下緣,整個下半圓得落到下一屏才是圓的。
   往下多鋪的那一截就是左下那道的可見半徑(15vw + 10vh,比 14.8vw + 9.8vh 多一點點
   餘裕),圓弧在層的內部收乾淨,捲過交界看到的是光自己散掉,不是被切一刀。
   圓心用 bottom 那一側定位(at left 0px bottom <多鋪的量>),不用百分比:
   多鋪的量是長度,層高就不再是板塊高的固定倍數,百分比會跟著飄。
   百分比是這一層的尺寸(板塊高的 1.22 倍),所以板塊下緣落在 82% 上。
   用 --gold-hi / --gold 的字面值不用 var():這份檔案裡 rgba() 一律寫 rgb 三元組。 */
.ch-opening::after {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: calc(-15vw - 10vh);
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(circle calc(38vw + 26vh) at right calc(3vw + 2vh) top calc(3vw + 2vh), rgba(243, 223, 154, .15), transparent 78%),
    radial-gradient(circle calc(18vw + 12vh) at left 0px bottom calc(15vw + 10vh), rgba(212, 175, 55, .085), transparent 82%);
}


/* 全頁共用一道光束:fixed 貼在視窗上,捲到哪個板塊都掃得到,也不會在板塊邊界斷開。
   別改成 absolute 想「跟著文件拉滿五個板塊」:skewX 的橫移量是離中心的垂直距離乘 tan15°,
   拉到 5 個視窗高會整條甩出頁面外,反而有些板塊看不到。fixed 才是真的不斷。
   質感靠兩層漸層疊出來:窄而亮的核(高光)壓在寬而極淡的暈(空氣感)上。
   單層直接拉亮會變成一塊會動的金色色塊,所以寧可核亮、暈淡。
   垂直方向刻意不做衰減 —— 之前用橢圓漸層收上下,結果光束只剩畫面中間一小截,看起來很短。
   傾斜交給 skewX,漸層用 90deg 就好,這樣每個高度的光束寬度一致,是一條直的光柱。
   兩層都塞進同一個 ::before:實測拆成 ::before + ::after 兩個合成層,iPhone p95 會從 16.7 掉到 33.3ms;
   改用 mask-image 做衰減更慘,iPhone 掉到 50ms/幀。 */
.beam {
  position: fixed;
  inset: 0;
  /* 41 = 壓在 .bar(40) 之上,頂欄也要一起被掃到;仍低於 .contact(45)/dock(50)/彈窗(90) */
  z-index: 41;
  overflow: hidden;
  pointer-events: none;
}
.beam::before {
  content: '';
  position: absolute;
  top: -15%;
  bottom: -15%;
  left: 0;
  width: 34%;
  background:
    linear-gradient(90deg, rgba(255, 250, 232, 0) 43%, rgba(255, 250, 232, .05) 47%, rgba(255, 252, 240, .18) 50%, rgba(255, 250, 232, .05) 53%, rgba(255, 250, 232, 0) 57%),
    linear-gradient(90deg, rgba(212, 175, 55, 0) 4%, rgba(212, 175, 55, .022) 26%, rgba(233, 206, 141, .075) 50%, rgba(212, 175, 55, .02) 74%, rgba(212, 175, 55, 0) 96%);
  transform: translateX(-84vw) skewX(-15deg);
  will-change: transform;
  animation: sweep 12.5s cubic-bezier(.5, .04, .3, 1) infinite;
}
@keyframes sweep {
  0%, 6% { transform: translateX(-84vw) skewX(-15deg); }
  62%, 100% { transform: translateX(168vw) skewX(-15deg); }
}
.ch-opening::before {
  content: '';
  position: absolute;
  left: 50%;
  top: 44%;
  width: min(90vw, 1100px);
  height: 46vh;
  transform: translate(-50%, -50%);
  background: radial-gradient(50% 50% at 50% 50%, rgba(212, 175, 55, .09), transparent 70%);
  pointer-events: none;
}
.hero-inner {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(20px, 3.4vh, 34px);
  /* 整組往上讓一截:板塊是置中的,下外距加多少整組就上移一半;溢出時(橫放手機)
     板塊退回 flex-start,這截就變成按鈕列跟下緣之間的留白,不會貼到機身底。 */
  margin-bottom: clamp(24px, 6vh, 56px);
}
.jack-label {
  font-size: clamp(12px, .95vw, 15px);
  letter-spacing: .48em;
  margin-right: -.48em;
  text-transform: uppercase;
  color: var(--gold);
}
.jack-label b {
  font-weight: 400;
  color: var(--ink-dim);
}
.jack {
  display: flex;
  /* 格子與點都改成同高同 line-height,置中對齊兩者基線才會重合;
     baseline 對 overflow:hidden 的 inline-block 是取下邊緣,格子一加高點就會掉下去。 */
  align-items: center;
  justify-content: center;
  /* 錯落是 --serif 自己給的:Cormorant Garamond 的預設數字就是舊式數字,
     3/4/5/7 下伸、8 上伸,不必外掛第二套字。曾改掛 Rosarivo 來換筆畫厚度,
     但它 10 顆數字只有 225 個輪廓段(Cormorant 313),12.5rem 放大後
     曲線節點變成肉眼可見的稜角。 */
  font-family: var(--serif);
  /* 壓在 wght 軸上限 700:這支是可變字體(300-700),600 以下字幹在 12.5rem
     撐不起燙金漸層,700 才有面積讓高光到深影鋪得開。不會有合成假粗體。 */
  font-weight: 700;
  /* --u 是版面單位,不是字級。格寬/格高/分隔/光暈全部改吃 --u,
     所以下面那些 .54 / 1.32 / .3 / .14 都還是原本的數,整排的外框像素一格沒動。
     字級另外乘 1.09:Cormorant 的數字字身比 Rosarivo 小一截,同字級下會縮水。
     上限由格寬定死 —— 等寬進距 .491em 必須塞得進 .54u 的格子,.491k <= .54
     解出 k <= 1.0998,取 1.09。超過就是進距比格子寬,置中之後兩側一起溢出,
     被 .cell 的 overflow:hidden 切掉,十顆數字全部右邊缺一塊(不是只有最後一顆)。
     1.09 之下墨跡頂端 138.3px,原本 Rosarivo 是 137.5px —— 比原本大,沒有變小。 */
  /* 放大只准動 --u,不准動下面那個 1.09 —— 那是等寬進距 .491em 塞進 .54u 格子解出來的
     上限,調高就是進距比格子寬,十顆數字全部被 .cell 的 overflow 切掉右邊。
     --u 一動,格寬、格高、分隔、光暈全部等比跟著走,比例一格沒變。
     上限 12.5rem 提到 14rem:1667px 以上 --u 被上限釘住,原本只佔內容寬的 74.6%,
     整排在大螢幕上明顯偏小 —— 14rem 讓它回到 80.6%,跟中間尺寸同一個量級。
     下限 2.8rem 一個數字沒動:373px 以下靠它撐著。

     中間那一段拆成兩支,原因是窄屏跟寬屏的按鈕根本不是同一種東西。
     560px 以下兩顆主按鈕各吃半行(見下面 .hero-ctas .btn-gold 的 flex:1 1 0),
     整條按鈕列就等於 .ch 的內容寬 = 100vw - 2×6vw = 88vw;12.6vw 的老值算出來
     整排只有 79.4vw,比按鈕列短了快一成,獎池反而縮在按鈕裡面。
     窄屏那支照內容寬回推:整排寬 6.3u 要等於 88vw 再多 10px,兩端各超出按鈕 5px,
     那 10px 落在 20px 起跳的內距裡,沒有推大捲動寬度。
     寬屏那支維持 12.6vw —— 560px 以上按鈕是照字長撐的一小段(量到 268px),
     獎池本來就是它的四倍寬,沒有對齊的問題,不動。
     兩支用 max(A, min(B, C)) 接起來,不用斷點:B 是窄屏那支、A 是 12.6vw、
     C = 79.8px 正好是 A 在 560px 的值。B 漲到 C 就停在 C,A 追上 C 之後換 A 接手,
     三段在交接點同值,拉動視窗寬度時整排是連續放大的,不會在某一格跳一下。 */
  --u: clamp(2.8rem, max(12.6vw, min(calc((88vw + 10px) / 6.3), 79.8px)), 14rem);
  font-size: calc(var(--u) * 1.09);
  /* 等寬數字:Cormorant 的 tnum 對到 .tosf,是「等寬的舊式數字」,上下伸一點沒少
     (+.661/-.275,和預設同值),錯落完全保留。要它有兩個理由:
     一是預設進距 .332~.489em 落差極大,置中是按進距算的,寬的那幾顆(0/6/8)
     墨會被推出 .54u 的格子外被裁掉;二是輪帶滾動時每顆數字寬度一致,不會左右抖。 */
  font-variant-numeric: tabular-nums;
  line-height: 1;
  text-rendering: geometricPrecision;
}
@supports (-webkit-background-clip: text) {
  /* 漸層要掛在單顆數字上,不能掛在 .col。.col 是 10 顆數字的整條輪帶,
     漸層一鋪滿 10 顆,每顆拿到的就是自己「值」對應的那一段:0 拿奶白、9 拿暗金,
     同一排數字顏色深淺全亂。掛到 span,每顆才都是完整的同一條金漸層。 */
  .jack .col span, .jack .sep {
    /* 高光拉到近白(#fffefa)。亮的那一段從前 15% 放寬到前 40%,中段仍是飽和金、
       底部留 --gold-dim 的深影 —— 整段一起提亮會變成淡金,貴氣是靠上下反差撐的。
       連同光暈一起量:整塊大獎的平均亮度 41.9 → 46.0、最亮 242.4 → 250.5,
       亮的是上半與外圈的泛光,底部那道深影一格沒動。 */
    background: linear-gradient(180deg, #fffefa 0%, #fefaea 20%, #faeec2 40%, #f3dd93 58%, var(--gold) 80%, var(--gold-dim) 100%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
}
/* 1em 裝不下這組數字的字身(Cormorant 實測 1.21em):舊式數字的下伸部被裁掉,
   輪帶上下顆數字還會從上緣露進來。放到 1.32em 才完整包住,
   轉盤位移是百分比(-n*10%),格高等比放大不影響定位。
   line-height 另外壓到 1.0545u,不跟格高同值:Cormorant 的 hhea 很不對稱
   (ascent .924em / descent .287em),line-height 一等於格高,基線就被推到
   格子偏下的位置 —— 上面空 38px、下伸部卻直接撞格底被裁掉。壓低 line-height
   等於把整條基線往上提,墨跡才置中,實測 0-9 十顆全部離格邊有餘裕。
   外光暈不畫在文字上:.cell 有 overflow:hidden,光暈掛在裡層會被裁掉;
   filter 是在裁切之後才作用,掛在外層(見下面的 .jack)才能往外擴散。 */
.jack .cell, .jack .sep {
  height: calc(var(--u) * 1.32);
}
/* 光暈掛在整排 .jack 上,不掛在每一格 .cell 上:一格一團光,每團都是那一格的方框
   往外攤,相鄰兩格的光在接縫處各自有一條直的邊,3x 截圖看得到整排被切成十二塊
   (橫放手機最明顯,--u 大、光也大)。掛到整排上是一團連續的光,而且只算一次模糊。
   .cell 的 overflow:hidden 在裡層,先裁再發光,輪帶上下顆數字不會透出來。 */
.jack {
  /* 只用一層 drop-shadow:兩層就是兩次模糊,實測桌機轉盤滾動時中位幀從 16.7 掉到 33.3ms。
     光暈不能用 text-shadow 做 —— text-shadow 畫在文字層,會被 .cell 的 overflow 裁成方框,
     而且它疊在漸層填色之上,會把燙金的深淺洗平。filter 是裁切之後才作用,兩個問題都沒有。
     半徑 .14u 放到 .19u、顏色吃滿不透明:光往外多攤開約四成,遠處明顯更亮,
     筆畫邊上那一圈幾乎沒有掉。
     只有一層可以調的就這兩個數,而它們是互相拉扯的 —— 同樣的光攤得越開,近處就越薄。
     實測 1440 下四組(.19/1、.21/1、.24/1、.21/.95)貼著筆畫 1-4px 的平均亮度分別是
     55.1 / 53.1 / 50.8 / 51.7,原值是 56.0;.19 配滿不透明是唯一一組近處守得住、
     遠處又拉得開的:10-20px 34.3→37.1、20-35px 23.4→27.8、35-60px 14.7→17.7。
     再往外攤(.21、.24)遠處只多一點點,近處就開始掉了。 */
  filter: drop-shadow(0 0 calc(var(--u) * .19) #f0d48c);
  /* iOS 上這團光只能走合成層,不能走軟體重繪:滾動時 .col 的 transform 讓 WebKit 把整排
     提成合成層,滾完又拆掉、退回軟體畫;軟體路徑的 filter 只重繪髒掉的那幾格,
     光暈在髒區左右兩緣被切成兩條直線,橫豎屏都看得到。will-change 把層釘住,整排
     每一幀都是一次算完,沒有髒區接縫。
     合成層上的 drop-shadow 只畫到層框為止,所以框用內距撐到光暈以外(半徑 .19u,
     三倍即散盡,橫向 .7u、縱向 .5u 都有餘),再用同值負外距抵回去,版面一格沒動。 */
  will-change: filter;
  padding: calc(var(--u) * .5) calc(var(--u) * .7);
  margin: calc(var(--u) * -.5) calc(var(--u) * -.7);
}
/* 手機上這團光看起來是暗的,原因不是比例 —— 模糊半徑綁在 --u 上,佔字身的比例每個
   寬度都是 12.84%,桌機手機一模一樣。問題是絕對值:390 下 --u 只有 46.8px,半徑
   6.55px,光緊貼著筆畫,看起來是一圈描邊而不是一團泛光。所以這裡兩件事一起做 ——
   透明度再往上加,半徑給一個地板。
   地板用 max() 不用寫死:760 的 --u 乘 .19 是 18.2px,本來就大於 15px,max() 會挑
   原本那個值,斷點兩側連續,不會在 761px 跳一下。
   仍然只有一層 drop-shadow —— 上面那段註記量過,疊成兩層桌機轉盤中位幀 16.7 掉到 33.3ms。 */
@media (max-width: 760px) {
  .jack {
    filter: drop-shadow(0 0 max(15px, calc(var(--u) * .19)) #f0d48c);
  }
}
.jack .cell {
  display: inline-block;
  width: calc(var(--u) * .54);
  overflow: hidden;
  text-align: center;
  /* 窗口上下緣各 .09u 淡出:滾動時上一顆離場、下一顆進場,切在格邊上是一條硬邊,
     淡出之後是自然隱沒。.09u 碰不到靜止的墨跡 —— 十顆數字量過,墨離格邊最近的
     是 3/7/9 的下伸部,.114u;上面最近的是 6,.153u。 */
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 calc(var(--u) * .09), #000 calc(100% - var(--u) * .09), transparent);
  mask-image: linear-gradient(to bottom, transparent, #000 calc(var(--u) * .09), #000 calc(100% - var(--u) * .09), transparent);
}
.jack .col {
  display: flex;
  flex-direction: column;
  transition: transform var(--t-slow) var(--ease);
}
.jack .col span {
  height: calc(var(--u) * 1.32);
  line-height: calc(var(--u) * 1.0545);
  /* 滾動時上面那顆淡出、下面那顆淡入,跟位移同一段時間;離場的墨跡到窗口邊緣時
     已經接近透明,配合 .cell 的遮罩,邊上不會留一條硬邊。 */
  opacity: 0;
  transition: opacity var(--t-slow) var(--ease);
}
.jack .col span.on {
  opacity: 1;
}
.jack .sep {
  width: calc(var(--u) * .3);
  line-height: calc(var(--u) * 1.0545);
  text-align: center;
}
.hero-sub {
  /* 這是全頁唯一的 h1。UA 的 h1 預設 bold,字級被下一行蓋掉了,字重要另外釘回 body 的 300 */
  font-weight: 300;
  text-align: center;
  font-size: clamp(13px, 1.05vw, 16px);
  margin-top: clamp(8px, 3vh, 38px);
  letter-spacing: .22em;
  color: var(--ink-dim);
  text-transform: uppercase;
  max-width: 44ch;
  text-wrap: balance;
}
/* 副標是兩句話,一句一行,中間夾一行只有一個間隔點的窄行 —— 三行。點寫在 CSS
   不寫進譯文:它是版面的分隔記號不是句子的一部分,四個語系共用同一個,譯文裡也不必各寫一次。
   字距 .22em 在行尾會多出一格空白,行內把它扣回來才是真的置中。 */
.hero-sub span {
  display: block;
  margin-right: -.22em;
}
/* 點那一行的行高比正文兩行短一截(1.15 對 1.6):它的工作是把兩句話分開,
   不是自己佔一整行。
   字級 1.25em 配行高 .92 —— 兩個相乘還是 1.15em,行盒高度跟原本一模一樣,
   點放大不會把下面的按鈕再往下推。字重 600:Jost 的粗體間隔點明顯厚一截,
   量到的墨點從 1.33px 長到 3.00~3.67px,在滿版留白裡才看得見。
   top: -.07em 是量出來的:間隔點坐在基線上方約 .33em,行盒卻是照 em 盒置中的,
   em 盒下半的降部空間大寫字母永遠用不到,所以不校正的話上緣空隙比下緣多 3px。
   校正後 320/390/768/1440/1920 五個寬度的上下空隙差都在 1.3px 以內。 */
.hero-sub span + span::before {
  content: '\00b7';
  display: block;
  font-size: 1.25em;
  font-weight: 600;
  line-height: .92;
  position: relative;
  top: -.07em;
  color: var(--ink-faint);
}
.hero-ctas {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 16px 22px;
  /* 副標從一行變三行,多出來的高度全部放到它下面 —— 上半(獎池、副標)是讀的,
     下半(兩顆按鈕、在線人數)是點的,兩者之間拉開才分得出哪裡是一段的結束。 */
  margin-top: clamp(10px, 2.4vh, 28px);
}
/* 三樣擠在一行時,兩顆主按鈕會被在線人數推得左右不對稱,人數自己也貼到最右邊。
   人數改吃滿整行落到第二行,按鈕那行就只剩兩顆、對稱置中 —— 每個寬度都同一個版型。 */
.hero-ctas .online {
  flex-basis: 100%;
  justify-content: center;
}
.hero-ctas .btn-gold, .hero-ctas .btn-ghost {
  font-size: 12px;
  padding: 1em 2.3em;
}
/* 在線人數是首屏唯一的「現在」—— 獎池是累計數、副標是定位語,只有這一行說的是此刻。
   原本 12/13px 跟頁尾的細字同級,在 12.5rem 的獎池底下小到看不見。整組等比放大一級:
   字 14、數字 16、點 7,行距與間距跟著 em 走,所以四個語系與五個寬度都同一個比例。 */
.online {
  display: inline-flex;
  align-items: center;
  gap: .7em;
  font-size: 14px;
  letter-spacing: .14em;
  color: var(--ink-dim);
}
/* 數字比標籤亮一級,但不到 --ink 的滿亮 —— 在一片近黑的首屏上,#e9e2d0 的等寬數字
   是除了獎池以外最亮的一塊,眼睛會先被它接走。#c3baa2 剛好落在 --ink 與 --ink-dim
   中間:仍然看得出「數字是重點、後面那串字是說明」,但不再跟獎池搶。 */
.online b {
  font-family: var(--mono);
  font-weight: 400;
  color: #c3baa2;
  font-size: 16px;
}
.dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--ok);
  box-shadow: 0 0 7px rgba(63, 174, 90, .8);
}
.scroll-cue {
  position: absolute;
  left: 50%;
  bottom: clamp(8px, 2.2vh, 24px);
  z-index: 6;
  display: grid;
  justify-items: center;
  align-content: end;
  gap: 6px;
  width: 54px;
  height: 46px;
  margin-left: -27px;
  color: var(--gold);
  filter: drop-shadow(0 0 5px rgba(212, 175, 55, .65)) drop-shadow(0 0 16px rgba(212, 175, 55, .3));
  opacity: 0;
  transition: opacity .5s var(--ease), color var(--t-fast) var(--ease);
}
.scroll-cue::before {
  content: '';
  width: 1px;
  height: 22px;
  background: linear-gradient(to bottom, rgba(212, 175, 55, 0), currentColor);
}
.scroll-cue::after {
  content: '';
  position: absolute;
  inset: -16px -8px -14px;
  background: radial-gradient(50% 50% at 50% 60%, rgba(212, 175, 55, .22), transparent 70%);
  opacity: 0;
  transition: opacity var(--t) var(--ease);
  pointer-events: none;
}
.scroll-cue svg {
  display: block;
  width: 22px;
  height: 8px;
}
/* 只有 .on 那一顆是「還可以往下」的邀請。其餘每屏各有一顆,opacity 走的是關鍵影格,
   不掛 .on 就停在 0 —— 但 opacity 為 0 的按鈕照樣進 Tab 序、照樣吃點擊。
   Tab 到看不見的東西上是壞的,visibility 一次收掉命中測試與焦點序,
   而可見那一顆的呼吸由 animation 給,不靠 transition,所以收起來不會吃掉淡出。 */
.scroll-cue:not(.on) {
  visibility: hidden;
}
.scroll-cue.on {
  animation: cueBreath 2.8s ease-in-out .35s infinite;
}
.scroll-cue.on::after {
  opacity: .5;
}
.scroll-cue:hover {
  color: var(--gold-hi);
  filter: drop-shadow(0 0 6px rgba(243, 223, 154, .85)) drop-shadow(0 0 20px rgba(212, 175, 55, .45));
}
.scroll-cue:hover::after {
  opacity: 1;
}
/* 換屏途中把 cue 收掉(app.js 的 setGliding 掛 .gliding)。它是「還可以往下」的邀請,
   人已經在路上就不必再邀;而且下一屏的 cue 在行程過半時被點亮,不收的話會半路冒出來。
   要連 animation 一起關 —— .scroll-cue.on 的可見度整個是 cueBreath 的關鍵影格在給,
   只寫 opacity 會被動畫蓋掉。 */
html.gliding .scroll-cue {
  animation: none;
  opacity: 0;
}
@keyframes cueBreath {
  0%, 100% { opacity: .35; transform: translateY(0); }
  46% { opacity: 1; transform: translateY(5px); }
}
/* 分隔線原本是「容器鋪 --line-soft 當底 + 1px gap 讓底色透出來」。
   問題是 .door 進場時 autoAlpha 從 0 起跳,整條容器底色就整塊露出來變成一條土黃帶。
   改成:容器底色換成頁面色(露也只露頁面色),分隔線掛到 .door 自己的 border-right。
   外框顏色從 .13 提到 .243:原本框線位置是「底色 .13 + 邊框 .13」兩層疊出來的,
   拿掉底色後要用單層等效值補回去,才跟改之前一模一樣(實測亮度 47,內線 29)。 */
/* 門排列的是十五家供應商，寬螢幕也排不成一列網格，所以每個寬度都是橫捲條。
   貼齊到中線，不是左緣：左緣對齊的話正在看的那張永遠貼在最左邊，右邊露半張、
   左邊什麼都不剩 —— 看起來像捲到頭了。中線對齊之後兩端各露半張，「還有」這件事
   兩個方向都說得出來，而選中的那張就在拇指正上方。
   兩端不必補留白：第一張與最後一張的理想中線落在可捲範圍外，瀏覽器會夾回 0 與
   最大值，那兩張自然貼邊。 */
.doors {
  position: relative;
  display: flex;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  background: var(--bg);
  border: 1px solid rgba(212, 175, 55, .243);
}
.door {
  position: relative;
  display: flex;
  flex: 0 0 clamp(180px, 15vw, 240px);
  flex-direction: row;
  align-items: center;
  justify-content: flex-start;
  gap: clamp(10px, 1.1vw, 18px);
  min-height: clamp(46px, 6vh, 62px);
  /* 右內距要放得下三位數的款數。分類門那時候放的是單字羅馬數字，窄得多。 */
  padding: 6px clamp(40px, 3.4vw, 54px) 6px clamp(14px, 1.3vw, 22px);
  background: var(--bg);
  border-right: 1px solid var(--line-soft);
  scroll-snap-align: center;
}
/* :last-of-type 不是 :last-child —— 橫捲提示(.hcue)是接在門排最後面的兩個 <span>,
   用 :last-child 的話最後一道門就不再是末子,右邊那條分隔線會冒回來,序號跟著左移 1px。
   門在首頁是 <a>、在大廳是 <button>,兩邊都只有這一種元素,認型別就選得準。 */
.door:last-of-type {
  border-right: 0;
}
/* hover 原本只有 ::after 這層底光,而且只有底光 —— 文字、圖示、序號的顏色一動不動。
   實測整格平均亮度只從 16.8 抬到 35.2,眼睛卻是盯著標籤看的,標籤沒變化就等於沒回饋。
   底光從 .16 提到 .3、漸層界線從 60% 拉到 72%,再讓標籤與圖示提到 --gold-hi、
   序號從 --gold-dim 提到 --gold。轉場掛在子元素上,不掛 .door 自己 ——
   .door 的 opacity 是 enter() 的 GSAP tween 逐幀在寫的,給它 transition-duration
   會在減動下被全域規則塞進 opacity,把整組進場拖慢(見 prefers-reduced-motion 區塊)。 */
.door::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(212, 175, 55, .3), transparent 72%);
  opacity: 0;
  transition: opacity var(--t) var(--ease);
  pointer-events: none;
}
/* .on 只有大廳第一屏的分類鈕會用到(首頁的 .door 是 <a>,不帶狀態);
   作用中的樣子與 hover 一致,不另外發明一種選中態。 */
.door:hover::after, .door.on::after {
  opacity: 1;
}
.door:hover .door-name, .door.on .door-name {
  color: var(--gold-hi);
}
.door:hover .prov-ico b, .door.on .prov-ico b {
  color: var(--gold-hi);
}
.door:hover .door-num, .door.on .door-num {
  color: var(--gold);
}
/* 首頁門排第一顆「人氣」:廠標位放的是大廳側欄同一顆方格圖示。 */
.door-all .prov-ico i {
  font-size: 20px;
  color: var(--gold);
  transition: color var(--t-fast) var(--ease);
}
.door-all:hover .prov-ico i {
  color: var(--gold-hi);
}
.door-num {
  position: absolute;
  top: 50%;
  right: clamp(8px, .7vw, 13px);
  transform: translateY(-50%);
  font-family: var(--serif);
  font-style: italic;
  font-size: 12px;
  color: var(--gold-dim);
  transition: color var(--t-fast) var(--ease);
}
/* 方形廠標。<b> 是底稿，<img> 疊在它上面把它蓋掉；圖載不進來 onerror 自拆，
   底稿自然露出來，所以缺圖的那幾家還是看得到兩個字母，不會開一塊空白。
   跟遊戲卡的 .g-mark + 封面是同一個做法。 */
.prov-ico {
  position: relative;
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: clamp(26px, 2vw, 34px);
  height: clamp(26px, 2vw, 34px);
}
.prov-ico b {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 600;
  font-size: 13px;
  color: var(--gold);
  transition: color var(--t-fast) var(--ease);
}
.prov-ico img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
/* 圖標是去背 WebP，透明的地方會把底稿那兩個字母透出來，所以有圖就把底稿收掉。
   載入失敗時 app.js 的 onerror 把 <img> 整個移除，這條選擇器跟著失效，字母自己回來
   —— 跟 .g-art:has(.g-cover) .g-mark 同一個機制，不必再寫 JS 去切 class。 */
.prov-ico:has(img) b {
  display: none;
}
.door-name {
  font-family: var(--serif);
  font-weight: 600;
  font-size: clamp(1rem, 1.28vw, 1.3rem);
  line-height: 1.15;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: color var(--t-fast) var(--ease);
}
.spotlight {
  margin-top: clamp(24px, 3.4vh, 52px);
}
/* 自己捲的容器一律不要原生捲軸。桌面瀏覽器縮到窄屏時那條是 15px 的實心捲軸,壓在
   門卡下緣、把整排切掉一截,而這幾處要的手感是用手指撥、用滑鼠拖(見 app.js 的
   dragScroll())。還捲不捲得動由兩端的 .hcue 報 —— 目錄側欄是直的、用不上 .hcue,
   靠切在邊上的半張項目自己說。 */
.doors, .pnl-nav, .pnl-table-wrap, .rail {
  scrollbar-width: none;
}
.doors::-webkit-scrollbar,
.pnl-nav::-webkit-scrollbar,
.pnl-table-wrap::-webkit-scrollbar,
.rail::-webkit-scrollbar {
  display: none;
}
/* 原生捲軸收掉之後,鍵盤使用者在這兩條橫捲容器裡唯一的位置提示就剩焦點框,而全站的
   焦點框是外擴 3px —— 橫捲容器的 overflow-x:auto 讓瀏覽器把 overflow-y 一併解析成
   auto,項目高度又只比容器矮 1px,外擴的那圈上下兩邊等於全被裁掉;右邊則被下一個
   項目的不透明底色蓋住(兄弟在文件順序上較晚繪製)。改成內縮 2px,框畫在項目自己的
   盒子裡,四邊都不會被裁也不會被蓋。 */
.door:focus-visible,
.pnl-nav .rl:focus-visible {
  outline-offset: -2px;
}
/* ── 橫向捲動的兩端提示 ──────────────────────────────
   分類門排、金庫的橫向目錄列、三張資料表格在窄屏都是橫捲容器。原本唯一的訊號是
   「最後一個項目露半截」,表格連這個都沒有,看起來就是一張被切掉右半邊的表。
   兩端各放一個零寬的黏性元素:一道往內壓暗的漸層加一枚金色角標,只有那個方向
   真的還捲得動時才亮(can-l / can-r 由 app.js 的 hcue() 依 scrollLeft 掛上)。
   不用 mask-image:.beam 那邊實測在 iPhone 上會掉到 50ms/幀。
   零寬 + sticky 就不必替每個容器多包一層 div —— .doors 在桌機是七欄網格、
   .pnl-nav 在桌機是黏性側欄,多一層盒子會把欄數與黏性一起弄壞。 */
/* 門排在每個寬度都橫捲，兩端提示跟著全寬度亮 —— 其餘幾個橫捲容器仍然只在窄屏。 */
.doors > .hcue {
  display: block;
}
.hcue {
  display: none;
  position: sticky;
  flex: 0 0 0;
  width: 0;
  align-self: stretch;
  z-index: 4;
  pointer-events: none;
}
/* 兩個提示都接在 DOM 最後面(見 app.js 的 hcue():接在前面會把兄弟的 nth-child
   全部位移一格,普查按路徑認元素,整棵子樹會被判成刪掉再加回)。但黏性的 left 只會
   把元素往右推,不會把它從內容尾端拉回可視左緣 —— 靠 order 讓它在排版上排到最前面,
   靜止位置回到內容起點,left: 0 才咬得住。三個容器在窄屏都是 flex,order 一律吃得到。 */
.hcue-l {
  left: 0;
  order: -1;
}
.hcue-r {
  right: 0;
}
.hcue::before,
.hcue::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  opacity: 0;
  transition: opacity .3s var(--ease);
}
.hcue::before {
  width: 52px;
}
/* 前 45% 幾乎不透光:角標就站在那一段上,漸層要是從邊緣就開始淡,底下那半個門卡的
   字會跟角標疊在一起,兩個都看不清。 */
.hcue-l::before {
  left: 0;
  background: linear-gradient(to right, rgba(7, 6, 4, .95), rgba(7, 6, 4, .78) 45%, rgba(7, 6, 4, 0));
}
.hcue-r::before {
  right: 0;
  background: linear-gradient(to left, rgba(7, 6, 4, .95), rgba(7, 6, 4, .78) 45%, rgba(7, 6, 4, 0));
}
.hcue::after {
  top: 50%;
  bottom: auto;
  width: 8px;
  height: 8px;
  border: solid var(--gold);
  border-width: 1.1px 1.1px 0 0;
}
.hcue-l::after {
  left: 13px;
  transform: translateY(-50%) rotate(-135deg);
}
.hcue-r::after {
  right: 13px;
  transform: translateY(-50%) rotate(45deg);
}
.can-l > .hcue-l::before,
.can-l > .hcue-l::after,
.can-r > .hcue-r::before,
.can-r > .hcue-r::after {
  opacity: 1;
}
/* 角標不只是提示,滑鼠與觸控都點得到:讓 ::before 那條 52px 的漸層帶接下指標事件。
   虛擬元素的命中會歸給宿主 <span>,所以 click 掛在 .hcue 上就收得到(見 app.js 的 hcue())。
   只有那個方向真的還捲得動時才接手 —— 另一端仍然完全透明也點不到,不會偷走門卡的點擊。
   外觀一格沒動:接手的就是原本畫在那裡的漸層,沒有新增任何看得見的東西。 */
.can-l > .hcue-l::before,
.can-r > .hcue-r::before {
  pointer-events: auto;
  cursor: pointer;
}
/* 滑鼠拖著捲的時候不要選到字,游標換成抓握。 */
.dragging {
  user-select: none;
  -webkit-user-select: none;
}
/* 拖曳跟放手之後的滑行都要先關掉貼齊:門排在窄屏是 scroll-snap-type: x mandatory,
   而這兩段都是一幀一幀寫 scrollLeft,每寫一次就被貼齊點拉回門卡邊上 —— 拖起來是
   一格一格跳的,滑行則等於沒發生。滑行自己會收在貼齊點上(app.js 的 snapNear()),
   class 拿掉的那一刻不會再跳一次。
   選擇器要寫兩次:貼齊那條規則在 @media (max-width: 600px) 裡、位置比這裡晚,
   單一 class 打不過它(權重同分時後者勝),實測滑行整段都還在被貼齊點拉,
   662px 的門排只走得到 186 -> 326 -> 467 三個值。 */
.dragging.dragging,
.coasting.coasting {
  scroll-snap-type: none;
}
.dragging, .dragging * {
  cursor: grabbing;
}
/* 第一眼的邀請:右端角標推三下就停。畫面邊上留一個永遠在動的東西比沒有提示更煩。 */
.can-r > .hcue-r::after {
  animation: hcueNudge 1.5s var(--ease) 3;
}
@keyframes hcueNudge {
  0%, 60%, 100% { transform: translateY(-50%) rotate(45deg); }
  30% { transform: translate(4px, -50%) rotate(45deg); }
}
/* 表格容器本來是普通區塊,改成 flex 才放得進兩端的黏性提示。表格自己是
   width: 100% + min-width: 640px,兩種排版算出來的用寬一樣。 */
.pnl-table-wrap {
  display: flex;
}
.pnl-table-wrap > .hcue {
  display: block;
}
/* 門排與目錄列只有一列高,角標釘在垂直中線正好;表格容器有整張表那麼高(390px 下
   量到 1179px),中線落在畫面外。這裡改成貼齊表頭那一列 —— 進到表格第一眼就看得到。 */
.pnl-table-wrap > .hcue::after {
  top: 21px;
}
.spot-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  --sg-gap: clamp(12px, 1.3vw, 20px);
  gap: var(--sg-gap);
}
#hall .doors {
  flex: 0 0 auto;
}
#hall .spotlight {
  flex: 1 1 auto;
  min-height: 0;
  margin-top: clamp(12px, 1.6vh, 22px);
  display: flex;
  flex-direction: column;
}
#hall .spot-grid {
  flex: 1 1 auto;
  min-height: 0;
  grid-template-rows: repeat(2, minmax(0, 1fr));
}
#hall .spot-grid .g-card {
  display: flex;
  flex-direction: column;
  min-height: 0;
}
#hall .spot-grid .g-art {
  aspect-ratio: auto;
  flex: 1 1 auto;
  min-height: 0;
}
#hall .spot-grid .g-meta {
  padding: 10px 12px 11px;
}
#hall .spot-grid .g-mark {
  font-size: clamp(2.4rem, 4.2vw, 4rem);
}
#hall .ch-head {
  margin-bottom: clamp(14px, 2vh, 24px);
}
#hall .ch-title {
  font-size: clamp(1.6rem, 2.6vw, 2.5rem);
}
.g-card {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--line-soft);
  transition: transform .45s var(--ease), border-color .45s var(--ease);
  cursor: pointer;
}
.g-card:hover {
  transform: translateY(-6px);
  border-color: var(--line);
}
.g-art {
  position: relative;
  aspect-ratio: 4 / 3;
  display: grid;
  place-items: center;
  background: linear-gradient(135deg, var(--c1, #1c1812), var(--c2, #3a2f1c));
  overflow: hidden;
}
.g-art::before {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(5, 4, 3, .5);
  opacity: 0;
  transition: opacity var(--t-fast) var(--ease);
  z-index: 1;
}
.g-art::after {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(230px at var(--mx, 50%) var(--my, 40%), rgba(255, 255, 255, .16), transparent 70%);
  opacity: 0;
  transition: opacity var(--t-fast) var(--ease);
}
/* 真封面鋪滿整格,壓在漸層與字母縮寫上面 —— 兩者本來就是「還沒有圖」時的替代品。
   z-index 不寫:它排在 .g-mark 前面,同一層自然在下,而 ::before(懸停壓暗,z-index 1)、
   .g-fav 與 .g-play(z-index 2)都比它高,懸停那一套原封不動。
   封面來源比例不一:多數是 4/3 橫幅,PG Soft 有一批是 3/4 直幅,少數是正方。object-fit
   用 contain 而不是 cover —— 整張封面完整落在格子裡,一個像素都不裁,比例對不上的那幾張
   在上下或左右留一圈邊,不會出現斷頭的字標。 */
.g-cover {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
/* 留邊那一圈的底色:直接用 --surface,跟卡片下半截 .g-meta 的底同一塊,封面之外
   整張卡是一片連續的底色。封面載入失敗時 app.js 把 <img> 移除,這條跟著失效,
   底下那層取樣自封面主色的漸層自己回來當「還沒有圖」的替代品。 */
.g-art:has(.g-cover) {
  background: var(--surface);
}
/* 有真封面就收掉字母縮寫。載入失敗時 app.js 把 <img> 整個移除,這條選擇器跟著失效,
   縮寫自己回來 —— 不必再寫一段 JS 去切換 class。 */
.g-art:has(.g-cover) .g-mark {
  display: none;
}
.g-mark {
  font-family: var(--serif);
  font-weight: 600;
  font-size: clamp(1.9rem, 3vw, 2.7rem);
  letter-spacing: .08em;
  margin-right: -.08em;
  color: rgba(255, 255, 255, .88);
  text-shadow: 0 2px 24px rgba(0, 0, 0, .45);
}
/* 供應商封面圖鋪滿整格,蓋掉底下的字母底稿(DOM 排在 .g-mark 後面,不用 z-index);
   載入失敗時 onerror 把 <img> 自己拆掉,漸層加字母就是後備畫面。hover 的暗場
   (::before)與光暈(::after)都是 z-index 1 起跳,照樣壓在圖上,互動手感不變。 */
.prov-cover {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* 角色畫在整幅的左半、佔滿畫面高度,所以每個比例都靠左裁:圖框比例
     0.60(390px)到 1.43(1920px),直式卡的窗口約是原圖寬的一半,角色剛好
     整個留下;寬卡留下九成,角色佔左半,右半的暗場留給廠標。靠上對齊是
     為了 1920px 那個最扁的框——那裡唯一會縱向裁掉的是腳下的水,不是頭。 */
  object-position: left top;
  /* 圖還在下載時 Chrome 會拿已解到的那幾列去套 object-fit: cover,等於把半張圖
     放大鋪滿整格,下載完再彈回原尺寸——就是重整時那下「左右放大再復原」的殘影。
     載完(onload 掛 .on)才淡入,那段空窗露的是底下的漸層加字母,本來就是後備畫面。 */
  opacity: 0;
  transition: opacity .28s ease;
}
.prov-cover.on {
  opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
  .prov-cover {
    transition: none;
  }
}
/* 官方廠標層。廠標是這張卡要傳達的主體,所以它壓在封面上、永遠完整,
   外圈是金色霓虹燈管框 + 暗底板:燈管是參考競品卡的作法,暗底板則讓白色
   字標壓在角色的藍色閃電上也讀得清楚。直式卡擺中下,寬卡移到右半放大。 */
.prov-badge {
  position: absolute;
  z-index: 2;
  left: 50%;
  bottom: 7%;
  transform: translateX(-50%);
  width: 82%;
  max-width: 240px;
  padding: 9px 12px;
  border-radius: 12px;
  background: rgba(6, 5, 4, .66);
  border: 1px solid rgba(240, 205, 110, .85);
  box-shadow:
    0 0 12px rgba(226, 184, 74, .45),
    inset 0 0 12px rgba(226, 184, 74, .22);
  pointer-events: none;
}
.prov-badge img {
  display: block;
  width: 100%;
  height: auto;
  filter: drop-shadow(0 1px 4px rgba(0, 0, 0, .8));
}
/* 卡片變寬(桌面 4 欄 1.06-1.23 比例)時廠標移到右半、放大,左邊留給角色。 */
@media (min-width: 901px) {
  .prov-badge {
    left: auto;
    right: 6%;
    bottom: 50%;
    transform: translateY(50%);
    width: 46%;
    max-width: 250px;
    padding: 13px 16px;
    border-radius: 14px;
  }
}
/* 參照競品卡的貼邊霓虹描邊:畫在卡框上而非圖裡,任何裁切比例都完整。
   (.g-art 的 ::before/::after 已被 hover 暗場與光暈佔用,所以用 outline
   負縮進 + 本體內陰影,不動既有偽元素。) */
.prov-card .g-art {
  outline: 1px solid rgba(212, 175, 55, .55);
  outline-offset: -1px;
  box-shadow: inset 0 0 18px rgba(212, 175, 55, .18);
}
/* #hall 的精選格是 GAMES.filter(tag==='hot') 取前八,八張必然全是熱門,
   標籤掛滿等於沒有資訊。大廳格是混合標籤,那裡才留著。 */
#hall .spot-grid .g-tag {
  display: none;
}
.g-tag {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 2;
  font-size: 9px;
  font-weight: 500;
  letter-spacing: .26em;
  margin-right: -.26em;
  text-transform: uppercase;
  color: var(--gold);
  background: rgba(10, 8, 6, .82);
  border: 1px solid var(--line);
  padding: .4em .8em .4em 1.05em;
}
.g-fav {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 2;
  width: 36px;
  height: 36px;
  display: grid;
  place-items: center;
  font-size: 16px;
  color: var(--ink-dim);
  background: rgba(10, 8, 6, .66);
  border: 1px solid var(--line-soft);
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.g-fav:hover {
  color: var(--gold-hi);
  border-color: var(--line);
}
.g-fav.on {
  color: var(--gold);
}
.g-play {
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: .7em;
  font-size: 11px;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--gold-hi);
  border: 1px solid var(--gold);
  padding: .8em 1.5em .8em 1.7em;
  transform: translate(-50%, -50%) translateY(8px);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
  white-space: nowrap;
}
.g-play:focus-visible {
  opacity: 1;
  pointer-events: auto;
  transform: translate(-50%, -50%);
}
@media (hover: hover) and (pointer: fine) {
  .g-card:hover .g-art::before,
  .g-card:hover .g-art::after {
    opacity: 1;
  }
  .g-card:hover .g-play {
    opacity: 1;
    pointer-events: auto;
    transform: translate(-50%, -50%);
  }
}
.g-meta {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 10px;
  padding: 13px 14px 14px;
}
/* flex 子項預設 min-width:auto = min-content,h3 那條 text-overflow:ellipsis 會失效,
   320px 下整排卡片把 .spot-grid 撐到 330px,整頁橫向溢出 30px。 */
.g-info {
  min-width: 0;
}
.g-info h3 {
  font-weight: 500;
  font-size: 13.5px;
  letter-spacing: .04em;
  line-height: 1.3;
}
/* 副標與 RTP 標籤原本是 --ink-faint。那個 token 對頁底 --bg(#0a0806)是 4.72:1,
   但卡片資訊條的底是 --surface(#121008),同一個色掉到 4.49:1 —— 差 0.01 沒過 AA,
   axe 在 390 與 1440 上各報 64 個節點(32 張卡 × 兩處)。提到 --ink-dim 是 6.03:1。
   不改 --ink-faint 這個 token,理由同 .field input::placeholder 那一段:它在別處
   還有用途,而這裡真正的成因是底色比頁底亮,不是 token 本身太暗。
   層級沒有掉:h3 是繼承來的 --ink(14.9:1),副標比它低一階,RTP 標籤仍弱於金色的數值。 */
.g-info p {
  font-size: 11px;
  color: var(--ink-dim);
  letter-spacing: .06em;
  margin-top: 2px;
}
.g-rtp {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--gold);
  white-space: nowrap;
}
.g-rtp i {
  font-style: normal;
  color: var(--ink-dim);
  margin-right: .5em;
}
#ledger .ch-head {
  margin-bottom: clamp(14px, 2vh, 24px);
}
#ledger .ch-title {
  font-size: clamp(1.6rem, 2.6vw, 2.5rem);
}
.ledger-cols {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(28px, 4.5vw, 80px);
  align-items: start;
}
.ledger-col.off {
  margin-top: 62px;
}
.lc-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--line);
}
.lc-head h3 {
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(1.4rem, 1.95vw, 1.75rem);
}
.lc-avg {
  font-size: 11px;
  letter-spacing: .12em;
  color: var(--ink-faint);
}
.lc-avg b {
  font-family: var(--mono);
  font-weight: 400;
  color: var(--gold);
  margin-left: .6em;
}
.ledger-col ol li {
  display: grid;
  grid-template-columns: 1fr auto auto;
  align-items: baseline;
  gap: clamp(10px, 1.4vw, 22px);
  padding: 14px 2px;
  border-bottom: 1px solid var(--line-soft);
  font-size: 14px;
}
.ledger-col ol li.new {
  animation: rowIn .6s var(--ease);
}
@keyframes rowIn {
  from { opacity: 0; transform: translateY(-10px); }
  to { opacity: 1; transform: none; }
}
.lu {
  font-family: var(--mono);
  font-size: 13px;
  color: var(--ink-dim);
}
.la {
  font-family: var(--mono);
  font-size: 13.5px;
  color: var(--gold-hi);
  font-variant-numeric: tabular-nums;
}
.la.wd {
  color: var(--ink);
}
.lt {
  font-size: 11.5px;
  color: var(--ink-faint);
  min-width: 5.5em;
  text-align: right;
}
/* 「支付通道 + 獎池」是第二排 .ledger-cols:同一組欄距、同一個 .lc-head(標題、右側說明、
   底線)、獎池跟提款一樣往下錯位 —— 四個區塊看起來是同一張帳,不是兩種版式拼在一起。 */
.ledger-foot {
  margin-top: clamp(20px, 2.6vh, 44px);
}
.rails ul {
  margin-top: 14px;
}
.pots li {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: baseline;
  gap: clamp(14px, 2vw, 26px);
  padding: 16px 0;
  border-bottom: 1px solid var(--line-soft);
}
.pot-name {
  font-family: var(--serif);
  font-weight: 600;
  font-size: 1.1rem;
  letter-spacing: .06em;
  min-width: 4.4em;
  color: var(--gold);
}
.pot-amt {
  font-family: var(--mono);
  font-size: 15px;
  color: var(--gold-hi);
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.pot-last {
  text-align: right;
  font-size: 10px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.pot-last b {
  display: block;
  font-family: var(--mono);
  font-weight: 400;
  font-size: 11.5px;
  letter-spacing: 0;
  text-transform: none;
  margin-top: 2px;
}
.rails ul {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  background: var(--line-soft);
  border: 1px solid var(--line-soft);
}
.rails li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 16px 18px;
  background: var(--bg);
}
.rn {
  font-weight: 500;
  font-size: 14px;
  letter-spacing: .1em;
}
.rs {
  display: inline-flex;
  align-items: center;
  gap: .6em;
  font-size: 9.5px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.cards {
  display: grid;
  grid-template-columns: 1.55fr 1fr 1fr;
  gap: clamp(16px, 2vw, 28px);
  align-items: start;
}
.cards .invite:nth-child(2) {
  margin-top: 36px;
}
.cards .invite:nth-child(3) {
  margin-top: 72px;
}
/* .ch 是置中的 flex 欄,在最後一個子元素補下外距 = 整組往上移一半的量。
   燙金請柬(板塊 3)上下留白特別多,加上固定頂欄吃掉上緣 60px,不補這段看起來就偏下。
   用外距不用 padding:padding 在 @media (max-height:1010px) 會被 .ch 整條覆寫掉。 */
#invite .cards {
  margin-bottom: clamp(48px, 7vh, 110px);
}
@media (max-width: 900px) {
  #invite .cards {
    margin-bottom: 0;
  }
}
.invite {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 34px;
  min-height: clamp(240px, 30vh, 320px);
  padding: clamp(26px, 3vw, 46px);
  /* 上緣那道泛光跟 .vip 是同一條漸層,連數值都一樣 —— 兩處是同一個語彙,分開調會走鐘。
     疊在原本的底色之上而不是換掉它:逗號分隔的圖層先寫的畫在上面,底下那條 165deg
     仍然負責卡片本身的深淺。背景圖層不參與盒模型,三張卡的框在兩個寬度都一格沒動。
     .invite 也是 auth / forgot / 404 / 三卷條文那張外殼卡用的同一個 class(見 2189 的註),
     所以那幾頁的卡也會一起亮起來 —— 那是同一套雙金框語彙,本來就該一致。 */
  background:
    radial-gradient(60% 130% at 50% 0%, rgba(212, 175, 55, .13), transparent 70%),
    linear-gradient(165deg, #15110a, #0c0a07);
  border: 1px solid var(--line);
  transition: transform var(--t) var(--ease);
}
.invite:hover {
  transform: translateY(-6px);
}
.invite::before {
  content: '';
  position: absolute;
  inset: 10px;
  border: 1px solid var(--line-soft);
  pointer-events: none;
}
.invite h3 {
  font-family: var(--serif);
  font-weight: 600;
  font-size: clamp(1.5rem, 2.1vw, 2rem);
  line-height: 1.15;
  text-wrap: balance;
}
.invite p {
  font-size: 12.5px;
  color: var(--ink-dim);
  letter-spacing: .04em;
  max-width: 34ch;
}
/* 34ch 是給首頁請柬那段散文的。表單裡的 .hint 也是 .invite 底下的 <p>,會一起吃到,
   在 531px 寬的欄位裡被封到 238px 就折成兩行 —— 那一列比別列高 49px,行距就不齊了。 */
.invite p.hint { max-width: none; }
/* 三張請柬左下角那一行是整屏唯一的動作,原本 11px、字重 300、只用 --gold ——
   在 clamp(1.5rem, 2.1vw, 2rem) 的標題與 12.5px 的說明之間,它是最不起眼的一行。
   字級抬到 13px、字重回到 400、顏色換成 --gold-hi(在卡片底上量到 12.4:1),
   字距同時從 .26em 收到 .2em:字放大又不收字距的話,320 寬那張卡的
   「KLAIM UNDANGAN」會折行 —— 收完四個語系在 320 都還是一行。 */
.invite-cta {
  display: inline-flex;
  align-items: center;
  gap: .9em;
  font-size: 13px;
  font-weight: 400;
  letter-spacing: .2em;
  margin-right: -.2em;
  text-transform: uppercase;
  color: var(--gold-hi);
}
.invite-cta i {
  transition: transform var(--t-fast) var(--ease);
}
.invite:hover .invite-cta i {
  transform: translateX(6px);
}
.ch-finale {
  gap: clamp(16px, 2.8vh, 38px);
}
.vip {
  /* 內框那條線要靠它定位。沒有位移值,所以 .vip 自己的邊框盒一格沒動。 */
  position: relative;
  padding: clamp(24px, 3vw, 48px) clamp(20px, 3vw, 48px);
  text-align: center;
  border: 1px solid var(--line);
  flex: 1 1 auto;
  margin-block: clamp(10px, 2.6vh, 34px) clamp(6px, 1.4vh, 18px);
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: radial-gradient(60% 130% at 50% 0%, rgba(212, 175, 55, .13), transparent 70%);
}
/* 收尾這張卡改成跟三張邀請卡同一種雙線框:外框留在 .vip 本體(值本來就跟 .invite 一樣),
   內框補在這裡,inset 與線色都照抄 .invite::before —— 站上只該有一套雙金框。 */
.vip::before {
  content: '';
  position: absolute;
  inset: 10px;
  border: 1px solid var(--line-soft);
  pointer-events: none;
}
.vip-title {
  font-family: var(--serif);
  font-weight: 600;
  font-size: clamp(2.6rem, 5.6vw, 5.1rem);
  line-height: 1.05;
}
.vip p {
  margin: clamp(14px, 2.4vh, 26px) auto clamp(20px, 3.4vh, 36px);
  font-size: clamp(13.5px, 1.15vw, 17px);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--ink-dim);
  max-width: 60ch;
  text-wrap: balance;
}
.vip .btn-gold {
  font-size: 13px;
  padding: 1.05em 2.8em;
}
.prov-wall {
  text-align: center;
}
.prov-wall ul {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px clamp(18px, 2.4vw, 42px);
  margin-top: 14px;
}
.prov-wall li {
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(.84rem, 1.05vw, 1.06rem);
  letter-spacing: .1em;
  color: var(--ink-faint);
  transition: color var(--t-fast) var(--ease);
}
.prov-wall li:nth-child(3n) {
  color: var(--ink-dim);
}
.prov-wall li:hover {
  color: var(--gold);
}
.foot {
  border-top: 1px solid var(--line-soft);
  padding: 14px 0 2px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px clamp(18px, 2.2vw, 32px);
  font-size: 11px;
  color: var(--ink-faint);
}
.foot nav {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 26px;
}
.foot nav a {
  color: var(--ink-faint);
  letter-spacing: .1em;
  transition: color var(--t-fast) var(--ease);
}
.foot nav a:hover {
  color: var(--gold);
}
.age {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--gold);
  border: 1px solid var(--gold);
  padding: .3em .6em;
  letter-spacing: .06em;
}
.foot .rights {
  margin-left: auto;
}
.contact {
  position: fixed;
  right: 20px;
  bottom: 22px;
  right: max(20px, env(safe-area-inset-right));
  bottom: max(22px, env(safe-area-inset-bottom));
  z-index: 45;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.contact a, .contact button {
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  font-size: 19px;
  color: var(--gold);
  background: rgba(10, 8, 6, .85);
  border: 1px solid var(--line);
  transition: transform var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
/* ── 表格分頁條 ────────────────────────────────────────
   遊玩記錄與全部流水兩頁的表格底下那一排。兩頁的表格樣式是各自 HTML 裡的複本,
   但這一段只有一份,放共用檔:兩頁的分頁條長得一模一樣,複製成兩份之後改一次要改兩處。
   靠右:一般網頁的分頁習慣就在右下角,而且這兩頁的合計那幾格也是靠右對齊,同一條軸線。
   數字用等寬字:頁碼從一位數變兩位數時,整條的寬度才不會跟著抖。
   38px 見方是連著間距一起量的舒適尺寸(WCAG 2.5.8 AA 的門檻是 24×24 加間距例外)。 */
/* display: flex 會蓋掉瀏覽器給 [hidden] 的 display: none —— 只剩一頁的時候
   內容雖然清空了,那條 14px 的上外距還在,表格底下會多出一段莫名的空白。 */
.pager[hidden] {
  display: none;
}
.pager {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
  margin-top: 14px;
}
.pager button {
  min-width: 38px;
  height: 38px;
  padding: 0 9px;
  display: grid;
  place-items: center;
  font-family: var(--mono);
  font-size: 12.5px;
  color: var(--ink-dim);
  background: none;
  border: 1px solid var(--line-soft);
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.pager button:hover:not(:disabled) {
  color: var(--gold-hi);
  border-color: var(--line);
}
/* 目前這一頁是實心的:只換文字顏色的話,在一排同樣淡的數字裡看不出哪一顆是現在。
   aria-current 同時也是給讀屏的答案,樣式與語意掛在同一個屬性上,不會各說各話。 */
.pager button[aria-current="page"] {
  color: var(--bg);
  background: var(--gold);
  border-color: var(--gold);
}
/* 跳號處的省略號。不是按鈕,所以不掛邊框也不佔 38px 的方格,只當一個間隔記號。 */
.pg-gap {
  padding: 0 2px;
  font-family: var(--mono);
  font-size: 12.5px;
  color: var(--ink-dim);
}
/* 第一頁的上一頁、最後一頁的下一頁留在原地變灰,不抽掉 —— 抽掉整條會左右晃一格。 */
.pager button:disabled {
  opacity: .35;
  cursor: default;
}
.pager-step {
  font-size: 15px;
}
.pager-gap {
  padding: 0 2px;
  font-family: var(--mono);
  font-size: 12.5px;
  color: var(--ink-dim);
}
/* 圖示字型是子集,只收了頁面真的用到的那幾個字,裡面沒有 telegram
   (fonts/icons.css 的清單看得到)。為了一顆鈕重打整份字型不划算,直接內嵌一段線條 SVG。
   1em 的尺寸吃外面那條 font-size: 19px,線寬 1.5 是照 ph-light 的筆畫對出來的 ——
   跟旁邊那顆 WhatsApp 併排看,粗細與視覺重量一致。
   currentColor 讓它跟著鈕的 color 走,hover、dim、強制色彩模式都不用另外接。 */
.i-tg {
  width: 1em;
  height: 1em;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.contact a:hover, .contact button:hover {
  transform: translateY(-3px);
  border-color: var(--gold);
}
.contact .to-top {
  opacity: 0;
  pointer-events: none;
  transform: translateY(8px);
  transition: opacity var(--t-fast) var(--ease), transform var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.contact .to-top.show {
  opacity: 1;
  pointer-events: auto;
  transform: none;
}
.contact .to-top.show:hover {
  transform: translateY(-3px);
  border-color: var(--gold);
}
/* ── 窄屏:三顆懸浮鈕收成一顆抽屜 ────────────────────────
   這疊在桌機是右下角三顆 46x46,量到整疊 158px 高。手機上它壓在表格的金額欄、
   卡片的收藏星星、頁尾版權字上面,而且是固定定位,橫捲也躲不開。
   收成一顆:抽屜關著時只剩 46x46,按下去其餘幾顆由下往上散開。
   另外接一條「醒著 / 半透明」:捲動中與剛換板塊時全亮,停手 2.6 秒淡到 .34,
   看得見但不擋視線(class 由 app.js 掛)。桌機沒有這個問題,整段只在 1080 以下開。 */
/* 選擇器要壓得過上面那條 .contact a, .contact button 的 display: grid,
   不然這顆在桌機也會冒出來,整疊從 158px 變成 214px。 */
.contact .contact-fab {
  display: none;
}
/* 收起時的臉是一枚對話泡 —— 這疊底下裝的就是聯絡管道,一個加號看不出是什麼。
   展開換成叉。兩層疊在同一格互相淡出淡入,不換 innerHTML:換內容補不出中間影格,
   按下去會像閃一下。 */
.contact-fab > i,
.contact-fab > .fab-x {
  grid-area: 1 / 1;
  transition: opacity var(--t) var(--ease), transform var(--t) var(--ease);
}
.contact.open .contact-fab > i {
  opacity: 0;
  transform: rotate(90deg) scale(.7);
}
.fab-x {
  position: relative;
  width: 17px;
  height: 17px;
  opacity: 0;
  transform: rotate(-90deg) scale(.7);
}
.contact.open .fab-x {
  opacity: 1;
  transform: none;
}
.fab-x::before,
.fab-x::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 0;
  width: 100%;
  height: 1px;
  background: var(--gold);
}
.fab-x::before {
  transform: translateY(-50%) rotate(135deg);
}
.fab-x::after {
  transform: translateY(-50%) rotate(45deg);
}
@media (max-width: 1080px) {
  .contact {
    transition: opacity .55s var(--ease);
  }
  .contact.dim {
    opacity: .34;
  }
  .contact.dim:focus-within {
    opacity: 1;
  }
  .contact .contact-fab {
    display: grid;
  }
  /* 抽屜裡的幾顆改成絕對定位:關著時整疊不占高度,.contact 就只剩那一顆的大小。
     散開的距離是 46 的鈕加 10 的間距 = 56,跟桌機那疊的節奏一樣。 */
  .contact > :not(.contact-fab) {
    position: absolute;
    right: 0;
    bottom: 0;
    transition: opacity .26s var(--ease), transform .36s var(--ease), visibility .36s;
  }
  /* 收回去是散開的倒帶:最外圈先落回鈕上,最靠近的那顆最後走。延遲用 --n 減 --i 換算
     (--n 是這一次散開時真正排上位子的顆數,layoutFan() 寫進 .contact),所以無論這一頁
     有幾顆、回到頂部亮不亮,倒序都算得準。45ms 是散開那一段的節拍,收回去走 38ms ——
     略快一點,手感才像「彈回去」而不是「再放一次」。 */
  .contact:not(.open) > :not(.contact-fab) {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transform: scale(.72);
    transition-delay: calc((var(--n, 3) - var(--i, 1)) * 38ms);
  }
  .contact.open > :not(.contact-fab) {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transform: translateY(calc(var(--i, 1) * -56px));
    transition-delay: calc(var(--i, 1) * 45ms);
  }
  /* 回到頂部本來就有自己的出場條件(捲離頁首才亮),抽屜開著也不能違背它 */
  .contact.open > .to-top:not(.show) {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transform: scale(.72);
  }
}
/* ledger 與 plays 是兩張長表格,右下角這疊懸浮鈕是固定定位的,表格從它底下捲過去。
   量過:這疊的左緣永遠落在「視窗寬減 66px」,而表格右緣到視窗邊只有 22~61px 的
   留白,所以 1100px 以下必定重疊。原本的解法是在 1024 以下收掉兩顆佔位鈕,把這疊
   從 158px 高縮成 46px;現在 1080 以下整疊本來就收成一顆 46x46 的抽屜,那條規則
   已經沒有作用,連同 panel 那條矮視窗的同款補丁一起收掉。 */
/* 陳列室的收藏星星在卡片右上角,窄於 1120px 時卡片右緣貼到懸浮鈕那條 66px 帶,
   捲到哪顆卡對上鈕,星星的中心點就點不到。實測乾淨門檻是 1111px(1024 斷點會
   留下 1025~1111 之間 8~12 顆被蓋),給卡片欄讓出 30px 就全清:320~1920 共
   30 個寬度從 9~60 次命中降到 0。 */
@media (min-width: 761px) and (max-width: 1120px) {
  body[data-page="lobby"] .case-grid {
    padding-right: 30px;
  }
}
/* 首頁 #hall 是滿版板塊,卡片列用 1fr 撐到板塊底邊,而懸浮鈕固定在視窗右下角
   (46px 見方,離底 22px)。最後一列右下那張卡的資訊條剛好落在鈕底下,RTP 那行
   被整塊蓋掉 —— 實測 320x700、375x812、390x700、390x844、430x932、600x800、
   700x700、800x700、900x700 九個寬度全中,768x1024 例外是因為那裡板塊底距
   本來就有 112px。板塊底部改留 72px = 鈕高 46 + 底距 22 + 4px 淨空,卡片列
   讓出這段高度,文字就永遠停在鈕上方。
   660 以下的高度不套:那一帶是橫持手機,板塊底距只有 16px,內容本來就溢出,
   再讓 72px 只會讓溢出更長。 */
@media (max-width: 900px) and (min-height: 661px) {
  #hall {
    padding-bottom: 72px;
  }
}
/* 金庫頁左欄的印記導航是黏性定位,矮視窗裡它的連結帶會滑進懸浮鈕底下:
   761px 起實測 704 高仍有重疊、707 才乾淨,取 713 留餘裕 —— 這一帶是橫持手機
   與矮桌面窗,頁內導航有黏性印記欄頂著,整疊收掉沒有損失。
   760px 以下疊的是單欄,只有 470 高以下才撞到 —— 那一段現在收成一顆抽屜,不必再管。 */
@media (min-width: 761px) and (max-height: 713px) {
  body[data-page="panel"] .contact {
    display: none;
  }
}
.cursor-light {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 60;
  width: 360px;
  height: 360px;
  margin: -180px 0 0 -180px;
  background: radial-gradient(circle, rgba(212, 175, 55, .09), transparent 62%);
  mix-blend-mode: screen;
  pointer-events: none;
  opacity: 0;
  transition: opacity .8s var(--ease);
}
@media (hover: none), (pointer: coarse) {
  .cursor-light {
    display: none;
  }
  /* 觸控沒有「指標離開」這件事,:hover 會黏在剛點過的元素上不放 ——
     點一張遊戲卡叫出啟動視窗,關掉之後那張卡還浮著 6px。
     這裡只收「浮起」的位移,金色高亮留著當點擊回饋。
     .brand 不收:它的 ::before 基準值是 scale(.86),transform: none 會把它放大;
     而且點它就換頁,黏不黏都看不到。 */
  .btn-gold:hover, .btn-ghost:hover,
  .g-card:hover, .invite:hover, .invite:hover .invite-cta i,
  .contact a:hover, .contact button:hover, .contact .to-top.show:hover {
    transform: none;
  }
}
.toast {
  position: fixed;
  left: 50%;
  bottom: 30px;
  bottom: max(30px, env(safe-area-inset-bottom));
  z-index: 95;
  max-width: 86vw;
  text-align: center;
  font-size: 12px;
  letter-spacing: .08em;
  color: var(--ink);
  background: rgba(10, 8, 6, .94);
  border: 1px solid var(--line);
  padding: .8em 1.5em;
  opacity: 0;
  transform: translateX(-50%) translateY(14px);
  pointer-events: none;
  transition: opacity var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.toast.show {
  opacity: 1;
  transform: translateX(-50%);
}
@media (max-width: 760px) {
  body[data-page="lobby"] .toast {
    bottom: calc(86px + env(safe-area-inset-bottom));
  }
}
.lobby {
  display: grid;
  grid-template-columns: 256px minmax(0, 1fr);
  min-height: 100vh;
  min-height: 100dvh;
  padding-top: 60px;
}
.rail {
  position: sticky;
  top: 60px;
  height: calc(100vh - 60px);
  height: calc(100dvh - 60px);
  overflow-y: auto;
  /* 側欄捲到底不要接著把整頁帶走 —— 這頁的整屏引擎正是靠 [data-inner-scroll]
     判邊界的,鏈式捲動會在交接的那一幀多走一屏 */
  overscroll-behavior-y: contain;
  border-right: 1px solid var(--line-soft);
  padding: 24px 0 40px;
}
.rl {
  display: grid;
  grid-template-columns: 2.4em 1fr auto;
  align-items: center;
  gap: 10px;
  width: 100%;
  text-align: left;
  padding: 13px 22px;
  color: var(--ink-dim);
  transition: color var(--t-fast) var(--ease), background var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.rl:hover {
  color: var(--ink);
}
.rl.on {
  color: var(--gold-hi);
  background: linear-gradient(90deg, rgba(212, 175, 55, .1), transparent 75%);
  box-shadow: inset 2px 0 var(--gold);
}
/* --gold-dim(#8a6d1f)對近黑底只有 4.08:1,小字要 4.5:1。提到 --gold 是 9.51:1,
   而且不是新語彙 —— .door 的序號 hover 時走的就是 --gold-dim 到 --gold 這一段,
   三卷法務頁的條號同樣是金的。編號金、名稱 --ink-dim,層級照舊。 */
.rl-num {
  font-family: var(--serif);
  font-style: italic;
  font-size: 13px;
  color: var(--gold);
}
.rl-num i {
  font-style: normal;
  font-size: 15px;
}
.rl-name {
  font-size: 13px;
  letter-spacing: .08em;
}
.rl-count {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--ink-faint);
}
.rail-sep {
  margin: 20px 22px 6px;
  font-size: 9.5px;
  letter-spacing: .32em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.hall {
  /* 上留白對齊 .rail 的 padding-top,兩欄第一個元素同一條基線 */
  padding: 24px clamp(18px, 3.6vw, 56px) clamp(60px, 10vh, 110px);
  padding-left: max(clamp(18px, 3.6vw, 56px), env(safe-area-inset-left));
  padding-right: max(clamp(18px, 3.6vw, 56px), env(safe-area-inset-right));
  min-width: 0;
}
.hall-head {
  display: flex;
  flex-direction: column;
  gap: 22px;
}
.tools {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 16px 26px;
}
.search {
  position: relative;
  flex: 1 1 240px;
  max-width: 460px;
}
.search i {
  position: absolute;
  left: 2px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 16px;
  color: var(--ink-faint);
  pointer-events: none;
}
.search input {
  width: 100%;
  background: none;
  border: 0;
  border-bottom: 1px solid var(--line-soft);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 14px;
  letter-spacing: .04em;
  padding: .65em .4em .65em 1.9em;
  transition: border-color var(--t-fast) var(--ease);
}
.search input::placeholder {
  color: var(--ink-faint);
}
.search input:focus {
  outline: none;
  border-color: var(--gold);
}
/* iOS Safari 聚焦 font-size < 16px 的文字輸入時會把整頁放大,而且鬆開後不會自己還原。
   全站只有這個搜尋框低於 16px(表單那些本來就是 16px),補到 16px 就沒事。
   內距是 em,字級一動高度跟著從 39.2px 長到 44.8px,順便補上觸控目標。
   掛在這個查詢而不是寬度斷點:會放大的是觸控裝置,平板也算,桌機一個像素都不動。
   規則要放在 .search input 本體後面 —— 兩者同權重,寫在上面那個 (hover: none)
   區塊裡會被後面的 14px 蓋掉。 */
@media (hover: none), (pointer: coarse) {
  .search input {
    font-size: 16px;
  }
}
/* 大廳的供應商門沿用首頁 #hall 的 .doors / .door,兩頁同一套語彙,不另立樣式;
   這裡只要跟上面的工具列隔開。 */
#lobby-doors {
  margin-top: clamp(20px, 3.4vh, 44px);
}
.case-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(205px, 1fr));
  /* 寬卡佔 2x2,欄數不是 10 的因數時自動排版會漏格,dense 讓後面的小卡回填 */
  grid-auto-flow: row dense;
  gap: clamp(14px, 1.6vw, 22px);
  margin-top: 30px;
}
/* 寬卡吃 2x2 一格。跨兩欄還要跨兩行,不然它自己把整行撐高,同排小卡下面各留一塊白。
   封面解除 4/3 改吃剩餘高度:寬卡內容只比兩行小卡矮一個 .g-meta,不補就換成它自己底部開洞。
   實測第三欄要到 973px 才長出來,留一個捲軸的餘裕抓 1024:欄數少於三時寬卡會佔滿整行,
   第一行只剩它一張、封面又被兩行的高度壓扁,那個區間讓它退回普通卡。 */
@media (min-width: 1024px) {
  .case-grid .g-card.wide {
    grid-column: span 2;
    grid-row: span 2;
    display: flex;
    flex-direction: column;
  }
  .case-grid .g-card.wide .g-art {
    aspect-ratio: auto;
    flex: 1;
  }
  /* 主打卡的卡腳加高。大封面是 4/3,而它的格子(兩欄兩列扣掉一個卡腳)比 4/3 高,
     圖只能縮在中間,上下各留一條三十幾像素的空帶(1440 下量到 35px)。加高卡腳等於
     把那條空帶還給文字,順帶把卡名放大一級 —— 主打卡本來就該比小卡重。
     剩下的差額由封面自己吃(見下面的 object-fit),裁掉的是四周的背景。 */
  .case-grid .g-card.wide .g-meta {
    padding: 20px 22px 22px;
  }
  .case-grid .g-card.wide .g-info h3 {
    font-size: 19px;
    letter-spacing: .05em;
  }
  .case-grid .g-card.wide .g-info p {
    font-size: 12.5px;
    margin-top: 6px;
  }
  /* 卡腳加高之後還差一截,由封面補滿:主打卡改 cover。裁掉的是左右的背景,各百分之
     四到五;標題字標與主體都在畫面中央的安全區裡,量過九款主打都沒被切到。
     1360 張封面現在一律是 640x480,格子比 4/3 矮,所以裁的一定是左右,上下一個像素
     不動 —— 窄屏那兩段的框已經改成貼著圖,只有這裡的兩欄兩列格子還比封面方。 */
  .case-grid .g-card.wide .g-cover {
    object-fit: cover;
  }
  /* 卡片排不出第二行時,span 2 會多開一列高度 0 的隱含行,寬卡就比同排小卡多吃一個
     row-gap,.g-meta 跟著低一截。五欄的第一行吃得下四張(1 + 2 + 1 + 1),所以第五張
     存在才保證有第二行;不到就退回單行高,寬卡仍佔兩欄,底線與同排對齊。
     「不到五張」原本寫成 :not(:has(.g-card:nth-child(5))),但 :has() 在 Safari 15.0-15.3
     之前不存在,擋板整條落空、寬卡就多吃一個 row-gap(實測差 22px)。改用第一張卡自己
     數兄弟:first-child 同時是倒數第四張以內,就代表整格不到五張 —— 同樣一句話,不必
     :has()。寬卡本身可能就是第一張,所以兩個選擇器都要寫。 */
  .case-grid .g-card:first-child:nth-last-child(-n+4).wide,
  .case-grid .g-card:first-child:nth-last-child(-n+4) ~ .g-card.wide {
    grid-row: auto;
  }
  /* 大封面左右交錯。dense 只管把洞填掉,不管往哪一欄擺 —— 放著不釘,六張大封面
     一律靠左貼齊,整頁最重的六格排成一根直柱。單數那幾張改吃最右兩欄,視線就在
     左右之間走 Z 字。負線號是照顯式格線的右緣算的,欄數從三變到五都不必改。
     三欄以下右兩欄與左兩欄只差一欄、交錯反而變成階梯狀的擠壓,留給四欄起跳。 */
  .case-grid .g-card.wide.rgt {
    grid-column: auto / span 2;
  }
}
@media (min-width: 1240px) {
  .case-grid .g-card.wide.rgt {
    grid-column: -3 / -1;
  }
}
/* 翻頁列。整條置中、只有細線與金字,跟側欄那排供應商同一種語氣。
   數字用 mono:頁碼是數字欄,等寬才不會在 1 與 10 之間跳寬度。 */
.pager {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: clamp(28px, 4vh, 46px);
}
.pager button {
  min-width: 44px;
  height: 44px;
  padding: 0 12px;
  display: grid;
  place-items: center;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: .08em;
  color: var(--ink-dim);
  border: 1px solid var(--line-soft);
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.pager button:hover:not(:disabled) {
  color: var(--gold-hi);
  border-color: var(--line);
}
/* 首尾兩顆到底時關掉。留在原地不收起來:少一顆箭頭整條會左右位移,
   而位移比灰掉更難看懂發生了什麼。 */
.pager button:disabled {
  color: var(--ink-faint);
  border-color: var(--line-soft);
  opacity: .45;
  cursor: default;
}
.pager .pg-arrow {
  font-size: 15px;
}
.empty {
  text-align: center;
  padding: clamp(60px, 12vh, 130px) 20px;
}
.empty h2 {
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(1.6rem, 3vw, 2.4rem);
}
.empty p {
  margin: 12px 0 28px;
  font-size: 13px;
  color: var(--ink-faint);
  letter-spacing: .08em;
}
.dock {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 50;
  display: none;
  grid-template-columns: repeat(5, 1fr);
  /* 橫放時五格會有一格落在瀏海底下。底部的 home indicator 由 .dock a 的下內距處理。 */
  padding-left: env(safe-area-inset-left);
  padding-right: env(safe-area-inset-right);
  background: rgba(10, 8, 6, .93);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-top: 1px solid var(--line);
}
.dock a, .dock button {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 10px 0 calc(10px + env(safe-area-inset-bottom));
  font-size: 9.5px;
  letter-spacing: .1em;
  color: var(--ink-dim);
  transition: color var(--t-fast) var(--ease);
}
.dock i {
  font-size: 20px;
}
.dock .on {
  color: var(--gold);
}
.launch {
  position: fixed;
  inset: 0;
  z-index: 90;
  width: 100%;
  height: 100%;
  max-width: 100%;
  max-height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  color: var(--ink);
  background: #050403;
  overflow: hidden;
}
.launch[open] {
  display: grid;
  place-items: center;
}
.launch:not([open]) {
  display: none;
}
.launch::backdrop {
  background: transparent;
}
.launch::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(52% 60% at 50% 46%, var(--tint, #1a1409), transparent 76%);
  opacity: .3;
}
.vault-door {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 51%;
  background: #0b0906;
  z-index: 2;
  transition: transform .95s var(--ease) .12s;
}
.vault-door.vl {
  left: 0;
  border-right: 1px solid var(--gold);
}
.vault-door.vr {
  right: 0;
  border-left: 1px solid var(--gold);
}
.launch.open .vault-door.vl {
  transform: translateX(-101%);
}
.launch.open .vault-door.vr {
  transform: translateX(101%);
}
.launch-body {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  text-align: center;
  padding: 24px;
  /* 全螢幕對話框鋪滿整個畫面,橫放時內容會落到瀏海底下 */
  padding-left: max(24px, env(safe-area-inset-left));
  padding-right: max(24px, env(safe-area-inset-right));
  padding-bottom: max(24px, env(safe-area-inset-bottom));
  opacity: 0;
  transform: translateY(12px);
  transition: opacity .6s var(--ease) .55s, transform .6s var(--ease) .55s;
}
.launch.open .launch-body {
  opacity: 1;
  transform: none;
}
.launch-kicker {
  font-size: 10px;
  letter-spacing: .44em;
  margin-right: -.44em;
  text-transform: uppercase;
  color: var(--gold);
}
/* 接了 API 的遊戲在開場擺整張封面:框改成封面本身的 4/3,contain 不裁切。
   沒有封面的維持底下那個 90px 的方塊。 */
.emblem.has-art {
  width: min(260px, 64vw);
  height: auto;
  aspect-ratio: 4 / 3;
}
.emblem.has-art img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.emblem {
  width: 90px;
  height: 90px;
  display: grid;
  place-items: center;
  font-family: var(--serif);
  font-weight: 600;
  font-size: 1.9rem;
  letter-spacing: .06em;
  color: rgba(255, 255, 255, .92);
  border: 1px solid var(--line);
}
.launch-name {
  font-family: var(--serif);
  font-weight: 600;
  font-size: clamp(1.7rem, 4vw, 2.7rem);
  line-height: 1.1;
}
.launch-sub {
  font-size: 12px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-dim);
}
.progress {
  width: min(300px, 62vw);
  height: 1px;
  background: var(--line-soft);
  overflow: hidden;
  margin-top: 8px;
}
.progress span {
  display: block;
  height: 100%;
  background: linear-gradient(90deg, var(--gold-dim), var(--gold-hi));
  transform: scaleX(0);
  transform-origin: left;
}
.launch.open .progress span {
  transform: scaleX(1);
  transition: transform 2.1s var(--ease) .75s;
}
.launch-tip {
  font-size: 11px;
  letter-spacing: .1em;
  color: var(--ink-faint);
  opacity: 0;
  transition: opacity .5s var(--ease);
}
.launch.done .launch-tip {
  opacity: 1;
}
.launch-x {
  position: absolute;
  top: 18px;
  right: 18px;
  z-index: 3;
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  font-size: 18px;
  color: var(--ink);
  border: 1px solid var(--line);
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.launch-x:hover {
  color: var(--gold);
  border-color: var(--gold);
}
/* 遊戲開在頁內的 iframe。簾幕(2.9 秒)與遊戲 HTML 都到位才掛上 .playing:
   金庫門、開場那格、徑向光暈全收掉,頂上留 48px 一條細欄,其餘整面給遊戲。 */
.launch-bar {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 3;
  height: 48px;
  display: none;
  align-items: center;
  gap: 18px;
  padding: 0 72px 0 max(18px, env(safe-area-inset-left));
  background: #0b0906;
  border-bottom: 1px solid var(--line);
  font-size: 11px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-dim);
  white-space: nowrap;
  overflow: hidden;
}
.launch-bar-name {
  font-family: var(--serif);
  font-size: 15px;
  letter-spacing: .04em;
  text-transform: none;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
}
.launch-bar-trial {
  color: var(--gold);
}
.launch-frame {
  position: absolute;
  top: 48px;
  left: 0;
  width: 100%;
  height: calc(100% - 48px);
  border: 0;
  background: #000;
  display: none;
}
.launch.playing .launch-bar {
  display: flex;
}
.launch.playing .launch-frame {
  display: block;
}
.launch.playing .launch-body,
.launch.playing .vault-door,
.launch.playing::before {
  display: none;
}
.launch.playing .launch-x {
  top: 6px;
  right: max(8px, env(safe-area-inset-right));
  width: 36px;
  height: 36px;
  font-size: 16px;
}
/* 試玩次數那句要看得見:金色、字距再拉開一點,不跟「正在接入」那行一樣暗。 */
.launch-sub.is-trial {
  color: var(--gold);
  letter-spacing: .28em;
  margin-right: -.28em;
}
/* 頂欄的訪客試玩餘額,登入後與後端沒回應時都不畫(app.js paintTrialPill)。 */
.trial-pill {
  font-size: 11px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--gold);
  white-space: nowrap;
}
.spine a.on {
  box-shadow: 0 0 12px rgba(212, 175, 55, .5);
}
/* ============================================================
   auth.html —— 登入 / 註冊
   外殼直接沿用 .invite(外金線 + inset:10px 內細線的雙框),只關掉它的 hover 浮起。
   自由輸入沿用站上唯一的文字輸入語彙:只有下邊框(見 .search input);
   .sel 的四邊框繼續只代表「選擇清單」,所以銀行欄留框、其餘欄留線。
   全部只轉 color / border-color,不用 transform —— 減動區塊那條全域覆寫不必為這一頁開例外。
   ============================================================ */
.auth {
  display: grid;
  justify-items: center;
  /* 上限 84px = 固定頂欄 60px + 24px 淨空,與 .ch 同一條底線。
     垂直留白全部綁 vh:1080 高的螢幕上登入態要能一屏放完,不出現捲軸。
     頁尾整寬之後,右端的版權字在窄螢幕會落進 .contact 那疊 46x46(實測疊高 158px)
     的正下方,那個由底下那條 media 給頁尾補右內距解決,不動這裡的下留白。 */
  padding: clamp(84px, 9vh, 112px) clamp(20px, 6vw, 120px) clamp(28px, 3.4vh, 48px);
  padding-left: max(clamp(20px, 6vw, 120px), env(safe-area-inset-left));
  padding-right: max(clamp(20px, 6vw, 120px), env(safe-area-inset-right));
  /* 撐滿一屏,讓最後一列(頁尾)吃掉剩下的高度並貼底。
     內容比一屏高時 1fr 收成 0,頁尾自然跟在內容後面。 */
  min-height: 100vh;
  /* 行動瀏覽器的網址列會收合,100vh 取的是收合後那個較大的高度,網址列還在時
     頁尾就被推到摺線下面。svh 取的是「網址列在」那個較小的高度:頁尾一定看得到,
     捲動時網址列收起來也不會整頁重排。跟 .ch 的 100svh 同一套。 */
  min-height: 100svh;
  grid-template-rows: repeat(3, auto) 1fr;
}
.auth > * {
  width: min(660px, 100%);
}
/* 頁尾例外:跟首頁同一條整寬單列,不收成卡片的 660px(收窄會擠成兩列)。
   align-self: end 讓它貼在那條 1fr 列的底部;margin-top 是內容滿版時的最小間距,
   不然卡片下緣會直接壓在頁尾的上邊框上。 */
.auth > .foot {
  width: 100%;
  align-self: end;
  margin-top: clamp(28px, 4vh, 56px);
}
.auth-kicker {
  font-family: var(--sans);
  font-size: 12px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--gold);
  /* 小標與大標是同一個稱謂的兩半,16px 讓它們讀起來像兩件事。
     收到 8px 之後兩行綁成一組,標題底下的留白才是這一段唯一的斷點。 */
  margin-bottom: 8px;
}
.auth-title {
  font-family: var(--serif);
  font-weight: 600;
  font-size: clamp(2.2rem, 4.2vw, 3.6rem);
  line-height: 1.1;
  /* 標題與表單卡之間原本留 20–34px。小標收緊後這一段跟著收,卡片整體上移約 16px,
     標題下緣到卡片上緣不再空出一條比行距還寬的暗帶。 */
  margin-bottom: clamp(12px, 1.6vh, 18px);
}
/* .invite 本來是首頁的請柬卡:直向 space-between、撐最小高度、hover 浮起 6px。
   當表單外殼要把這三件都關掉;class 名字對不上用途是刻意的取捨,
   換來的是不必再造一套雙金框。 */
body[data-page="auth"] .invite {
  display: block;
  min-height: 0;
  gap: 0;
  /* 左右比首頁請柬再厚一圈:內框 inset 是固定的 10px,外圍留白不夠時整張卡會顯得擠。
     上下改綁 vh,矮螢幕自己收,不然登入態一屏放不下。 */
  padding: clamp(24px, 3vh, 38px) clamp(32px, 4.4vw, 64px);
}
body[data-page="auth"] .invite:hover {
  transform: none;
}
/* 卡片裡那幾條線比全站的 --line-soft 亮。.13 的金線在近黑底上對比只有 1.2:1,
   輸入框的下邊框就是這個欄位唯一的邊界,未聚焦時幾乎看不出哪裡可以打字。
   提到 .5 之後,卡片漸層兩端量到 3.08:1 與 3.05:1,過 WCAG 1.4.11 的 3:1;
   聚焦態的 .72 是 5.15:1,加上那層外發光,兩態仍然分得開。
   只在這張卡裡改寫 token,首頁與大廳共用的 --line-soft 不動。 */
body[data-page="auth"] .tabs,
body[data-page="auth"] .form {
  --line-soft: rgba(212, 175, 55, .5);
}
.tabs {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  border-bottom: 1px solid var(--line-soft);
  margin-bottom: var(--row-gap);
}
/* 表單這一段共用的縱距。頁籤與表單是並排的兩個區塊,不是父子,所以兩邊各宣告一次
   同一個 token —— 寫在一條規則裡,值只有一個出處。.field 在 .form 裡面,繼承就拿得到。
   矮螢幕靠 vh 自己再收一點,登入態要能一屏放完。 */
.tabs,
.form {
  --row-gap: clamp(16px, 1.9vh, 22px);
}
.tab {
  min-height: 56px;
  padding: .8em .4em;
  background: none;
  border: 0;
  /* -1px 讓作用中那條金線壓在 .tabs 的細線上,而不是疊在它下面多出一列 */
  border-bottom: 1px solid transparent;
  margin-bottom: -1px;
  font-family: var(--sans);
  font-size: 13px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--ink-dim);
  cursor: pointer;
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.tab:hover {
  color: var(--ink);
}
.tab.on {
  color: var(--gold-hi);
  border-bottom-color: var(--gold);
}
.form {
  display: grid;
  gap: var(--row-gap);
}
/* 作者樣式表的 display 會蓋掉 UA 的 [hidden] { display: none },
   不補這條兩張表單會同時顯示。 */
.form[hidden] {
  display: none;
}
/* .field 也踩同一個坑,而且更難看出來:登入表單的一次性驗證碼欄開頁時是收著的
   (app.js 只有在後台回 otp-required 時才把 hidden 拿掉,驗證也是照 hidden 判斷),
   但下面那條 display: grid 把 UA 的 [hidden] 蓋掉,那一整列一直畫在登入表單上。 */
.field[hidden] {
  display: none;
}
/* 表單的縱向節奏只有兩個數字:欄與欄之間是 --row-gap,欄名與輸入框之間是它的一半。
   原本欄內 12px、欄間 20–28px、頁籤下緣 22–32px 三個數各走各的,同一張卡裡看得出
   三種不同的縱距。收成一個 token 之後,整張表單由上到下只有一種節拍。 */
.field {
  display: grid;
  gap: calc(var(--row-gap) / 2);
}
/* 標籤與佔位文字原本是 --ink-faint(對近黑底只有 4.5:1,佔位再乘 .55 更掉到 2:1 上下),
   實機上看不清楚。標籤提到 --ink、佔位提到 --ink-dim 並拿掉那層 opacity,
   兩者分別是 15:1 與 6:1;字級同時從 10 / 14 提到 12 / 16。 */
.field label {
  font-family: var(--sans);
  font-size: 12px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--ink);
  transition: color var(--t-fast) var(--ease);
}
.field input {
  width: 100%;
  /* 44px 是 DESIGN.md 的觸控底線,48 留 4px 餘裕。不沿用 .search input 的 padding
     —— 那組換算下來只有 36.4px。原本的 54px 在六欄的註冊表單上累積出 36px 的虛高。 */
  min-height: 48px;
  background: none;
  border: 0;
  border-bottom: 1px solid var(--line-soft);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  letter-spacing: .04em;
  padding: .45em .2em;
  transition: border-color var(--t-fast) var(--ease);
}
/* 佔位與標籤要分得開。標籤是 --ink(對卡片底色 14.8:1),佔位一路從 --ink-dim(6.1:1)
   降到 --ink-faint(4.51:1),實機上看仍然跟欄位名一樣搶眼,所以再降一階到 3.02:1。
   這是刻意的取捨:低於一般字級 AA 的 4.5:1,但仍在 3:1 之上(非文字元素的下限)。
   前提是每一格都有常駐的 <label>,佔位沒有獨佔任何資訊 —— 唯二例外是登入的帳號欄
   (列出信箱/用戶名/手機號三種)與推薦碼欄(標示選填),那兩句讀不清就要改掛 .hint。
   不改 --ink-faint 這個 token:它在卡片以外還有別的用途。 */
.field input::placeholder {
  color: #665f50;
  opacity: 1;
}
.field input:focus,
.field input:focus-visible,
.dial:focus-within {
  /* 全站的 :focus-visible 是 1px 金色方框 + 3px offset。在只有底線的輸入框上,
     那個方框會憑空多出一個框;號碼欄更糟 —— 框只圈住號碼那半,看起來跟區號是兩件東西。
     這一頁改用「底線轉金 + 一層金色外發光」,對比與可見度都在,形狀跟欄位本身一致。
     金線壓到 .72 不用純金:整條實金在近黑底上太硬,發光那層才是主要訊號。 */
  outline: none;
  border-color: rgba(212, 175, 55, .72);
  box-shadow: 0 0 0 1px rgba(212, 175, 55, .1), 0 8px 26px -12px rgba(212, 175, 55, .55);
}
/* 區號是可選的 select,label 指的是後面那個號碼欄。號碼用等寬 —— 站上數字本來就是這個語彙。 */
.dial {
  display: grid;
  /* 收合處只剩區號,最長的 +1876 在這一格的字型與字距下量到 47px。
     欄寬就照那個數字定:47 + 左內距 3 + 右側讓給箭頭的 20 = 70,取 76px 收邊。
     原本是 clamp(76px, 22%, 108px),寬螢幕吃到上限 108px —— 三位數的 +62 只佔 31px,
     文字與箭頭之間空出 54px,那一格看起來比它裝的東西寬一倍。
     定值不用百分比:百分比讓同一顆下拉在每個寬度長得不一樣,而它裝的字是固定的。 */
  grid-template-columns: 76px minmax(0, 1fr);
  align-items: center;
  border-bottom: 1px solid var(--line-soft);
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
/* 沿用 .sel 是為了那張已經調好的深色原生清單(color-scheme + base-select 的燙金選取態),
   但四邊框不留:區號跟號碼是同一個欄位,共用底下那條線才讀得出來。中間拉一條細分隔。 */
.dial .sel {
  min-height: 48px;
  border: 0;
  border-right: 1px solid var(--line-soft);
  border-radius: 0;
  background-position: right 8px center;
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  letter-spacing: .04em;
  padding: 0 20px 0 .2em;
  /* 寬度交給格線那一欄。base-select 那段的 min-inline-size: var(--sel-w) 與 480 以下的
     width: 96px 都是給頂欄那兩顆下拉用的,套到這裡會撐破 320 或在分隔線左邊留一塊死區。 */
  width: 100%;
  min-inline-size: 0;
}
.dial .sel:hover {
  color: var(--gold-hi);
}
@supports (appearance: base-select) {
  /* 收合按鈕只留區號。國名在收合處沒有作用 —— 那一格窄,「+62 Indonesia」會折行,
     整串字也把號碼欄擠掉。清單裡兩段都在,選的時候才需要國名。 */
  .dial .sel selectedcontent .dial-n {
    display: none;
  }
  /* 自訂按鈕預設帶 UA 的邊框與內距,整顆歸零,版面交回 .sel 自己。 */
  .dial .sel button {
    all: unset;
    display: flex;
    align-items: center;
  }
  /* 清單字級跟著這一欄放大:.sel 的 11px 是頂欄那兩顆下拉的尺寸,
     225 筆國名用 11px 掃起來太吃力。 */
  .dial .sel option {
    font-size: 14px;
    letter-spacing: .04em;
  }
}
/* 全站那個 1px 金框只會圈住區號那半格,正是這一頁要避開的形狀。
   焦點訊號改由上面的 .dial:focus-within 給整列,鍵盤可見度不變。 */
.dial .sel:focus-visible {
  outline: none;
}
/* 原本區號與號碼走等寬字(數字對齊),但整列的字面比其他欄位大一圈、字距也寬,
   一排欄位看下來只有這一列特別重。改成跟 .field input 同一套 --sans / .04em。 */
.dial input {
  border-bottom: 0;
}
/* 密碼欄右端的顯示切換。按鈕用絕對定位疊上去,不像 .dial 那樣切一格:
   欄位底下那條線要連續,切格會在按鈕左邊再長出一條分隔線。
   輸入框補一段右內距,長密碼才不會鑽到按鈕底下。 */
.pw {
  position: relative;
}
.pw input {
  padding-right: 46px;
}
.pw-eye {
  position: absolute;
  right: 0;
  top: 0;
  /* 讓開底下那 1px,按鈕的底不要壓在線上 */
  bottom: 1px;
  width: 46px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink-dim);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  transition: color var(--t-fast) var(--ease);
}
.pw-eye:hover {
  color: var(--gold);
}
/* 標籤與提示並排。提示自成一行的話,登入表單會被推出一屏高,而登入頁不該出現捲動。
   基線對齊讓 12px 的大寫標籤跟 12.5px 的提示坐在同一條線上;窄到放不下時自己換行,
   那時才多佔一行 —— 只有 320px 這種寬度會遇到,那個寬度本來就已經要捲。 */
.field-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px 12px;
}
.hint {
  font-size: 12.5px;
  letter-spacing: .02em;
  color: var(--ink-dim);
}
/* 錯誤不用第二個色相(DESIGN.md §2)。訊號是三件事疊加:下邊框轉實心金、
   label 轉金、訊息出現。單看邊框會跟 focus 撞色,靠 label 與訊息區分。
   訊息本身不加 .22em —— 那個手勢是給短標籤的,整句話拉開字距沒法讀。 */
.err {
  font-size: 13px;
  letter-spacing: .02em;
  color: var(--gold-hi);
}
/* 用 --gold-hi 不用 --gold:標籤平時已經是 --ink,轉成比 --ink 更暗的 --gold 反而像被關掉。 */
.field.invalid label,
.check.invalid span {
  color: var(--gold-hi);
}
.field.invalid input,
.field.invalid .sel,
.field.invalid .dial {
  border-color: var(--gold);
}
/* 整列都是觸控目標:label 包住方塊與文字,min-height 撐到 44px。
   方塊本身只有 18px,靠 label 補足點擊面積。 */
.check {
  display: grid;
  gap: 6px;
}
.check label {
  display: flex;
  align-items: center;
  gap: 14px;
  min-height: 44px;
  font-size: 13.5px;
  letter-spacing: .02em;
  color: var(--ink);
  cursor: pointer;
}
.check input {
  flex: none;
  width: 20px;
  height: 20px;
  accent-color: var(--gold);
}
/* 同意句裡的兩條連結。金色加髮絲底線就夠:這一行本來就只有一句話,
   再加背景或方框會把勾選列讀成三顆按鈕。 */
.check a {
  color: var(--gold);
  border-bottom: 1px solid var(--line);
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.check a:hover {
  color: var(--gold-hi);
  border-bottom-color: var(--gold);
}
.form-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px 16px;
}
.form-foot .check label {
  min-height: 44px;
}
.link-quiet {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  background: none;
  border: 0;
  font-family: var(--sans);
  font-size: 13px;
  letter-spacing: .02em;
  color: var(--ink-dim);
  cursor: pointer;
  transition: color var(--t-fast) var(--ease);
}
.link-quiet:hover {
  color: var(--gold);
}
.form .btn-gold {
  /* 660px 的卡片配滿寬按鈕會拉成一條 548px 的長條,字被 .22em 字距扯得更散。
     收成內容寬 + 下限,字級從 11 提到 13。 */
  justify-self: center;
  min-width: min(300px, 100%);
  min-height: 56px;
  /* 字級 13 提到 15。外框尺寸不變:寬度由 min-width 的 300px 決定(最長的
     Create Account 放大後仍只佔 275px),高度由 min-height 的 56px 決定
     (內容高 45px)。橫向內距同時從 3.2em 收到 2.6em,並在窄屏改吃 6vw ——
     em 會跟著字級長,320 寬的英文註冊鈕撐開後只離 inset:10px 那條內金線 2px。
     6vw 只在 600 以下小於 2.6em,寬螢幕的內距一如原本。 */
  padding: .9em min(2.6em, 6vw);
  /* 上限 17px。320 寬的英文註冊態(Create Account)在 17px 下內容寬 201.6px,
     連同內距超過格線那一欄,按鈕會撐到離內金線只剩 10px。用 vw 收下限 15px,
     那一格回到 22px 淨空,其他語言與 ~370 以上的寬度仍然拿滿 17px。 */
  font-size: clamp(15px, 4.6vw, 17px);
  /* 17px 底下 normal 行高算出來是 29.4px,加上 .9em 的上下內距就是 60px,
     min-height 的 56px 不再是決定值,外框會憑空長高 4px。釘成 1 讓高度回到 56px。 */
  line-height: 1;
}
@media (max-width: 1100px) {
  /* 頁尾整寬後,右端版權字的右緣是 100% - 6vw;.contact 左緣是 100% - 66px,
     1100px 以下兩者相交。讓出右邊那 66px 就夠,不必用下留白把整條頁尾往上推
     —— 推上去等於在頁尾底下留一大塊空白,頁尾就不貼底了。 */
  .auth > .foot {
    /* .contact 左緣是 100% - 66px,頁尾右緣是 100% - 6vw,只需要補回相交的那一段。
       寫死 76px 會在 834 / 760 把頁尾擠成兩列,首頁那條在同寬度下還是一列。 */
    padding-right: max(0px, 78px - 6vw);
  }
}
@media (max-height: 1010px) {
  .ch {
    /* 下限改成 64px = 固定頂欄 60px + 4px 淨空,也就是上一版註解自己引用過的那個
       實測值(#hall 標題頂端 64.1px)。原本的 84px 其實從來沒讓 vh 那一項生效過:
       這條查詢只在視窗高 ≤1010px 時套用,而 1010 高時 7.6vh 也才 76.8px,永遠小於
       84,clamp 一律卡在下限 —— 手機的每一個尺寸(390/430/360/412/844/926/740 高)
       量到的都是同一個死板的 84px,等於白留一段。改成 64px 之後 7.6vh 才接得上:
       900 高量到 68.4px,844 高量到 64.1px,660 高的邊界 50.2px 再被下限接住。
       捲動定位是 app.js 的 snapEngine 自己算的(stops = panels.map(p => p.offsetTop)),
       面板停穩時上緣就在 y=0,頂欄底端的淨空完全由這道上內距決定;64px 是量出來的
       最緊值 —— 全部 55 個(視窗 x 板塊)組合裡,內容頂端最低就是 64.0px,
       離頂欄底端還有 4px,沒有一格鑽進毛玻璃底下。
       板塊內容是彈性的(#hall 的卡片列用 1fr 撐滿),讓出來的高度由卡片吸收,
       沒有任何一段的底部溢出因此變多。 */
    padding-block: clamp(64px, 7.6vh, 88px) clamp(40px, 5.6vh, 64px);
  }
  .ch-head {
    margin-bottom: 18px;
  }
  .lc-head {
    padding-bottom: 10px;
  }
  .ledger-col ol li {
    padding: 9px 2px;
  }
  .ledger-col ol li:nth-child(n+6) {
    display: none;
  }
  .ledger-col.off {
    margin-top: 38px;
  }
  .ledger-foot {
    margin-top: 18px;
  }
  .rails li {
    padding: 11px 14px;
  }
  .pots li {
    padding: 10px 0;
  }
}
@media (max-height: 660px) {
  .ch {
    /* 同一個 64px 下限,理由跟上面那條一樣:這個高度區間 8.4vh 最大也才 55.4px,
       一樣永遠小於舊的 84,clamp 一樣卡在下限。橫放手機(844x390/926x428/740x360)
       改成 64px 之後量到的就是 64.0px —— #opening 是唯一停在 scrollY=0、
       又會在這個高度溢出而退回 flex-start 的板塊,它是這個下限的最緊情形。 */
    padding-block: clamp(64px, 8.4vh, 88px) 16px;
  }
  .ch-head {
    margin-bottom: 12px;
  }
  .ledger-col ol li:nth-child(n+5) {
    display: none;
  }
  .ledger-col.off {
    margin-top: 28px;
  }
  .vip {
    padding: 22px 20px;
  }
  .prov-wall li {
    font-size: .82rem;
  }
}
@media (max-width: 1080px) {
  .bar-nav, .spine {
    display: none;
  }
  .bar {
    grid-template-columns: auto 1fr auto;
  }
  .bar .brand {
    justify-self: start;
  }
  body[data-page="home"] .bar .brand {
    grid-column: 1;
  }
  .brand img {
    width: min(48vw, 330px);
    height: auto;
  }
  .door {
    flex-basis: min(48vw, 210px);
    max-width: 210px;
    min-height: clamp(54px, 7vh, 72px);
  }
}
@media (max-width: 900px) {
  .spot-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  /* 桌機是四欄一列、八張同尺寸;窄屏改成半列的錯落牆:小卡佔兩條半列、大卡佔三條,
     兩欄的接縫永遠對不齊,看起來就是不規則的。
     半列是關鍵。整列的網格只給得出「一列」與「兩列」兩種高度,而兩列的卡等於把封面
     拉成 0.49 的細長條,跨兩欄的那張又壓成 2.53 的扁片(390 下實測)—— 遊戲封面
     放不進那兩種框。半列之後大卡只比小卡高一半,比例就收在 0.65~1.7 這一帶。
     列高一律 1fr,整格還是吃滿板塊剩下的高度,所以照樣一屏一板塊。
     位置寫死不靠自動排版:混跨度的自動排版排到最後會多開一條隱含列,那條列沒有 1fr,
     整格就撐出板塊外面。
     五條是 16:9 這一帶的老手機與橫持裝置用的 —— 板塊高度只有欄寬的 2.5~2.7 倍,
     切六條的話小卡只剩 83px 的封面(1.93 的扁片)。真正的高螢幕在下面那段換六條。 */
  #hall .spot-grid {
    grid-template-rows: repeat(5, minmax(0, 1fr));
  }
  #hall .spot-grid .g-card:nth-child(1) {
    grid-area: 1 / 1 / 4 / 2;
  }
  #hall .spot-grid .g-card:nth-child(2) {
    grid-area: 1 / 2 / 3 / 3;
  }
  #hall .spot-grid .g-card:nth-child(3) {
    grid-area: 3 / 2 / 6 / 3;
  }
  #hall .spot-grid .g-card:nth-child(4) {
    grid-area: 4 / 1 / 6 / 2;
  }
  #hall .spot-grid .g-card:nth-child(n+5) {
    display: none;
  }
  #hall .spot-grid .g-meta {
    padding: 9px 10px 10px;
    gap: 6px;
  }
  #hall .spot-grid .g-info h3 {
    font-size: 12.5px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  #hall .spot-grid .g-info p {
    font-size: 10px;
  }
  #hall .spot-grid .g-rtp {
    font-size: 10px;
  }
  .ledger-cols {
    grid-template-columns: 1fr;
  }
  /* 桌機是兩欄並排,「提款」那欄的上外距是刻意的錯位。窄屏兩欄疊成一欄之後,
     那段錯位就變成存款與提款之間憑空多出來的一截:實測 390x844 是 68px
     (28px 的格線間距再加 40px 外距),而下面「支付方式 / 開獎」離提款只有 18px、
     兩份清單彼此 28px —— 同一屏三種節奏。錯位歸零,三處一律吃同一條間距。 */
  .ledger-col.off {
    margin-top: 0;
  }
  .ledger-foot {
    margin-top: clamp(28px, 4.5vw, 80px);
  }
  .rails ul {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .cards {
    grid-template-columns: 1fr;
  }
  .cards .invite:nth-child(2), .cards .invite:nth-child(3) {
    margin-top: 0;
  }
  /* 請柬那一屏在窄屏是三張固定高的卡疊起來,實測 390x844 整段 977px、超出一屏 133px,
     一個板塊要捲兩次才看得完。改成跟 #hall 的精選格同一招:整組卡吃掉板塊剩下的高度,
     三張各分三分之一,內距、行距與標題字級都跟著視窗高縮 —— 一屏放得下。 */
  #invite .cards {
    flex: 1 1 auto;
    min-height: 0;
    grid-template-rows: repeat(3, minmax(0, 1fr));
    gap: clamp(10px, 1.6vh, 20px);
    /* 桌機那三張是階梯式錯位、各自貼齊自己的內容高(align-items: start);
       這裡三張各分一列,不撐滿就會在每張下面留一塊大小不一的空白。 */
    align-items: stretch;
  }
  #invite .invite {
    min-height: 0;
    gap: clamp(6px, 1.4vh, 22px);
    padding: clamp(12px, 2.4vh, 26px) clamp(16px, 4.4vw, 30px);
  }
  #invite .invite h3 {
    font-size: clamp(1.1rem, 2.5vh, 2rem);
  }
  .foot .rights {
    margin-left: 0;
  }
}
/* 現代直立手機的螢幕比是 0.46 上下(390x844、414x896、430x932),板塊高度是欄寬的
   3.5 倍以上,五條半列會把大卡拉到 0.55 的細長條。這一帶換六條:大卡回到 0.69,
   小卡 1.22,順便多排得下一張(五張)。門檻取 0.52 —— 落在 0.46 那群與 16:9 老機
   (375x667 = 0.56)中間,兩邊都有一成餘裕,網址列縮放不會讓版面在捲動中翻面。 */
@media (max-width: 600px) and (max-aspect-ratio: 13/25) {
  #hall .spot-grid {
    grid-template-rows: repeat(6, minmax(0, 1fr));
  }
  #hall .spot-grid .g-card:nth-child(n+5) {
    display: flex;
  }
  #hall .spot-grid .g-card:nth-child(3) {
    grid-area: 3 / 2 / 5 / 3;
  }
  #hall .spot-grid .g-card:nth-child(4) {
    grid-area: 4 / 1 / 7 / 2;
  }
  #hall .spot-grid .g-card:nth-child(5) {
    grid-area: 5 / 2 / 7 / 3;
  }
  #hall .spot-grid .g-card:nth-child(n+6) {
    display: none;
  }
}
@media (max-width: 600px) and (orientation: portrait) and (min-aspect-ratio: 13/25) {
  /* 五條半列、四張卡。磚塊讓出來的高度給右上那張封面(320x568 實測 160.8 → 179.2),
     右下那張維持兩條列 —— 再往上讓的話右上只剩 92.8px,封面被壓成 1.44 的扁片。 */
  #hall .spot-grid .g-card:nth-child(2) {
    grid-area: 1 / 2 / 4 / 3;
  }
  #hall .spot-grid .g-card:nth-child(3) {
    grid-area: 4 / 2 / 6 / 3;
  }
}
@media (max-width: 600px) and (orientation: portrait) and (max-aspect-ratio: 13/25) {
  /* 六條半列。右欄兩張各佔三條,跟左欄那兩張同高 —— 磚塊原本吃掉的兩條列
     全數還給封面,390x844 實測右上 203.1 → 237.6、右下 203.1 → 310.7。 */
  #hall .spot-grid .g-card:nth-child(2) {
    grid-area: 1 / 2 / 4 / 3;
  }
  #hall .spot-grid .g-card:nth-child(3) {
    grid-area: 4 / 2 / 7 / 3;
  }
  #hall .spot-grid .g-card:nth-child(5) {
    display: none;
  }
}
/* 601~900 是横持手機與小平板。兩欄在這裡的問題不是列高是欄寬:欄寬會長到 256~388px,
   半列高度沒跟著長,封面就被壓成 1.7~2.6 的扁片。改三欄,欄寬回到 168~256。 */
/* 第二、三屏的上緣。.ch 的上內距在 @media (max-height: 1010px) 是
   clamp(64px, 7.6vh, 88px),那條下限 64px 對上 60px 高的頂欄只剩 4px ——
   凡是 vh 算出來不到 64 的畫面都會落在下限上:390x844 量到 64.1px、
   1024x768 與 1366x768 都是 64px,門排與請柬最上面那條邊看起來是貼在頂欄底下的。
   下限抬到 78px,離頂欄 18px。係數順帶從 7.6vh 提到 8.6vh,讓中間尺寸接得上
   —— 768x1024 解出 88px、430x932 解出 80.2px,跟改之前一模一樣,只有本來落在
   下限上的那些畫面真的往下走。
   視窗高超過 1010px 的畫面走 .ch 自己那條 clamp(64px, 8vh, 120px),8vh 已經
   80px 以上,本來就不在下限上,所以這段只管 1010 以下。
   只給這兩屏 —— 第一屏是置中的主視覺、第四屏本來就要捲兩段,兩邊都不缺這段留白。
   這兩屏在桌機是「門排 + 格子」的彈性直欄(#hall .spotlight 是 flex: 1 1 auto),
   多出來的上內距由格子自己吸收:1024x768 實測格子 593 → 579,卡片比例照舊,
   底下那行捲動提示與板塊底距離一格沒動。 */
@media (max-height: 1010px) {
  #hall,
  #invite {
    padding-top: clamp(78px, 8.6vh, 96px);
  }
}
/* 第四屏的下緣。右下角那疊懸浮鈕收起來也有 46px,離視窗底 22px,等於固定佔住
   最下面 68px。金流那屏比一個視窗高,整屏引擎的最後一個落點正好把板塊底對齊視窗底,
   最後一列開獎倒數就壓在那顆鈕底下。補一段比 68px 再寬一點的下內距,最後一列讓開。
   (捲到一半時仍會有別的列從鈕底下經過 —— 那是固定鈕本來就有的,靠停手兩秒淡到
   .34 那條規則收尾,不是這裡能解的。) */
@media (max-width: 900px) and (orientation: portrait) {
  #ledger {
    padding-bottom: 84px;
  }
}
@media (min-width: 601px) and (max-width: 900px) {
  .spot-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}
/* 601~760 的欄寬只有 168~215,板塊高度是它的 3 倍以上,跟直立手機同一種比例,
   切六條半列。七張:左右兩欄各兩張大的,中欄三張小的,三欄的接縫互相錯開。 */
@media (min-width: 601px) and (max-width: 760px) {
  #hall .spot-grid {
    grid-template-rows: repeat(6, minmax(0, 1fr));
  }
  #hall .spot-grid .g-card:nth-child(n+5) {
    display: flex;
  }
  #hall .spot-grid .g-card:nth-child(3) {
    grid-area: 1 / 3 / 4 / 4;
  }
  #hall .spot-grid .g-card:nth-child(4) {
    grid-area: 3 / 2 / 5 / 3;
  }
  #hall .spot-grid .g-card:nth-child(5) {
    grid-area: 4 / 1 / 7 / 2;
  }
  #hall .spot-grid .g-card:nth-child(6) {
    grid-area: 4 / 3 / 7 / 4;
  }
  #hall .spot-grid .g-card:nth-child(7) {
    grid-area: 5 / 2 / 7 / 3;
  }
  #hall .spot-grid .g-card:nth-child(n+8) {
    display: none;
  }
}
/* 761~900 的欄寬回到 215~256,板塊高度卻沒長多少(横持手機更是只有欄寬的 2.3 倍),
   六條會把小卡壓成 1.9、大卡壓成 3.9 的扁片。這一段切五條,六張:每欄一大一小,
   大小的位置逐欄對調,接縫照樣錯開。 */
@media (min-width: 761px) and (max-width: 900px) {
  #hall .spot-grid {
    grid-template-rows: repeat(5, minmax(0, 1fr));
  }
  #hall .spot-grid .g-card:nth-child(n+5) {
    display: flex;
  }
  #hall .spot-grid .g-card:nth-child(3) {
    grid-area: 1 / 3 / 4 / 4;
  }
  #hall .spot-grid .g-card:nth-child(4) {
    grid-area: 3 / 2 / 6 / 3;
  }
  #hall .spot-grid .g-card:nth-child(5) {
    grid-area: 4 / 1 / 6 / 2;
  }
  #hall .spot-grid .g-card:nth-child(6) {
    grid-area: 4 / 3 / 6 / 4;
  }
  #hall .spot-grid .g-card:nth-child(n+7) {
    display: none;
  }
}
/* ── 直屏:精選格八家全列 ────────────────────────────────────────── */
@media (max-width: 1080px) and (orientation: portrait) {
  /* 精選格:八家全列,不再只露四、五家。
     以前這一格是「一屏放得下多少就放多少」—— 五條或六條半列、手工指定每張卡的
     grid-area、第五張之後一律 display: none。八張要在同一屏擺完的話每張只剩百來
     像素高,封面壓成扁片;而這一格擺的是供應商品牌卡,漏掉三家等於首頁自己不承認
     有那三家。改成齊排:兩欄、列高由封面的 4/3 加卡腳自己定,板塊順著長高。
     #hall 因此會比一個視窗高 —— snapEngine 的 landings() 早就認得「比視窗高的板塊
     要分段停」,一次捲動仍然走一整個視窗高,只是這一屏要走兩下才到下一屏。 */
  #hall .spotlight {
    flex: 0 0 auto;
  }
  #hall .spot-grid {
    flex: 0 0 auto;
    grid-template-rows: none;
    grid-auto-rows: auto;
  }
  /* :nth-child(n) 只為了把權重補到跟上面那幾條手工落點一樣,好讓後寫的這條贏 ——
     它本身命中每一張卡,沒有篩選作用。 */
  #hall .spot-grid .g-card:nth-child(n) {
    display: flex;
    grid-area: auto;
    margin-top: 0;
  }
  #hall .spot-grid .g-art {
    aspect-ratio: 4 / 3;
    flex: 0 0 auto;
  }
}
/* 直放平板把 .spine 收回來。上面那條 1080 的規則把 .bar-nav 與 .spine 一起關掉,
   .bar-nav 關得對 —— 量過 744~1080 這一段,目錄與品牌標都落在 .bar 的第一欄、
   整塊疊在一起,要並排得到 1133px 才夠寬。但 .spine 是固定定位的,不佔頂欄一格,
   關掉它等於 index.html 在每一台直放 iPad(744/768/810/820/834/1024)上一個
   段落入口都沒有,那是一頁五段的長捲頁。
   只在直放開:横放的瀏海機(844/926/932)寬度也落在這一段,而横放時
   safe-area-inset-right 有 44~59px,固定在右緣的東西不是壓在感測器底下、
   就是被推進門卡裡;直放的側邊安全區一律是 0,沒有這個問題。
   right 從 22 收到 8:.ch 的右內距是 clamp(20px, 6vw, 120px),744px 時只有
   44.64px,而點名中的那條線本身 36px 寬 —— 22 起算會壓到門卡上,8 起算收在
   44px,整條留在留白裡。摺疊機內屏(673px,留白約 40px)放不下,維持不顯示。 */
@media (min-width: 744px) and (max-width: 1080px) and (orientation: portrait) {
  .spine {
    display: flex;
    right: 8px;
  }
}
@media (max-width: 760px) {
  .rail {
    display: none;
  }
  .lobby {
    grid-template-columns: minmax(0, 1fr);
  }
  .dock {
    display: grid;
  }
  /* 底部 .dock 是 fixed 的,要靠 .hall 的下留白讓開 */
  .hall {
    padding-bottom: calc(96px + env(safe-area-inset-bottom));
  }
  /* 窄屏的牆是齊排:兩欄,每張卡同高,接縫一路對齊。
     以前這裡是錯落排 —— 卡高在「兩條半列」與「三條半列」之間輪替,兩欄的接縫永遠
     對不齊。那一版的代價是高卡沒有自己的內容高度可吃,封面得解除 4/3 去填分配到的
     剩餘高度,同一面牆上封面就有兩種比例,矮的那種還會把圖壓扁。窄屏第一位的是
     封面本身要完整,不是版面要有花樣,所以錯落取消,列高由封面的 4/3 加卡腳自己定。
     列高走 auto,不走 1fr 的等高半列:1360 張封面現在一律是 640x480,框只要不是
     4/3 就會在圖的左右留出一條空帶(390 下量到 12px、430 下 16.5px、320 下 35px)。
     半列制下寬卡跨三條、格子比例算出來是 1.43~1.46,怎麼分都對不上 4/3;改成每一列
     自己照內容長高,寬卡那一列就是「封面 4/3 + 卡腳」的和,框剛好貼著圖,零留邊。
     排版走 row 不走 dense:dense 會把後面的卡抓回來補洞,而這面牆的順序是排過的
     (見 app.js 的 marketOrder(),有標籤的排前面),補洞等於把它打散。 */
  .case-grid {
    grid-template-columns: repeat(2, 1fr);
    grid-auto-rows: auto;
    grid-auto-flow: row;
  }
  /* 主打那張橫幅跨滿兩欄,列高由它自己的內容定 —— 390 下量到 352 寬配 264 高,
     正好是封面的 4/3,後面那面牆在第一屏還是露得出來。 */
  .case-grid .g-card.wide {
    grid-column: span 2;
  }
  .pnl-nav > .hcue {
    display: block;
  }
  /* 收藏星星在卡片右上角,而懸浮鈕固定在視窗右下那條 66px 寬的帶子上,捲到哪張卡對上
     它,那顆星的中心點就點不到。桌機那一段是讓卡片欄往左讓 30px,這裡讓不起 ——
     兩欄總共只有 324px,再讓就換成卡片名字塞不下。改成跟左上角的標籤對調:標籤是
     純文字、點不到也沒差,星星換到左上就永遠離那條帶子最遠。實測 320~1024 共七個
     寬度、十一頁,被遮住的可點元素從 1 個降到 0。 */
  .case-grid .g-fav {
    right: auto;
    left: 8px;
  }
  .case-grid .g-tag {
    left: auto;
    right: 10px;
  }
  body[data-page="lobby"] .contact {
    bottom: calc(78px + env(safe-area-inset-bottom));
  }
  /* 頂欄在這個寬度只放得下語言選單加一顆按鈕:商標本來就在縮,再擠一顆會縮到看不清。
     留下的是註冊那顆 —— 訪客在窄屏要做的第一件事是開戶,不是登入,而且金底那顆
     在只有一顆按鈕時才撐得起頂欄右側的重量;登入從註冊頁的頁籤一下就到。
     登入了則換成 VIP 金庫(data-when="in" 那顆,金底的註冊自己會被 [hidden] 收掉),
     所以這條只砍未登入態的那顆,不是整個 .btn-ghost。 */
  .bar .btn-ghost[data-when],
  .bar .trial-pill {
    display: none;
  }
}
/* 761 起 .rail 那條 300px 側欄長回來,牆自己只剩 420～630px —— 還是兩欄,卻掉出上面
   那段的範圍,寬卡退回普通卡,整面牆變成三十二張一模一樣的小卡。1024 那道門檻本來擋的
   是「兩欄下寬卡佔滿整行、封面被兩列壓扁」,但那是牆有整個視窗寬時的算法:這一段的牆
   窄了一半,寬卡佔滿一行也才 420～630 寬配相近的高,比例落在 0.95～1.10,跟 760 以下
   同一族。所以這裡接回兩欄那一套,768 的直放平板跟 390 的手機有同一種節奏。
   欄數寫死兩欄:auto-fill 在 761～767 只排得出一欄(420px),單欄下 span 2 會長出一條
   隱含欄把整頁撐橫。 */
@media (min-width: 761px) and (max-width: 1023px) {
  .case-grid {
    grid-template-columns: repeat(2, 1fr);
  }
  /* 跟 760 以下同一招:列高走 auto,寬卡只跨欄不跨列,格子高度由「封面 4/3 + 卡腳」
     自己定。以前這裡是兩欄兩列的等高半列,寬卡的格子比例量到 1.04(768)到 1.06(810),
     比封面方得多 —— 只能靠 cover 從左右各裁掉一成一才填得滿,西部場景那幾張的木牌
     字標就貼著邊。框改成貼著圖之後裁切歸零。 */
  .case-grid .g-card.wide {
    grid-column: span 2;
  }
  /* 主打卡的卡腳比小卡重一級,兩欄寬的封面下面配一條同樣份量的資訊帶。
     字級不跟著放大:這一段是 768 的直放平板與手機橫放(844x390、932x430)共用的,
     窄屏上主打卡靠封面就站得住主位,再放大一級的卡名在 390 高的視窗裡是實打實的
     一條可見高度。放大一級只留給 1024 起的寬屏。 */
  .case-grid .g-card.wide .g-meta {
    padding: 20px 22px 22px;
  }
}
@media (max-width: 600px) {
  /* 實測 390px 下 .doors scrollWidth 1470 / clientWidth 341,七個分類只露出 1.6 個,
     整條又被邊框框住,看不出還能橫捲。收窄到讓第三個露一半 —— 半截的項目本身
     就是最好懂的「還有更多」訊號,不必額外加淡出遮罩(.beam 那邊實測 mask-image
     在 iPhone 會掉到 50ms/幀,能不用就不用)。 */
  .door {
    flex-basis: min(36vw, 150px);
  }
}
@media (max-width: 560px) {
  .brand img {
    height: auto;
    width: min(50vw, 230px);
  }
  /* 兩顆主按鈕在窄屏各吃半行。照內容寬排的話,四種語言會排出四種版型 —— 中文那顆
     只有三、四個字,換成英語或印尼語的同一顆是它的兩倍寬,窄到某個寬度就擠不進
     同一行,整組掉成上下兩顆,而那個寬度每種語言都不一樣。
     等分之後每個寬度、每種語言都是同一個樣子:兩顆等寬並排、在線人數獨佔第二行。
     字太長就折行(這裡要解掉 .btn-gold 的 nowrap,那條是給頂欄那兩顆用的),
     balance 讓兩行長度接近,stretch 讓折了行的那顆跟另一顆一樣高。 */
  .hero-ctas {
    align-items: stretch;
  }
  .hero-ctas .btn-gold {
    flex: 1 1 0;
    min-width: 0;
    white-space: normal;
    text-wrap: balance;
    padding-left: 1em;
    padding-right: 1em;
  }
}
@media (max-width: 480px) {
  .bar {
    padding: 0 14px;
    gap: 10px;
  }
  .sel {
    padding: 5px 18px 5px 6px;
    font-size: 10px;
    width: 96px;
  }
  /* 用 id 而不是 .sel:上面 base-select 那段是 #prov 設 --sel-w,
     權重比 .sel 高,寫在 .sel 上蓋不掉,手機就會被桌機寬度撐開。 */
  #prov {
    --sel-w: 96px;
    line-height: 15px;
  }
  /* 標籤收起來之後,剩下的箭頭本體只有 11x11 —— 連 WCAG 2.5.8 的 24x24 都構不到,
     更別說本站自己訂的 44x44。圖示放大到 20px 先讓它看得見,可點範圍再用一層
     透明的 ::after 撐到 44x44。用偽元素不用內距:.back 在頂欄格線的第一軌,
     加內距會把整條軌道撐寬,商標跟著往右挪。 */
  .bar .back span {
    display: none;
  }
  .bar .back {
    position: relative;
    /* .brand 也是定位元素而且排在後面,不給 z-index 的話它會壓掉下面那塊
       命中區右邊 4px —— 箭頭右側一點點會變成「回首頁」而不是「上一頁」。 */
    z-index: 1;
    font-size: 20px;
  }
  .bar .back::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 44px;
    height: 44px;
    transform: translate(-50%, -50%);
  }
}
/* 窄屏的語言選單:地球圖示 + 一兩個字的縮寫。字是 app.js 換的(LANG_ABBR),
   這裡只補圖示跟收寬度。圖示畫成 data URI 而不是用圖示字型 —— fonts/icons.css
   那 21 個字裡沒有地球/語言/翻譯,而背景圖不吃額外請求,也就沒有被擋掉的可能。
   位置刻意排在 480 那段後面:那段用 #prov 設了 --sel-w 與 width,權重跟這裡
   同分,同分時後者勝 —— 寫在前面會被它蓋回 96px。
   #prov 不在這條規則裡:大廳那顆是遊戲商篩選,選項是專有名詞,縮不得。 */
@media (max-width: 600px) {
  /* 窄屏把這一層釘死在 .ch 的內容寬。不釘的話它是 .ch 這條直排 flex 的項目,寬度
     由最寬的子項撐出來 —— 獎池那排刻意比內容寬多出 10px,整個 .hero-inner 就被它
     一起撐寬,底下兩顆按鈕(這個寬度是 flex:1 1 0,照容器寬等分)跟著長到同寬,
     兩端又貼齊了,那 10px 的超出等於白做。釘住之後多出來的是獎池自己溢出去的,
     兩側各 5px 落在 20px 起跳的內距裡,捲動寬度沒有變。
     只寫在窄屏:600px 以上獎池本來就比按鈕列寬好幾倍,沒有要對齊的東西,
     釘上去只會平白改掉桌機每一個寬度的盒子尺寸。 */
  .hero-inner {
    width: 100%;
  }
  /* 三行副標在窄屏更佔位:上緣收一點,下緣照樣拉開,讀的那半與點的那半分得清楚。 */
  .hero-sub {
    margin-top: clamp(6px, 2vh, 24px);
  }
  .hero-ctas {
    margin-top: clamp(16px, 3.4vh, 34px);
  }
  /* 面板跟著縮寫收窄:清單裡也是縮寫,最寬的一項只有兩個字。
     靠右對齊收合的鍵,兩者的右緣連成一條線。 */
  .lang-list {
    min-width: 66px;
  }
  .lang-list li {
    font-size: 13px;
  }
}
/* 兩欄下卡片只有 172px 寬,資訊條左右排時名字那格只剩 79px —— 「Aurum Rush」
   斷成兩行、「Pragmatic Play」再斷一次,資訊條自己吃掉 99px,封面只剩 127px。
   440 以下改直排:三行各自吃滿卡寬,最長的名字也只有一行。
   440 以上的欄寬夠(480 下量到 122px 的名字格),維持左右排 —— 那是原本的樣子;
   360 以下是單欄、卡片有 284px 寬,同樣不必直排;大卡跨兩欄也有 354px,一起排除。 */
@media (min-width: 361px) and (max-width: 440px) {
  .case-grid .g-card:not(.wide) .g-meta {
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    padding: 10px 12px 11px;
  }
}
@media (max-width: 360px) {
  /* 大廳這裡另外扣掉 .case-grid 讓給懸浮鈕的 30px 右內距,兩欄只剩 120px —— 廠商名
     與 RTP 擠成兩行還是塞不下。這一級退回單欄,寬卡跟著解除跨格(單欄下 span 2 會
     長出一條隱含欄,整頁橫向溢出)。 */
  .case-grid {
    grid-template-columns: minmax(0, 1fr);
  }
  /* 封面框不再壓成 16/9。那個比例是為了「一張卡不要吃掉大半個螢幕」而設的,代價是
     4/3 的封面在框裡左右各留 35~40px 的空帶 —— 這一級每一張卡都在漏邊,漏得比任何
     一個斷點都寬。框回到 .g-art 預設的 4/3(320 下量到 282x211.5),圖貼滿,一屏
     仍看得到一張整卡加下一張的開頭。 */
  .case-grid .g-card.wide {
    grid-column: auto;
  }
  /* 兩欄卡片縮到 134px 之後,「Pragmatic Play」會折行而「PG Soft」不會,
     同一列兩張卡的圖片高度就差一截;標題也被 ellipsis 砍成「Aurum...」。
     把 meta 從左右排改成上下排,三行各自獨佔整個卡寬:標題和廠商都完整顯示,
     四張圖高度一致(量到都是 136px),整段高度不變。 */
  /* 資訊條直排之後有三行,而這一級的半列只有 61px 高 —— 74px 的資訊條會把封面
     擠成 61px(比例 2.17 的扁片)。三行照排,字級與內距收一輪把資訊條壓到 48px,
     封面就回到 1.5 上下。 */
  #hall .spot-grid .g-meta {
    flex-direction: column;
    align-items: flex-start;
    gap: 1px;
    padding: 6px 9px 7px;
  }
  #hall .spot-grid .g-info h3 {
    font-size: 11.5px;
  }
  #hall .spot-grid .g-info p {
    font-size: 9px;
    margin-top: 0;
  }
  #hall .spot-grid .g-rtp {
    font-size: 9px;
  }
}
@media (min-width: 1800px) {
  .case-grid {
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  }
  .lobby {
    grid-template-columns: 300px minmax(0, 1fr);
  }
  /* 這個寬度長得出六到八欄,第五張卡還擠得進第一行,§5 那條 nth-child(5) 擋板就漏了。
     八欄要第九張才保證有第二行(1 + 2 + 6 = 9 格),門檻在這裡往上抬。數法同 §5。 */
  .case-grid .g-card:first-child:nth-last-child(-n+8).wide,
  .case-grid .g-card:first-child:nth-last-child(-n+8) ~ .g-card.wide {
    grid-row: auto;
  }
}
/* ── 手機橫放 ─────────────────────────────────────────────────────
   橫放的手機是「很寬但很矮」:844x390 / 932x430 / 740x360。寬度落在 740~932,
   照寬度分流的話它會拿到平板那一套兩欄大卡 —— 實測 932x430 下第一張卡量到
   579x567,比整個視窗還高,一屏連一張遊戲都看不完整。這一段照高度分流,是全站
   唯一一個「寬度不算數」的斷點,所以刻意排在所有寬度斷點之後:同分時後者勝,
   上面那幾段的兩欄與錯落跨度在這裡全部退掉,不必逐條加權重。
   max-height: 500px 是門檻:目前最高的橫放手機是 430px(iPhone 16 Pro Max),
   而最矮的橫放平板是 744px(iPad mini),中間空得很開,500 兩邊都不會誤傷。 */
/* 側欄從 256 收到 204:932 寬的視窗裡 256 吃掉 27%,而最長的兩個分類名
   「Semua Game」與「Live Casino」在 204 下都還是一行(188 時前者會折)。
   省下的 52px 剛好夠牆多長半欄。
   要加 min-width: 761 —— 760 以下 .rail 是 display: none,兩欄只剩 .hall 一個
   格子項,它會落進第一條軌道,整面牆被壓成 188px 寬。 */
@media (orientation: landscape) and (max-height: 500px) and (min-width: 761px) {
  .lobby {
    grid-template-columns: 204px minmax(0, 1fr);
  }
  .rail {
    padding: 12px 0 24px;
  }
}
@media (orientation: landscape) and (max-height: 500px) {
  /* 上留白跟著側欄收,兩欄仍然同一條基線(.hall 的註解) */
  .hall {
    padding-top: 12px;
    padding-bottom: 40px;
  }
  .hall-head {
    gap: 12px;
  }
  .case-grid {
    /* 矮視窗要的是「一屏看得到兩排」。136px 的欄配 4/3 封面是 102px 的圖加上
       資訊條,一張卡量到 175px 上下,兩排加間距 362px —— 430 高的視窗扣掉 60px
       頂欄還剩 370,剛好停得住;390 高的視窗看得到一排半,半張卡本身就是
       「還有更多」的訊號(.door 那條註解是同一個判斷)。 */
    grid-template-columns: repeat(auto-fill, minmax(136px, 1fr));
    grid-auto-rows: auto;
    grid-auto-flow: row;
    gap: 12px;
    margin-top: 16px;
  }
  /* 主打橫幅在這裡退掉。跨兩欄的大封面在 430px 高的視窗裡就是一張看不完的圖,
     退回普通卡之後每一格都是同一個 4/3,一屏正好兩排。 */
  .case-grid .g-card.wide {
    grid-column: auto;
  }
  /* 欄寬 152px 的卡腳左右排不下:「Spadegaming」與「RTP 96.9%」會疊在一起,
     卡名也被 ellipsis 砍掉。改成上下三行,每行各自吃滿卡寬 —— 跟 440 以下那段
     兩欄卡是同一招,只是那一段照寬度分流,碰不到這裡。 */
  .case-grid .g-meta {
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    padding: 10px 12px 11px;
  }
  /* 760 以下的橫放(740x360)走的是底部 .dock 那一套,而 .dock 原本要 96px 的
     下留白 —— 360 高的視窗那是 27%。圖示與字級收一輪,量到 62px。 */
  .dock a, .dock button {
    padding: 6px 0 calc(6px + env(safe-area-inset-bottom));
    font-size: 9px;
  }
  .dock i {
    font-size: 16px;
  }
}
@media (orientation: landscape) and (max-height: 500px) and (max-width: 760px) {
  .hall {
    padding-bottom: calc(66px + env(safe-area-inset-bottom));
  }
}

/* 減動版不看系統設定,只看網址 —— 跟開場帘幕同一條規矩(intro.js 開頭那段註解)。
   Windows 的「動畫效果」預設就是關的,WSL/遠端桌面/省電模式/某些企業原則也會替使用者
   打開它,一台一個樣;這份樣本要展示的正是這些動效,被那顆開關砍掉就等於沒有東西可看。
   要看減動版仍然拿得到:網址加 ?motion=reduce。html.motion-full 由每一頁 <head> 的
   第一支腳本掛上(第一次繪製之前就決定,不會閃),沒有那個 class 才吃下面這一段。
   下面的規則本身一字未動:減動時只砍位移,不砍淡入 —— 透明度變化不會引發前庭不適,
   連淡入一起砍掉元素會硬跳出來,比不做還糟。JS 那半在 app.js 的 REDUCE。 */
html:not(.motion-full) *,
html:not(.motion-full) *::before,
html:not(.motion-full) *::after {
  transition-property: opacity, color, background-color, border-color, box-shadow, filter !important;
}
/* 這三處原本的 transition 只管 transform / border-color / color,上面那條把 opacity
   塞了進去 —— 而它們的 opacity 正好是 GSAP 進場動畫逐幀在寫的。GSAP 每寫一幀,
   CSS 就再花 .35~.55s 慢慢往新值補,兩層疊起來把進場整整拖慢 400~570ms:
   .g-card 全亮從 +1208ms 變成 +1683ms、.invite 從 +958ms 變成 +1531ms,
   而沒有 transition 的 .door / .rails li 完全不受影響。
   把 opacity 從這三個的清單拿掉,GSAP 寫什麼畫面就是什麼。
   日後若替 enter() 的目標加上 hover 轉場,記得一起加進這條。 */
html:not(.motion-full) .can-r > .hcue-r::after {
  animation: none !important;
}
html:not(.motion-full) :is(.g-card, .invite, .prov-wall li) {
  transition-property: color, background-color, border-color, box-shadow, filter !important;
}
/* 掃光 .beam 刻意不關掉。它是 12.5s 一輪的自主循環動態,WCAG 2.2.2 要求超過 5 秒的
   自動動態要能暫停,而這頁沒有暫停鍵,所以這是一個明知故犯的例外 —— 判斷跟開場帘幕
   一樣:這道光是整頁質感的主體,在減動下把它變成 display: none,使用者看到的不是
   「動效收斂了」而是「網頁壞了」(這個回報實際發生過三次:游標光暈、開場帘幕、這道掃光)。
   真要補合規,正解是加一個全站「暫停動態」開關,不是把單一元素抹掉。
   .cursor-light 同理不關:它只跟著指標走,指標不動它就不動,
   不是自主動態,關掉只是白白拿走一個手感。 */
html:not(.motion-full) :is(.brand img, .brand::before, .ledger-col ol li.new) {
  animation: none;
}
/* .scroll-cue 的可見度整個靠 cueBreath 的關鍵影格給,animation 一關就變全透明 */
html:not(.motion-full) .scroll-cue.on {
  animation: none;
  opacity: .68;
}
/* 開場帘幕整片拉到畫面兩側,走跟一般模式同一條路,不再收位移 ——
   曾經收成 18%,實際看起來就是「只開了一條縫」。
   這裡唯一要做的是把 transform 補回轉場清單:上面那條全域規則會把它剝掉,
   而剝掉之後終點值照樣套用,門會直接瞬移出畫面,連掃開的過程都看不到。
   .progress span 是同一個坑,而且它是確定型的載入回饋不是裝飾動態,
   WCAG 2.3.3 本來就不列管;被壓成瞬間填滿的話,進度條說完成了、
   提示文字卻還要再等 2.9 秒。 */
html:not(.motion-full) :is(.vault-door, .progress span) {
  transition-property: transform !important;
}
/* Windows 高對比:燙金字是 color:transparent + background-clip:text 疊出來的,
   系統把背景換成純色之後整排字會直接消失。這幾處退回系統文字色。 */
@media (forced-colors: active) {
  .gold-text, .jack .col span, .jack .sep {
    background: none;
    -webkit-background-clip: border-box;
    background-clip: border-box;
    color: CanvasText;
    -webkit-text-fill-color: CanvasText;
  }
  .jack {
    filter: none;
  }
  .beam, .cursor-light {
    display: none;
  }
  /* 登入頁的焦點訊號是「底線轉金 + 金色外發光」。強制色彩會把 box-shadow 抹成 none、
     邊框色交給系統,兩層訊號同時消失,而那條規則又寫了 outline: none。這裡補回系統焦點框。 */
  .field input:focus-visible,
  .dial:focus-within {
    outline: 2px solid Highlight;
    outline-offset: 2px;
  }
}
/* ============================================================
   金庫章程 —— 三卷法務文件(terms.html / privacy.html / responsible.html)
   三頁共用這一塊,所以寫在 style.css 而不是各頁自己的 <style>:ledger 抄 panel
   那份表格樣式是因為原檔已經寫在 panel.html 裡拿不到,這裡是全新的元件,
   複製三份只是三倍的維護面。全部選擇器都掛在 .doc* 底下,既有六頁碰不到。

   一頁一張請柬:外金線 + inset 10px 的內細線,標題與全部條文都寫在同一個框裡,
   由上讀到底,中途不再有第二個框、第二條導覽或旁邊的目錄軌 —— 這一頁只有一件事要做。
   外殼直接沿用 .invite,理由同 auth.html:站上已經有一套雙金框,不造第二套。
   轉場一律只寫 color / background-color:減動的全域規則會把 transform 剝掉,
   而這一頁本來就沒有位移可收。
   ============================================================ */
.doc {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-height: 100vh;
  /* 理由同 .auth:網址列還在時 100vh 會比可視高度大一截 */
  min-height: 100svh;
  padding: clamp(84px, 9vh, 112px) clamp(20px, 6vw, 120px) clamp(28px, 3.4vh, 48px);
  padding-left: max(clamp(20px, 6vw, 120px), env(safe-area-inset-left));
  padding-right: max(clamp(20px, 6vw, 120px), env(safe-area-inset-right));
}
.doc > * {
  /* 760 是由量度回推的:內距在 1440 下是 64,兩邊扣掉剩 632px,
     15px 的 Jost 約 72ch —— 長文讀起來還在舒適區,而框沒有寬到讓右邊空出死區。
     舊版是 940,那是為了容下一條 220px 的目錄軌;軌沒了,寬度就該跟著收回量度。 */
  width: min(760px, 100%);
}
/* 頁尾整寬不收進 760,理由跟 .auth > .foot 同一條:收窄會擠成兩列,跟首頁對不上。
   margin-top: auto 吃掉多出來的空間讓頁尾貼底;內容夠長時由請柬的下外距
   保住那道最小間距(flex 的外距不合併,兩者各自生效)。 */
.doc > .foot {
  width: 100%;
  margin-top: auto;
}
/* .invite 本來是首頁的請柬卡:直向 space-between、撐最小高度、hover 浮起 6px。
   當整卷章程的外框要把這三件都關掉,跟 auth.html 那一段同樣的取捨。 */
body[data-page="doc"] .invite {
  display: block;
  min-height: 0;
  gap: 0;
  margin-bottom: clamp(28px, 4vh, 56px);
  padding: clamp(34px, 4.4vh, 56px) clamp(30px, 4.4vw, 64px) clamp(30px, 4vh, 48px);
}
body[data-page="doc"] .invite:hover {
  transform: none;
}
/* .invite p 是首頁請柬那一行說明文:34ch 封頂、.04em 字距。整卷條文都在這個框裡,
   那兩條會跟著套進來 —— 實測正文欄從 631px 被截成 306px,右邊空掉一半。
   .doc-sec p 的層級跟 .invite p 打平(各 1 類 1 型),只贏在順序,蓋得掉字級與顏色,
   蓋不掉它沒宣告的 max-width 與 letter-spacing。這裡一次還原,不逐條補。 */
body[data-page="doc"] .invite p {
  max-width: none;
  letter-spacing: normal;
}
/* ── 卷首 ───────────────────────────────────────────
   只剩卷名一行。原本上面有一句稱謂、下面一行憑證(編號 / 版本 / 生效 / 上次修訂),
   指示是兩排一起刪、整頁往上補回空間,所以標題的下距歸零 —— 留著會在卷名與那條
   分隔線之間空出一段沒有東西的暗帶。置中只給這一段,條文一律靠左。 */
.doc-head {
  text-align: center;
  padding-bottom: clamp(22px, 3vh, 34px);
  border-bottom: 1px solid var(--line-soft);
  margin-bottom: clamp(26px, 3.4vh, 42px);
}
.doc-head .auth-title {
  margin-bottom: 0;
}
/* ── 卷首引言 ─────────────────────────────────────
   理性博彩那一卷開頭有一句獨立的定調句,不屬於任何一條。比條文大一階、用金色,
   跟卷名之間留一段,讀起來是題辭不是第 1 條的第一行。只有那一卷用得到。
   選擇器跟著 body[data-page] 掛:.invite p(1 類 1 型)壓得過單一個類別,
   不掛的話字級與顏色會被首頁請柬那條 12.5px 搶走。 */
body[data-page="doc"] .doc-lede {
  font-family: var(--serif);
  font-size: clamp(1.05rem, 1.6vw, 1.3rem);
  line-height: 1.6;
  letter-spacing: .04em;
  color: var(--gold);
  margin-bottom: clamp(30px, 4vh, 52px);
}
/* ── 條文 ───────────────────────────────────────────
   序號留著是因為它是資訊不是裝飾:條文靠編號被引用(「依第 7 條」),
   客服與申訴都指得到它。所以寫成 1 不是 01 —— 引用格式沒有前導零。
   序號後面那截 26px 的金線是這一頁唯一的裝飾,取代整條橫貫的分隔線:
   橫線會把讀的那一欄切成一塊一塊,margin 裡的短線只標記不切斷。
   scroll-margin-top 留著:頁尾與客服都還有錨點連結指得進來,固定頂欄 60px + 淨空。 */
.doc-sec {
  scroll-margin-top: 84px;
}
.doc-sec + .doc-sec {
  margin-top: clamp(30px, 4vh, 52px);
}
.doc-sec h2 {
  display: flex;
  align-items: baseline;
  gap: .7em;
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(1.3rem, 2.1vw, 1.7rem);
  letter-spacing: .04em;
  line-height: 1.35;
  color: var(--ink);
  margin-bottom: 14px;
}
/* 編號用 --gold 不用 --gold-dim:#8a6d1f 落在近黑底上只有 4.1:1,
   小字要 4.5:1,axe 判 serious。線是背景不是字,不受這條規則,留 --gold-dim。 */
.doc-n {
  flex: none;
  display: flex;
  align-items: center;
  gap: .9em;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: .1em;
  color: var(--gold);
}
.doc-n::after {
  content: "";
  width: 26px;
  height: 1px;
  background: var(--gold-dim);
}
/* 量度由框的內距決定,不再各自封頂 68ch:框比舊版的欄窄,再封一次只會在
   右邊留下一條比留白還窄的參差帶,中文一行填滿時看得特別清楚。 */
.doc-sec p,
.doc-sec li {
  color: var(--ink-dim);
  font-size: clamp(14px, 1.05vw, 15.5px);
  line-height: 1.85;
}
.doc-sec p + p,
.doc-sec p + .doc-list,
.doc-sec .doc-list + p {
  margin-top: 12px;
}
/* ul 在全站被清成無標記,條列卻需要看得出是條列。用金色破折號當標記,
   跟序號旁邊那截短線同一個語彙,不引進圓點也不引進第二個色相。 */
.doc-list li {
  position: relative;
  padding-left: 1.5em;
}
.doc-list li + li {
  margin-top: 6px;
}
.doc-list li::before {
  content: "—";
  position: absolute;
  left: 0;
  color: var(--gold-dim);
}
/* 由寬到窄,同 §3 的慣例 */
@media (max-width: 1100px) {
  /* 頁尾整寬後右端版權字會跟 .contact 相交,讓開相交的那一段就夠 —— 同 .auth > .foot */
  .doc > .foot {
    padding-right: max(0px, 78px - 6vw);
  }
}
@media (max-width: 700px) {
  /* .contact 那疊 46x46 固定在 right:20,也就是吃掉畫面右邊 66px。窄螢幕上請柬幾乎
     滿寬,中文一行又剛好填到底,行末那一兩個字會壓在按鈕底下。內距補到 46 之後,
     375 寬的行末落在 306px、按鈕左緣在 309px,讓開了;代價是一行少約 1.5 個字。
     只補右邊會讓左右不對稱 —— 中文填滿整行時那 14px 的差看得出來,所以兩邊一起補。
     320 寬時框本身的右線就已經在按鈕底下,那要動 .contact,不是這一頁的事。 */
  body[data-page="doc"] .invite {
    padding-left: 46px;
    padding-right: 46px;
  }
}
/* ============================================================
   列印
   ============================================================
   整站是深底燙金,直接送印表機的話:燙金字是 color:transparent +
   background-clip:text 疊出來的,紙上等於一滴墨都沒有;--ink 的
   #e9e2d0 對白紙只有 1.29:1;固定定位的頂欄、側欄、右下按鈕會壓在
   內文上,而 .ch 的 min-height:100vh 會把首頁撐成一疊空白。
   全站的顏色都走 var(),所以這裡只換 token,不逐條覆蓋規則 ——
   跟 forced-colors 那一段同一個做法,差別是那邊交給系統色,
   這邊自己給一組印在白紙上的色。 */
@media print {
  :root {
    --bg: #fff;
    --bg2: #fff;
    --surface: #fff;
    --line: rgba(0, 0, 0, .32);
    --line-soft: rgba(0, 0, 0, .16);
    /* 金色壓深:#d4af37 對白紙 2.10:1,#6b5310 是 7.35:1 */
    --gold: #6b5310;
    --gold-hi: #4a3a0b;
    --gold-dim: #7d6a35;
    --ink: #14110c;
    --ink-dim: #453f33;
    --ink-faint: #5c5546;
  }
  html,
  body {
    background: #fff !important;
    color: var(--ink) !important;
  }
  /* 燙金字退回實色。跟 forced-colors 那段是同一組選擇器,只是這裡有自己的色可以給。 */
  .gold-text,
  .jack .col span,
  .jack .sep {
    background: none;
    -webkit-background-clip: border-box;
    background-clip: border-box;
    color: var(--gold);
    -webkit-text-fill-color: var(--gold);
  }
  .jack {
    filter: none;
  }
  /* 純裝飾與純互動的東西不進紙。.skip 也一起 —— 紙上沒有鍵盤焦點。 */
  .beam,
  .cursor-light,
  .spine,
  .contact,
  .dock,
  .toast,
  .skip,
  .scroll-cue,
  .launch {
    display: none !important;
  }
  /* 固定與黏著全部退回文件流,不然每一頁都蓋一條頂欄。 */
  .bar,
  .rail {
    position: static !important;
    height: auto;
    overflow: visible;
    backdrop-filter: none;
  }
  /* 頂欄只留品牌:返回鍵、語言選單、登入鍵在紙上按不下去。 */
  .bar .back,
  .bar-end,
  .bar-nav {
    display: none !important;
  }
  /* 深色的面在紙上會把字整段吃掉 —— 請柬框那層 linear-gradient(165deg, #15110a …)
     蓋在白底上,--ink 的 #14110c 就等於黑字印在黑紙。整站的底色一律拿掉,
     版面改成完全靠邊線與留白撐 —— 那本來就是這套設計的骨架。
     偽元素不在 `body *` 的範圍裡,所以條號後面那道金線、回執的方章都留得住。 */
  body * {
    background-color: transparent !important;
    background-image: none !important;
  }
  /* 一屏一章是螢幕上的節奏,紙上只會變成一疊空白。 */
  .ch {
    min-height: 0;
    padding-top: 24px;
    padding-bottom: 24px;
  }
  .invite,
  .g-card,
  .doc-sec,
  .pnl-ch {
    break-inside: avoid;
  }
  /* 條文分頁時標題不落單。 */
  h1, h2, h3 {
    break-after: avoid;
  }
  /* 進場動畫的起始狀態是 opacity:0,列印預覽有機會停在那一格。 */
  .js:not(.anim-ready) .bar,
  .js:not(.anim-ready) .doc,
  .g-card,
  .invite,
  .prov-wall li,
  .door {
    opacity: 1 !important;
    transform: none !important;
    animation: none !important;
  }
}
