/* ==========================================================================================
   screens/lobby.css — the hub (official entry backdrop, the emblem in its radar and the title, 成就统计 / 密钥加入 /
   作战提示 at the left, the light S.W.E.E.P.报告 / 干员调配 plates at the right, the 独立模拟 / 同盟模拟 entries at the
   bottom right), and the two full-screen dialogs (the project's Modal): 选择模拟协议 (official picture, difficulty cards
   with the 已选定 stamp, 开始独立模拟 — or the room's 确认 / read-only view) and 选择同盟方式 (radar, 创建同盟 and 加入同盟
   cards). Text follows 文字大小 (calc(k * var(--t))).
   ========================================================================================== */

/* ---- hub backdrop ------------------------------------------------------------------------------------- */
/* the entries' width follows 文字大小 (2.3rem at 小; §35.18 review: at a fixed 2.3rem the names had to stop at 小's size) */
.lobby-hub { --hub-entry-w: calc(2.3 * var(--t)); --hub-gap: .14rem; background: #050807; }
/* Korean breaks between words, not between the syllables of one (§35.18 review: 「독립 시뮬레이|션」 at 小); a word too
   long for its box still breaks rather than running out of it. The hub's own stage only: 选择模拟协议's button keeps its
   two lines (「독립 시뮬레이션 시작」 took three at 特大 in a 1024×600 window by words) */
.lobby-hub:lang(ko) .hub-stage { word-break: keep-all; overflow-wrap: break-word; }
/* Japanese never starts a line with a small kana, ー or a closing mark (§35.18 review: the tips' 「オペレ|ーター」 at 中 / 特大
   in a 1024×600 window; line-break: normal allows a break before them), as in the room */
.lobby-hub:lang(ja) .hub-stage { line-break: strict; }
/* a last line of one character: the hub's tips, the protocol dialog's paragraphs and its big button's label wrap `pretty`
   (§35.18 review of the text-fit fixes: 「比較的所要時間が短いシミュレーショ|ン」 on a phone at 特大, 「単独演算を開|始」,
   Korean 「독립 시뮬레이션 시|작」 on desktops). Scoped as in the room (room.css): WebKit's `pretty` adds lines to short
   labels, and the lobby's other dialogs were not measured with it. The dialog's button only (`.proto-foot`): the room's
   big button shares the label's class and wraps plainly — in Safari `pretty` broke its Japanese 「シミュレーション|開始」
   inside the word, 「シミュレー|ション開始」, at 小 on the phones (review of 6f34f380), as `balance` had. `pretty`:
   Chrome 117+, Safari 26+; Firefox wraps as before */
.tips__text, .proto-brief p, .proto-hint, .proto-foot .proto-start__label { text-wrap: pretty; }
/* 选择同盟方式's note breaks Japanese between phrases in Chrome 119+ (BudouX; review of 6f34f380: 「…教えてもらう|か、招待リンク…」
   at 特大 on the phones, now 「…教えて|もらうか、招待リンクを|直接開いてください」); Safari and Firefox ignore it and wrap as
   before */
.ally-recent:lang(ja) { word-break: auto-phrase; }
/* the top bar's ping pill grows with its text at 大 / 特大, as in the room (§35.18 review: its fixed .32rem cut it) */
.lobby-hub > .topbar .ping { height: auto; min-height: .32rem; padding-top: 1px; padding-bottom: 1px; }
.hub-bg {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  background:
    radial-gradient(55% 60% at 50% 48%, rgba(96, 170, 186, .14), transparent 72%),
    linear-gradient(180deg, #08100f, #040606 82%);
}
/* the official layers are drawn on black: `screen` keeps only their light. Their place, size and opacity below are
   eyeballed from the event video [ASSUMED: no official layout data] */
.hub-bg__glow, .hub-bg__ship { position: absolute; left: 50%; height: auto; transform: translate(-50%, -50%); mix-blend-mode: screen; }
.hub-bg__glow { top: 46%; width: 9.6rem; opacity: .2; }
.hub-bg__ship { top: 54%; width: 13.4rem; opacity: .4; animation: hub-ship 18s ease-in-out infinite alternate; }
@keyframes hub-ship { to { transform: translate(-50%, calc(-50% - .1rem)); } }
.hub-bg__grid {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(255, 255, 255, .028) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, .028) 1px, transparent 1px);
  background-size: .6rem .6rem;
  -webkit-mask-image: radial-gradient(70% 70% at 50% 50%, #000 30%, transparent 85%);
  mask-image: radial-gradient(70% 70% at 50% 50%, #000 30%, transparent 85%);
}
.lobby-hub .topbar { background: linear-gradient(180deg, rgba(4, 8, 8, .85), transparent); border-bottom: 0; }

/* ---- 大厅背景与音乐 (PR #643 split 8, ui/lobbyMedia.js): the player's own picture / video over the official layers,
   darkened by its 暗度 (--own-dim) so the title and the entries stay readable; the dialog reuses the settings rows ---- */
.hub-bg__own { position: absolute; inset: 0; background: #050807; animation: hub-own-in 400ms ease-out backwards; }
.hub-bg__own img, .hub-bg__own video, .hub-bg__own canvas { display: block; width: 100%; height: 100%; object-fit: cover; }
.hub-bg__own::after { content: ''; position: absolute; inset: 0; background: rgba(5, 8, 7, var(--own-dim, .35)); }
@keyframes hub-own-in { from { opacity: 0; } }
.lmedia .modal__body { display: flex; flex-direction: column; gap: .16rem; }
.lmedia__part { display: flex; flex-direction: column; gap: .1rem; padding: .14rem .16rem; border: 1px solid var(--line); background: rgba(0, 0, 0, .25); }
.lmedia__head { display: flex; align-items: baseline; gap: .1rem; font-size: calc(.18 * var(--t)); color: var(--text-hi); }
.lmedia__now { display: flex; align-items: center; gap: .08rem; min-width: 0; font-size: calc(.16 * var(--t)); color: var(--text-md); }
.lmedia__now .icon { flex: none; width: .2rem; height: .2rem; color: var(--mint-500); }
.lmedia__name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lmedia__size { flex: none; font-size: calc(.14 * var(--t)); color: var(--text-lo); }
.lmedia__btns { display: flex; flex-wrap: wrap; align-items: center; gap: .1rem; }
.lmedia__btns .set-toggle { grid-column: auto; }
.lmedia__dim { padding: 0 .16rem; }
.lmedia__note { display: flex; gap: .06rem; margin: 0; font-size: calc(.15 * var(--t)); line-height: 1.6; color: var(--text-lo); }
.lmedia__note .icon { flex: none; width: .18rem; height: .18rem; margin-top: .04rem; }

/* 大厅场景 (ui/hubScene.js): four generated scenes over the official backdrop; colour tokens per scene ---------- */
[data-hub-theme="night"] {
  --sky-0: #03080a; --sky-1: #08141a; --sky-2: #12262a; --sky-3: #050909;
  --haze: rgba(92, 168, 156, .17); --cloud: rgba(140, 196, 186, .055);
  --ridge-far: #122022; --ridge-mid: #0b1516; --ridge-near: #060b0b;
  --rim: rgba(110, 226, 196, .34); --fog: rgba(54, 104, 98, .3); --beam: rgba(150, 240, 215, .1);
  --beacon: #59f4ca; --window: rgba(89, 244, 202, .7); --grid: rgba(89, 244, 202, .32);
  --mote: rgba(170, 245, 225, .7);
}
/* the official backdrop's swatch: its dark field and glow */
[data-hub-theme="official"] {
  --sky-0: #08100f; --sky-1: #0c1a1b; --sky-2: #1b3134; --sky-3: #040606;
  --ridge-far: transparent; --ridge-mid: transparent; --ridge-near: transparent; --beacon: rgba(150, 220, 230, .7);
}
[data-hub-theme="frost"] {
  --sky-0: #070c12; --sky-1: #142029; --sky-2: #34444f; --sky-3: #090d11;
  --haze: rgba(205, 226, 240, .2); --cloud: rgba(220, 236, 246, .08);
  --ridge-far: #3a4852; --ridge-mid: #212c34; --ridge-near: #0f1418;
  --rim: rgba(240, 248, 255, .62); --fog: rgba(180, 200, 214, .24); --beam: rgba(225, 240, 255, .12);
  --beacon: #9fd8ff; --window: rgba(170, 220, 255, .7); --grid: rgba(170, 215, 240, .26);
  --mote: rgba(240, 248, 255, .85);
}
[data-hub-theme="ember"] {
  --sky-0: #080605; --sky-1: #120d0b; --sky-2: #251913; --sky-3: #070505;
  --haze: rgba(196, 104, 52, .15); --cloud: rgba(130, 96, 76, .08);
  --ridge-far: #211814; --ridge-mid: #150f0c; --ridge-near: #090606;
  --rim: rgba(255, 150, 80, .28); --fog: rgba(84, 52, 38, .32); --beam: transparent;
  --beacon: #ffae48; --window: rgba(255, 168, 80, .75); --grid: rgba(255, 170, 90, .22);
  --mote: rgba(255, 150, 70, .85);
}
[data-hub-theme="calm"] {
  --sky-0: #040606; --sky-1: #070b0b; --sky-2: #0c1211; --sky-3: #040505;
  --haze: rgba(80, 120, 110, .07); --cloud: transparent;
  --ridge-far: #0e1514; --ridge-mid: #090e0e; --ridge-near: #050808;
  --rim: rgba(89, 244, 202, .14); --fog: rgba(30, 50, 46, .25); --beam: transparent;
  --beacon: #4ed8af; --window: rgba(78, 216, 175, .45); --grid: rgba(89, 244, 202, .22);
  --mote: transparent;
}

.hub-scene { position: absolute; inset: 0; pointer-events: none; overflow: hidden; background: var(--sky-3); }
.hub-bg__sky { position: absolute; inset: 0;
  background: linear-gradient(180deg, var(--sky-0) 0%, var(--sky-1) 36%, var(--sky-2) 63%, var(--sky-3) 100%); }
.hub-bg__stars { position: absolute; left: 0; top: 0; width: 1px; height: 1px; border-radius: 50%;
  animation: hub-twinkle 7s ease-in-out infinite alternate; }
.hub-bg__haze { position: absolute; inset: 0;
  background: radial-gradient(ellipse 80% 20% at 50% 64%, var(--haze), transparent 72%),
    radial-gradient(ellipse 130% 36% at 50% 72%, var(--haze), transparent 70%); }
.hub-bg__clouds { position: absolute; left: 0; top: 6%; width: 200%; height: 50%;
  background:
    radial-gradient(30% 10% at 15% 42%, var(--cloud), transparent 70%),
    radial-gradient(22% 7% at 38% 20%, var(--cloud), transparent 70%),
    radial-gradient(36% 11% at 66% 58%, var(--cloud), transparent 70%),
    radial-gradient(20% 6% at 88% 28%, var(--cloud), transparent 70%);
  background-size: 50% 100%; background-repeat: repeat-x; animation: hub-drift 180s linear infinite; }
.hub-bg__land { position: absolute; left: 0; bottom: 0; width: 100%; height: 64%; overflow: visible; }
.hub-bg__ridge--far { fill: var(--ridge-far); }
.hub-bg__ridge--mid, .hub-bg__fort { fill: var(--ridge-mid); }
.hub-bg__ridge--near { fill: var(--ridge-near); }
.hub-bg__rim { fill: none; stroke: var(--rim); stroke-width: 1.2; vector-effect: non-scaling-stroke; }
.hub-fog-0 { stop-color: var(--fog); stop-opacity: 0; }
.hub-fog-1 { stop-color: var(--fog); stop-opacity: 1; }
.hub-beam-0 { stop-color: var(--beam); }
.hub-beam-1 { stop-color: var(--beam); stop-opacity: 0; }
.hub-bg__beam { transform-origin: 791px 300px; animation: hub-beam 16s ease-in-out infinite alternate; }
.hub-bg__windows rect { fill: var(--window); animation: hub-window 9s steps(1) infinite; animation-delay: var(--dl); }
.hub-bg__beacons g { fill: var(--beacon); animation: hub-beacon 2.8s ease-in-out infinite; animation-delay: var(--dl); }
.hub-bg__beacon-glow { opacity: .22; }
.hub-bg__motes { position: absolute; inset: 0; }
.hub-bg__mote { position: absolute; border-radius: 50%; background: var(--mote); box-shadow: 0 0 6px var(--mote); opacity: 0;
  animation: hub-mote var(--d) linear infinite; animation-delay: var(--dl); }
[data-hub-theme="frost"] .hub-bg__mote { animation-name: hub-snow; }
@keyframes hub-twinkle { from { opacity: .5; } to { opacity: 1; } }
@keyframes hub-drift { to { transform: translateX(-50%); } }
@keyframes hub-beam { from { transform: rotate(-18deg); } to { transform: rotate(24deg); } }
@keyframes hub-window { 0%, 70% { opacity: .9; } 72%, 78% { opacity: .2; } 80%, 100% { opacity: .9; } }
@keyframes hub-beacon { 0%, 100% { opacity: .25; } 50% { opacity: 1; } }
@keyframes hub-mote { 0% { transform: translate3d(0, 0, 0); opacity: 0; } 15% { opacity: .8; } 85% { opacity: .45; } 100% { transform: translate3d(2vw, -18vh, 0); opacity: 0; } }
@keyframes hub-snow { 0% { transform: translate3d(0, -12vh, 0); opacity: 0; } 15% { opacity: .9; } 85% { opacity: .7; } 100% { transform: translate3d(-3vw, 14vh, 0); opacity: 0; } }
.bgset__swatch { position: relative; display: block; width: 100%; aspect-ratio: 16 / 9; overflow: hidden;
  background: linear-gradient(180deg, var(--sky-0), var(--sky-1) 40%, var(--sky-2) 66%, var(--sky-3)); }
.bgset__swatch svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.bgset__swatch .sw-far { fill: var(--ridge-far); }
.bgset__swatch .sw-mid { fill: var(--ridge-mid); }
.bgset__swatch .sw-near { fill: var(--ridge-near); }
.bgset__swatch .sw-beacon { fill: var(--beacon); }
@media (prefers-reduced-motion: reduce) {
  .hub-scene * { animation: none; }
  .hub-scene .hub-bg__mote { opacity: .3; }
}
/* the scene buttons of 大厅背景与音乐 */
.bgset__themes { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: .1rem; }
.bgset__theme {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .05rem;
  min-width: 0;
  padding: .06rem;
  font: inherit;
  text-align: left;
  color: var(--text-hi);
  cursor: pointer;
  background: rgba(223, 230, 226, .04);
  border: 1px solid rgba(223, 230, 226, .14);
  transition: border-color var(--t-fast), box-shadow var(--t-fast);
}
.bgset__theme:hover { border-color: var(--mint-a35); }
.bgset__theme.is-selected { border-color: var(--mint-400); box-shadow: inset 0 0 0 1px var(--mint-400), 0 0 .14rem var(--mint-a20); }
.bgset__name { font-size: calc(.15 * var(--t)); font-weight: 800; white-space: nowrap; }
.bgset__en { font: 700 calc(.09 * var(--t)) / 1 ui-monospace, Consolas, monospace; letter-spacing: .14em; color: var(--text-dim); white-space: nowrap; }
@media (max-width: 720px) { .bgset__themes { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

/* ---- hub layout: the centre spans the first row; both columns lie above it -------------------------- */
.hub-stage {
  position: relative;
  z-index: 1;
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(0, 4rem) minmax(0, 1fr) minmax(0, calc(var(--hub-entry-w) * 2 + var(--hub-gap)));
  grid-template-rows: minmax(0, 1fr) auto;
  grid-template-areas: "side center right" "side entries entries";
  gap: .2rem .4rem;
  width: 100%;
  padding: .1rem .36rem .36rem;
}

.hub-center {
  grid-row: 1;
  grid-column: 1 / -1;
  align-self: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .1rem;
  min-width: 0;
  text-align: center;
  pointer-events: none;
  animation: card-in var(--t-slow) var(--ease-out) backwards;
}
.hub-center__mark { position: relative; display: grid; place-items: center; min-height: 1.4rem; margin-bottom: .1rem; }
.hub-center__logo { position: relative; width: 1.3rem; height: auto; filter: drop-shadow(0 0 .12rem rgba(210, 255, 240, .25)); }
.hub-center__mark .emblem { position: relative; margin-bottom: 0; }
.hub-center__en { position: relative; font-family: var(--font-display); font-size: calc(.17 * var(--t)); letter-spacing: .32em; color: rgba(223, 230, 226, .72); text-shadow: 0 1px .08rem rgba(0, 0, 0, .85); }
.hub-center__en b { color: var(--mint-400); font-weight: 700; }
.hub-center__title {
  position: relative;
  margin: 0;
  /* follows 文字大小 while it fits on one line beside the side columns (larger, it ran under the left column's tips —
     §35.18 review): the centre is the stage's width (100vw less its .72rem padding) and the title's box 8.8rem less (below);
     7 CJK characters with their spacing are 7.4–8em, so it stops at that box / 8.2 (never below .56rem at 小); the latin
     title below */
  font-size: min(calc(.56 * var(--t)), calc((100vw - 9.52rem) / 8.2));
  font-weight: 900;
  letter-spacing: .14em;
  line-height: 1.15;
  color: var(--text-hi);
  text-shadow: 0 .04rem .3rem rgba(0, 0, 0, .8);
  overflow-wrap: anywhere;
}
.hub-center__title em { font-style: normal; color: var(--mint-400); }
.hub-center__title--latin { font-family: var(--font-display); letter-spacing: .04em; text-transform: uppercase; }
/* the title is centred over the whole stage: it keeps clear of the side columns (4rem and its gap each side), and the
   latin one — 「STRONGHOLD PROTOCOL: ALLIANCE」, 20em of the display font — is .46 × --t while it fits on one line
   inside that, (100vw − 9.52rem) / 20.2 (§35.18 review: at .56rem it reached under the left column's tips in English, at
   大 / 特大 in 800–1280 px windows; pinned at .46rem it no longer followed 文字大小). [ASSUMED] the .46 */
.hub-center__title { max-width: calc(100% - 8.8rem); }
.hub-center__title--latin { font-size: min(calc(.46 * var(--t)), calc((100vw - 9.52rem) / 20.2)); }
/* the radar rings around the emblem (original drawing) */
.hub-radar { position: absolute; left: 50%; top: 50%; width: 4.6rem; height: 4.6rem; transform: translate(-50%, -50%); }
.hub-radar svg { width: 100%; height: 100%; overflow: visible; fill: none; stroke: rgba(89, 244, 202, .15); stroke-width: 1; }
.hub-radar .hub-radar__ticks { stroke-width: 5; stroke-dasharray: 1.4 9.8; }
.hub-radar__sweep {
  position: absolute;
  inset: 5.4%;
  border-radius: 50%;
  background: conic-gradient(from 0deg, transparent 0 292deg, rgba(89, 244, 202, .15) 360deg);
  -webkit-mask-image: radial-gradient(circle, transparent 0 17%, #000 18%);
  mask-image: radial-gradient(circle, transparent 0 17%, #000 18%);
  animation: hub-sweep 9s linear infinite;
}
@keyframes hub-sweep { to { transform: rotate(1turn); } }

/* ---- left column: 成就统计, 密钥加入, 作战提示 ------------------------------------------------------------ */
.hub-side { grid-area: side; position: relative; z-index: 1; display: flex; flex-direction: column; gap: .14rem; min-width: 0; padding-top: .3rem; }
/* 成就统计 (#643's top-left card, from the event video): a dusk scene with the emblem and the trophy medal, the label strip
   with the LV under it */
.hub-ach {
  position: relative;
  width: 100%;
  display: flex;
  flex-direction: column;
  padding: 0;
  font: inherit;
  text-align: left;
  color: #eef3f1;
  cursor: pointer;
  background: #0c1110;
  border: 1px solid rgba(220, 230, 226, .16);
  box-shadow: 0 .04rem .16rem rgba(0, 0, 0, .45);
  transition: border-color var(--t-fast), filter var(--t-fast);
}
.hub-ach:hover, .hub-ach:focus-visible { border-color: rgba(78, 216, 175, .35); filter: brightness(1.08); outline: none; }
.hub-ach:focus-visible { box-shadow: 0 0 0 2px var(--mint-400); }
.hub-ach__scene { position: relative; height: 1rem; overflow: hidden; display: grid; place-items: center; }
.hub-ach__land { position: absolute; inset: 0; width: 100%; height: 100%; }
.hub-ach__scene::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: repeating-linear-gradient(0deg, rgba(0, 0, 0, .18) 0 1px, transparent 1px 3px), linear-gradient(90deg, rgba(8, 10, 10, .55), transparent 40%);
}
.hub-ach__mark { position: relative; z-index: 1; display: grid; place-items: center; }
.hub-ach__mark .emblem { margin: 0; gap: .06rem; animation: none; }
.hub-ach__mark .emblem__svg { width: .52rem; height: .56rem; filter: drop-shadow(0 0 .04rem rgba(0, 0, 0, .6)); }
.hub-ach__mark .emblem__svg circle { fill: #15110c; animation: none; }
.hub-ach__mark .emblem__svg circle.is-accent { fill: #2cf0b8; }
.hub-ach__mark .emblem__bracket { width: .07rem; height: .66rem; border-width: 1px; border-color: rgba(20, 16, 10, .55); }
.hub-ach__rank {
  position: absolute;
  left: .1rem;
  top: .1rem;
  z-index: 2;
  width: .6rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .01rem;
  padding: .04rem 0 .03rem;
  background: rgba(14, 18, 17, .55);
  border: 1px solid rgba(240, 244, 243, .4);
}
.hub-ach__medal { width: .44rem; height: .44rem; object-fit: contain; }
.hub-ach__rank > .icon { width: .3rem; height: .3rem; color: #eef3f1; }
.hub-ach__rank small { display: inline-flex; align-items: center; gap: .02rem; font-size: min(calc(.13 * var(--t)), .15rem); color: #e6ebe9; }
.hub-ach__rank small .icon { width: .12rem; height: .12rem; }
.hub-ach__label {
  position: relative;
  display: flex;
  align-items: center;
  gap: .08rem;
  flex-wrap: wrap;
  min-height: .46rem;
  padding: .02rem .16rem;
  font-size: calc(.21 * var(--t));
  font-weight: 700;
  background: linear-gradient(90deg, rgba(20, 26, 25, .96), rgba(14, 18, 17, .96));
  border-top: 1px solid rgba(220, 230, 226, .14);
}
.hub-ach__label::before, .hub-ach__label::after { content: ''; position: absolute; top: .06rem; bottom: .06rem; width: .06rem; border: 1px solid rgba(220, 230, 226, .3); }
.hub-ach__label::before { left: .04rem; border-right: 0; }
.hub-ach__label::after { right: .04rem; border-left: 0; }
.hub-ach__badge { flex: none; width: .24rem; height: .24rem; fill: #e8eeec; }
.hub-ach__lv { margin-left: auto; font-size: calc(.15 * var(--t)); font-weight: 600; color: var(--mint-400); }
.hub-tile {
  display: flex;
  align-items: center;
  gap: .14rem;
  width: 100%;
  min-height: .74rem;
  padding: .1rem .16rem;
  text-align: left;
  color: var(--text-hi);
  background: rgba(8, 14, 13, .8);
  border: 1px solid rgba(223, 230, 226, .2);
  border-left: 3px solid var(--mint-500);
  transition: background var(--t-fast), border-color var(--t-fast);
}
.hub-tile:hover, .hub-tile:focus-visible { background: rgba(24, 40, 36, .9); border-color: var(--mint-a35); }
.hub-tile__icon { flex: none; display: grid; place-items: center; width: .44rem; height: .44rem; border: 1px solid var(--mint-a35); color: var(--mint-400); }
.hub-tile__icon .icon { width: .24rem; height: .24rem; }
.hub-tile__text { display: flex; flex-direction: column; gap: .02rem; min-width: 0; }
.hub-tile__label { font-size: calc(.2 * var(--t)); font-weight: 800; }
.hub-tile__en { font-family: ui-monospace, Consolas, monospace; font-size: calc(.1 * var(--t)); font-weight: 600; letter-spacing: .18em; color: var(--text-dim); }
.hub-side .tips { margin-top: .04rem; background: rgba(8, 14, 13, .72); }

/* ---- right column: light plates with bracket marks (S.W.E.E.P.报告, 干员调配 = loadout.js's LoadoutButton) --------- */
.hub-right { grid-area: right; position: relative; z-index: 1; align-self: start; display: flex; flex-direction: column; gap: .12rem; min-width: 0; padding-top: .3rem; }
.lobby-hub .hub-plate {
  --pl-ink: #222b28;
  --bk-c: var(--mint-400);
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-start;
  gap: .14rem;
  width: 100%;
  height: auto;
  min-height: .7rem;
  min-width: 0;
  padding: .04rem .22rem .04rem .2rem;
  font: inherit;
  font-size: calc(.2 * var(--t));
  letter-spacing: .04em;
  color: #111816;
  text-align: left;
  cursor: pointer;
  background:
    linear-gradient(var(--pl-ink), var(--pl-ink)) left .07rem center / 2px 54% no-repeat,
    linear-gradient(var(--pl-ink), var(--pl-ink)) left .07rem top 23% / .06rem 2px no-repeat,
    linear-gradient(var(--pl-ink), var(--pl-ink)) left .07rem bottom 23% / .06rem 2px no-repeat,
    linear-gradient(var(--pl-ink), var(--pl-ink)) right .07rem center / 2px 54% no-repeat,
    linear-gradient(var(--pl-ink), var(--pl-ink)) right .07rem top 23% / .06rem 2px no-repeat,
    linear-gradient(var(--pl-ink), var(--pl-ink)) right .07rem bottom 23% / .06rem 2px no-repeat,
    linear-gradient(180deg, #e8edea, #c6cfcb);
  border: 1px solid rgba(255, 255, 255, .5);
  box-shadow: 0 .05rem .18rem rgba(0, 0, 0, .5), inset 0 -2px 0 rgba(0, 0, 0, .14);
}
.lobby-hub .hub-plate:not(:disabled):hover { border-color: #fff; box-shadow: 0 .05rem .22rem rgba(0, 0, 0, .55), 0 0 .16rem rgba(78, 216, 175, .3); filter: brightness(1.05); }
.lobby-hub .hub-plate:focus-visible { outline: 2px solid var(--mint-400); outline-offset: 2px; }
.hub-plate__glyph, .lobby-hub .hub-plate .lo-entry__icon, .lobby-hub .hub-plate > .btn__icon {
  flex: none;
  display: grid;
  place-items: center;
  width: .46rem;
  height: .46rem;
  padding: .07rem;
  box-sizing: border-box;
  color: var(--mint-400);
  background: #182120;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .08);
}
.hub-plate__glyph svg { width: 100%; height: 100%; }
/* (a label too long for its plate wraps beside its glyph and the plate grows, rather than an ellipsis — §35.18 review:
   Japanese S.W.E.E.P.レポート beside its tag at 特大 in 800–1280 px windows. It takes the row's free width, at least its
   longest word, so only the tag drops under it when even that does not fit) */
.hub-plate__label, .lobby-hub .hub-plate .btn__label { flex: 1 1 0; min-width: min-content; font-weight: 900; letter-spacing: .04em; line-height: 1.15; white-space: normal; color: #111816; }
.hub-plate__tag { margin-left: auto; padding: .03rem .07rem; font-size: calc(.11 * var(--t)); font-weight: 700; letter-spacing: .12em; color: rgba(17, 24, 22, .6); border: 1px solid rgba(17, 24, 22, .28); white-space: nowrap; }
.lobby-hub .hub-plate .lo-entry__n { margin-left: auto; }
/* 成就统计 as a plate: only on short screens, where the left column with its card gives way (see the media block) */
.lobby-hub .hub-plate--ach { display: none; }
.hub-plate--ach .hub-plate__glyph svg { fill: currentColor; }

/* ---- entries (独立模拟 / 同盟模拟), bottom right ----------------------------------------------------------- */
/* (the card, the line above it, the tips' head and the 成就统计 card's label grow or wrap rather than cut their text at
   大 / 特大 in a small window — §35.18 review; the trophy count under the medal stops at .15rem, 大's size [ASSUMED]) */
/* (the two cards share a height: the taller one's, their text at the bottom) */
.hub-entries { grid-area: entries; position: relative; z-index: 1; display: flex; align-items: stretch; justify-content: flex-end; gap: var(--hub-gap); min-width: 0; }
.hub-entry-wrap { display: flex; flex-direction: column; gap: .05rem; min-width: 0; animation: card-in var(--t-slow) var(--ease-out) backwards; }
.hub-entry-wrap:nth-child(2) { animation-delay: 60ms; }
.hub-entry__group { display: flex; align-items: center; gap: .06rem; min-height: .22rem; padding-left: .04rem; font-size: calc(.13 * var(--t)); color: rgba(223, 230, 226, .7); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.hub-entry__group .icon { flex: none; width: .16rem; height: .16rem; color: var(--mint-400); }
.hub-entry__long { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.hub-entry__short { display: none; }
/* Narrow desktop windows keep the full descriptions (phones have their own short labels below).
   [ASSUMED] A shared two-line minimum keeps both cards level when only one description wraps. */
@media (max-width: 900px) and (min-height: 521px) {
  .hub-entry__group { min-height: 3em; white-space: normal; overflow: visible; text-overflow: clip; }
  .hub-entry__long { white-space: normal; overflow: visible; text-overflow: clip; }
}
.hub-entry {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: flex-start;
  flex: 1 0 auto;
  width: var(--hub-entry-w);
  max-width: 100%;
  min-height: calc(1.34 * var(--t));
  padding: .14rem .16rem;
  /* the icon's height kept above the text (below) */
  padding-top: calc(.12rem + .42 * var(--t) + .04rem);
  overflow: hidden;
  text-align: left;
  color: var(--text-hi);
  background: linear-gradient(160deg, rgba(30, 46, 42, .94), rgba(9, 15, 14, .96));
  border: 1px solid rgba(223, 230, 226, .26);
  box-shadow: 0 .06rem .24rem rgba(0, 0, 0, .5);
  transition: transform var(--t-fast), border-color var(--t-fast), box-shadow var(--t-fast);
}
.hub-entry:hover, .hub-entry:focus-visible { transform: translateY(-.04rem); border-color: var(--mint-400); box-shadow: 0 .08rem .3rem rgba(0, 0, 0, .55), 0 0 .2rem var(--mint-a20); }
.hub-entry:active { transform: translateY(1px); }
.hub-entry__icon { position: absolute; right: .14rem; top: .12rem; color: var(--mint-a35); }
.hub-entry__icon .icon { width: calc(.42 * var(--t)); height: calc(.42 * var(--t)); }
/* the card, its icon and its text follow 文字大小 together (2.3 × 1.34 --t, the icon .42 --t), as at 小; the text stays
   below the icon — the card's top padding is the icon's .12rem offset, its height and a gap — so a long name or the
   decorative line grows the card rather than running under it (§35.18 review: 「ALLIANCE SIMULATION」 ran under the
   people icon in English, Korean names under it at 大 / 特大; a padding beside it instead wrapped the line in every
   language, Chinese 「ALLIANCE / SIMULATION」 at 小, which never reached the icon). A short card keeps its min-height */
.hub-entry__en { font-family: ui-monospace, Consolas, monospace; font-size: calc(.11 * var(--t)); font-weight: 700; letter-spacing: .22em; color: var(--mint-400); }
/* the name wraps between words (§35.18 review: on one line English 「Solo Simulation」 / 「Team Simulation」 ran 25–40 px
   past the 2.3rem card at 小 in every window and 84–100 px at 特大, the card cutting it); 「Simulation」 alone is ~6.2em,
   and the card (2.3 × --t) keeps ~1.98 × --t inside for the .3 × --t name */
.hub-entry__name { margin-top: .04rem; font-size: calc(.3 * var(--t)); font-weight: 900; letter-spacing: .06em; line-height: 1.1; }
.hub-entry__corner { position: absolute; right: 0; bottom: 0; width: .3rem; height: .3rem; background: linear-gradient(135deg, transparent 50%, var(--mint-500) 50%); opacity: .8; }
/* 同盟模拟, the main way to play: bright */
.hub-entry--coop { background: linear-gradient(160deg, var(--mint-500), #1f8f72); color: #04140f; border-color: var(--mint-400); }
.hub-entry--coop .hub-entry__en { color: rgba(4, 20, 15, .75); }
.hub-entry--coop .hub-entry__icon { color: rgba(4, 20, 15, .25); }
.hub-entry--coop .hub-entry__corner { background: linear-gradient(135deg, transparent 50%, #e8fff7 50%); }
@keyframes card-in { from { opacity: 0; transform: translateY(.14rem); } }

/* ---- tips -------------------------------------------------------------------------------------------- */
.tips {
  --bk-c: var(--line-3);
  margin-top: .3rem;
  padding: .16rem .22rem .2rem;
  background: rgba(8, 10, 9, .55);
  border: 1px solid var(--line);
}
.tips__head { display: flex; flex-wrap: wrap; align-items: center; gap: .1rem; font-size: calc(.16 * var(--t)); font-weight: 700; color: var(--text-md); }
.tips__head > .icon { width: .2rem; height: .2rem; color: var(--mint-500); }
/* the count and its arrows move to a line of their own, together, when the head is too narrow for them (§35.18 review) */
.tips__pager { display: inline-flex; align-items: center; gap: .1rem; margin-left: auto; }
.tips__idx { font-size: calc(.16 * var(--t)); color: var(--text-md); }
.tips__nav {
  display: grid;
  place-items: center;
  width: .3rem;
  height: .3rem;
  padding: 0;
  border: 1px solid var(--line-2);
  background: transparent;
  color: var(--text-lo);
  transition: color var(--t-fast), border-color var(--t-fast);
}
.tips__nav:hover { color: var(--mint-400); border-color: var(--mint-700); }
.tips__nav .icon { width: .18rem; height: .18rem; }
.tips__text { margin-top: .1rem; font-size: calc(.17 * var(--t)); color: var(--text-lo); line-height: 1.6; animation: tip-in var(--t-slow) var(--ease-out); }
@keyframes tip-in { from { opacity: 0; transform: translateX(.1rem); } }

/* ---- the two full-screen dialogs (Modal .proto / .ally) --------------------------------------------- */
.modal.proto-veil { padding: 0; background: #0b0c0c; -webkit-backdrop-filter: none; backdrop-filter: none; }
.modal__box.proto, .modal__box.ally {
  position: fixed;
  inset: 0;
  width: auto;
  max-height: none;
  padding: var(--sa-t, 0px) var(--sa-r, 0px) var(--sa-b, 0px) var(--sa-l, 0px);
  color: #eef0ef;
  background: #0b0c0c;
  border: 0;
  box-shadow: none;
  overscroll-behavior: contain;
  animation: proto-in 200ms var(--ease-out) backwards;
}
.modal__box.proto::after, .modal__box.proto > .modal__stripe, .modal__box.ally::after, .modal__box.ally > .modal__stripe { display: none; }
.modal__box.proto > .modal__body, .modal__box.ally > .modal__body { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; padding: 0; overflow: hidden; color: inherit; }
.proto__body, .ally__body { position: relative; flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
@keyframes proto-in { from { opacity: 0; } }
.proto__bg {
  position: absolute;
  inset: 0;
  pointer-events: none;
  transition: background 400ms;
  background:
    radial-gradient(46% 60% at 30% 52%, rgba(255, 255, 255, .05), transparent 70%),
    repeating-linear-gradient(90deg, rgba(255, 255, 255, .022) 0 1px, transparent 1px 4px),
    linear-gradient(rgba(255, 255, 255, .03) 1px, transparent 1px) 0 0 / 1.1rem 1.1rem,
    linear-gradient(90deg, rgba(255, 255, 255, .03) 1px, transparent 1px) 0 0 / 1.1rem 1.1rem,
    radial-gradient(120% 90% at 50% 40%, #151616, #070808);
  background:
    radial-gradient(46% 60% at 30% 52%, color-mix(in srgb, var(--d-color, #4ed8af) 16%, transparent), transparent 70%),
    radial-gradient(40% 50% at 100% 50%, color-mix(in srgb, var(--d-color, #4ed8af) 10%, transparent), transparent 70%),
    repeating-linear-gradient(90deg, rgba(255, 255, 255, .022) 0 1px, transparent 1px 4px),
    linear-gradient(rgba(255, 255, 255, .03) 1px, transparent 1px) 0 0 / 1.1rem 1.1rem,
    linear-gradient(90deg, rgba(255, 255, 255, .03) 1px, transparent 1px) 0 0 / 1.1rem 1.1rem,
    radial-gradient(120% 90% at 50% 40%, #151616, #070808);
}
.proto-top, .proto-body { position: relative; }
.proto-top { flex: none; display: flex; align-items: flex-start; justify-content: space-between; gap: .2rem; padding: .18rem .34rem 0 .22rem; z-index: 2; }
.proto-back {
  display: inline-flex;
  align-items: center;
  height: max(.62rem, 32px, calc(36px * var(--sp-ui, 1)));
  padding: 0;
  font: inherit;
  color: #f2f4f3;
  background: linear-gradient(180deg, #2b2c2d, #1b1c1d);
  border: 1px solid rgba(255, 255, 255, .1);
  box-shadow: 0 .04rem .14rem rgba(0, 0, 0, .5);
}
.proto-back > .icon { width: max(.4rem, 22px); height: max(.4rem, 22px); margin: 0 .3rem 0 .14rem; }
.proto-back__home {
  display: grid;
  place-items: center;
  align-self: stretch;
  width: max(2rem, 32px, calc(96px * var(--sp-ui, 1)));
  border-left: 2px solid #0d0e0e;
  background: radial-gradient(circle, rgba(255, 255, 255, .22) 1px, transparent 1.6px) 0 0 / .14rem .14rem, linear-gradient(90deg, #2f3132, #3d3f40 50%, #2f3132);
}
.proto-back__home .icon { width: max(.32rem, 18px); height: max(.32rem, 18px); }
.proto-back:hover, .proto-back:focus-visible { border-color: rgba(255, 255, 255, .35); }
.proto-title { display: flex; flex-direction: column; align-items: flex-end; gap: .02rem; min-width: 0; padding-top: .06rem; text-align: right; }
.proto-title .modal__title { margin: 0; font-size: calc(.36 * var(--t)); font-weight: 900; letter-spacing: .06em; color: #eef0ef; }
.proto-title__mode { display: inline-flex; align-items: center; gap: .08rem; font-size: calc(.16 * var(--t)); font-weight: 700; color: var(--d-color, var(--mint-400)); }
.proto-title__mode .icon { width: 1.1em; height: 1.1em; }
.proto-title__mode i { font-style: normal; font-family: var(--font-display); font-size: calc(.13 * var(--t)); letter-spacing: .16em; color: #8b8f8e; }

/* the cards' column 5.6rem, at least 300 px (§35.18 review: in a window whose 1rem is under 54 px — 960×540, 1100×530,
   800×600 — the px floors of the glyph and the 文字大小 made 5.6rem too narrow for English 「Standard Simulation」 /
   「Ultimate Simulation」 on one line, and the unselected cards' names ended in an ellipsis), never past 46vw. [ASSUMED] the
   floor */
.proto-body { flex: 1 1 auto; min-height: 0; display: grid; grid-template-columns: minmax(0, 1fr) min(max(5.6rem, 32px, calc(300px * var(--sp-ui, 1))), 46vw); gap: .3rem; padding: 0 .34rem .26rem .22rem; }
.proto-stage { position: relative; min-width: 0; min-height: 0; display: grid; place-items: center; }

/* the official picture of the selected difficulty, with its brief at the bottom left */
/* the picture fills the column (as #643's drawn scene did: from a little above the cards down to the brief) */
.proto__pic { position: absolute; inset: -.5rem -1.8rem .9rem -.3rem; display: grid; place-items: center; min-height: 0; animation: proto-pic var(--t-slow) var(--ease-out); }
.proto__art {
  width: 100%;
  height: 100%;
  max-width: 9.4rem; /* the art is 427 × 332: up to about 2.2× before it turns soft */
  max-height: 7.3rem;
  object-fit: contain;
  filter: drop-shadow(0 0 .2rem var(--d-color));
  filter: drop-shadow(0 0 .2rem color-mix(in srgb, var(--d-color) 45%, transparent));
}
.proto__glyph { width: 2.2rem; height: 2.2rem; color: var(--d-color); opacity: .8; filter: drop-shadow(0 0 .2rem var(--d-color)); }
@keyframes proto-pic { from { opacity: 0; transform: translateX(-.14rem); } }

/* the scene (ui/protocolScene.js, PR #643 + video 5:00–5:16): the official ship on a survey grid between two squares of
   defenders, the cable with a light running down it; it reaches under the cards like the event's. A new difficulty
   remounts it: dark first, then up in the new colour. */
.proto-side { position: relative; z-index: 1; }

.ps { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; color: var(--d-color); animation: ps-in 640ms ease-out backwards; }
@keyframes ps-in { 0% { opacity: 0; filter: brightness(.15); } 35% { opacity: .35; filter: brightness(.3); } 100% { opacity: 1; filter: none; } }
.ps-grid line { stroke: currentColor; stroke-opacity: .12; stroke-width: 1; }
.ps-pad polygon { fill: currentColor; fill-opacity: .1; stroke: currentColor; stroke-opacity: .55; stroke-width: 1.2; }
.ps-pad__edge { fill: none; stroke: currentColor; stroke-opacity: .7; stroke-width: 2; stroke-dasharray: 26 8; }
.ps-hull { filter: drop-shadow(0 0 6px var(--d-color)); }
.ps-ship image { filter: drop-shadow(0 0 10px var(--d-color)); filter: drop-shadow(0 0 10px color-mix(in srgb, var(--d-color) 55%, transparent)); }
.ps-face { stroke: currentColor; stroke-width: 1.3; stroke-linejoin: round; fill: currentColor; }
.ps-face--top { fill-opacity: .42; }
.ps-face--front { fill-opacity: .26; }
.ps-face--side { fill-opacity: .16; }
.ps-seam { stroke: #fff; stroke-opacity: .35; stroke-width: 1; }
.ps-beacon { fill: #fff; animation: ps-blink 1.6s steps(2) infinite; }
@keyframes ps-blink { 50% { opacity: .2; } }
.ps-cable { fill: none; stroke: currentColor; stroke-width: 5; stroke-opacity: .7; stroke-linecap: round; }
.ps-cable__pulse { fill: none; stroke: #fff6d8; stroke-width: 6; stroke-linecap: round; stroke-dasharray: 90 1200; stroke-dashoffset: 90;
  filter: drop-shadow(0 0 6px var(--d-color)); animation: ps-pulse 2.6s cubic-bezier(.5, 0, .7, 1) 400ms infinite; }
@keyframes ps-pulse { from { stroke-dashoffset: 90; opacity: 1; } 85% { opacity: 1; } to { stroke-dashoffset: -1000; opacity: 0; } }
.ps-fig { animation: ps-fig 360ms var(--ease-out) backwards; animation-delay: calc(240ms + var(--i) * 18ms); }
@keyframes ps-fig { from { opacity: 0; transform: translateY(-6px); } }
.ps-fig__body, .ps-fig__head { fill: currentColor; fill-opacity: .88; stroke: rgba(0, 0, 0, .45); stroke-width: .8; }
.ps-fig__head { fill-opacity: 1; }
.ps-fig__shadow { fill: #000; opacity: .35; }
.ps-spike polygon { fill: currentColor; fill-opacity: .75; }
.ps-spike__x { stroke: currentColor; stroke-width: 2; stroke-opacity: .8; }
.ps-spike { animation: ps-fig 420ms var(--ease-out) backwards; animation-delay: calc(var(--i) * 60ms + 120ms); }
.ps-call rect { fill: rgba(0, 0, 0, .55); stroke: currentColor; stroke-width: 1.5; }
.ps-call line { stroke: currentColor; stroke-width: 1.5; stroke-opacity: .8; }
.ps-call rect.ps-call__icon { fill: currentColor; fill-opacity: .25; }
.ps-call__man { fill: currentColor; }
.ps-call { animation: ps-fig 420ms var(--ease-out) 420ms backwards; }
.ps-scan { stroke: currentColor; stroke-opacity: .2; stroke-width: 2; animation: ps-scan 7s linear infinite; }
@keyframes ps-scan { from { transform: translateY(40px); } to { transform: translateY(620px); } }
.proto-brief {
  position: absolute;
  left: .1rem;
  bottom: .1rem;
  max-width: min(6rem, 92%);
  padding: .12rem .2rem .14rem;
  background: linear-gradient(90deg, rgba(0, 0, 0, .7), rgba(0, 0, 0, .2));
  border-left: 3px solid var(--d-color);
}
.proto-brief__code { margin-right: .1rem; padding: 0 .08rem; font-size: calc(.14 * var(--t)); color: #111; background: var(--d-color); }
.proto-brief__name { font-size: calc(.26 * var(--t)); color: var(--d-color); }
.proto-brief p { margin: .04rem 0 0; font-size: calc(.16 * var(--t)); line-height: 1.5; color: #b7bcba; }

/* the difficulty cards: the chosen one slides out with a glow and the 已选定 stamp; centred while they fit (auto margins, so
   a list taller than the column still scrolls from its top). The gaps and pads a little tighter than #643's (.14rem, .1rem
   and .1 / .11rem) so the full cards fit at 小 in a 16:9 window (they were 2–26 px too tall at 1280x720 – 1920x1080:
   §35.18's leftover). [ASSUMED] the spacing */
.proto-side { min-height: 0; display: flex; flex-direction: column; gap: .14rem; }
.proto-list {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  display: flex;
  flex-direction: column;
  gap: .1rem;
  padding: .07rem .06rem .07rem .5rem;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, .25) transparent;
}
.proto-list > :first-child { margin-top: auto; }
.proto-list > :last-child { margin-bottom: auto; }
.pcard {
  position: relative;
  flex: none;
  display: flex;
  flex-direction: column;
  gap: .04rem;
  padding: .08rem .26rem .09rem;
  overflow: hidden;
  font: inherit;
  text-align: left;
  color: #e9eceb;
  background: linear-gradient(180deg, #252627, #1a1b1c);
  border: 2px solid #55585a;
  border-radius: .2rem;
  box-shadow: 0 .05rem .16rem rgba(0, 0, 0, .5);
  transition: transform 220ms var(--ease-out), border-color 220ms;
}
.pcard:hover:not(.is-on), .pcard:focus-visible:not(.is-on) { border-color: #7b7f81; }
/* the room's read-only view (another doctor's: the host chooses): shown, not chosen */
.pcard:disabled { cursor: default; }
.pcard:disabled:hover:not(.is-on) { border-color: #55585a; }
.pcard.is-on { transform: translateX(-.44rem); border-color: #8f9496; }
.pcard__glow {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity 260ms;
  background: radial-gradient(70% 140% at 100% 50%, rgba(255, 255, 255, .12), transparent 72%);
  background: radial-gradient(70% 140% at 100% 50%, color-mix(in srgb, var(--d-color) 70%, transparent), transparent 72%);
}
.pcard.is-on .pcard__glow { opacity: 1; }
.pcard__head, .pcard__desc, .pcard__effects, .pcard__meta { position: relative; }
.pcard.is-on .pcard__head, .pcard.is-on .pcard__desc, .pcard.is-on .pcard__effects, .pcard.is-on .pcard__meta { padding-right: max(1.3rem, 32px, calc(70px * var(--sp-ui, 1))); }
.pcard__head { display: flex; align-items: center; gap: .08rem; }
.pcard__glyph { width: max(.3rem, 18px); height: max(.3rem, 18px); color: var(--d-color); }
.pcard__name { font-size: min(calc(.28 * var(--t)), .36rem); font-weight: 900; letter-spacing: .04em; color: var(--d-color); text-shadow: 0 0 .1rem rgba(0, 0, 0, .6); white-space: nowrap; }
.pcard__desc { padding-bottom: .05rem; font-size: calc(.16 * var(--t)); color: #9a9f9d; border-bottom: 1px solid rgba(255, 255, 255, .18); }
.pcard__effects { display: flex; flex-direction: column; padding-top: .04rem; font-size: calc(.17 * var(--t)); line-height: 1.4; }
.pcard__effects span::before { content: '·'; margin-right: .06rem; }
.pcard__meta { display: flex; flex-wrap: wrap; align-items: center; gap: .04rem .14rem; margin-top: .04rem; font-size: calc(.13 * var(--t)); color: #7f8583; }
.pcard__meta b { color: #cfd3d1; }
.pcard__stage { display: inline-flex; align-items: center; gap: .04rem; }
.pcard__stage .icon { width: 1.1em; height: 1.1em; }
.pcard__stamp {
  position: absolute;
  right: .2rem;
  top: 50%;
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .04rem;
  width: max(1.3rem, 32px, calc(70px * var(--sp-ui, 1)));
  height: max(1.1rem, 32px, calc(60px * var(--sp-ui, 1)));
  transform: translateY(-50%) rotate(-6deg);
}
.pcard.is-on .pcard__stamp { display: flex; animation: proto-stamp 260ms var(--ease-out) backwards; }
@keyframes proto-stamp { from { opacity: 0; transform: translateY(-50%) rotate(-6deg) scale(1.4); } }
.pcard__ring { position: absolute; inset: -.1rem -.14rem; width: calc(100% + .28rem); height: calc(100% + .2rem); }
.pcard__ring path { fill: none; stroke: #fff; stroke-width: 3; stroke-linecap: round; opacity: .9; }
.pcard__tick { display: grid; place-items: center; width: max(.46rem, 26px); height: max(.46rem, 26px); color: #2a1712; background: #f5f5f5; border-radius: .06rem; box-shadow: 0 .02rem .08rem rgba(0, 0, 0, .5); }
.pcard__tick .icon { width: 78%; height: 78%; color: var(--d-color); filter: brightness(.7); }
.pcard__ok { font-size: calc(.18 * var(--t)); font-weight: 800; color: #fff; text-shadow: 0 1px 3px rgba(0, 0, 0, .6); white-space: nowrap; }

/* the foot: the test-room box, the hint, 开始独立模拟 / 创建同盟 */
.proto-foot { flex: none; display: flex; flex-direction: column; gap: .08rem; padding-left: .5rem; }
.create-box__test {
  display: flex; flex-direction: row; flex-wrap: wrap; align-items: center; gap: .04rem .1rem;
  color: #e8b84a; font-size: calc(.16 * var(--t));
}
.create-box__test input { width: .2rem; height: .2rem; margin: 0; flex: none; accent-color: #e8b84a; }
.create-box__test em { flex-basis: 100%; font-style: normal; }
@media (max-width: 720px) {
  .create-box__test { font-size: 16px; }
  .create-box__test input { width: 32px; height: 32px; }
  .create-box__test em { font-size: 14px; }
}
.proto-hint { display: flex; align-items: center; gap: .08rem; min-height: .24rem; margin: 0; font-size: calc(.14 * var(--t)); color: #858b89; }
.proto-hint .icon { flex: none; width: 1.1em; height: 1.1em; }
.proto-hint--ro { min-height: max(.64rem, 32px, calc(38px * var(--sp-ui, 1))); font-size: calc(.18 * var(--t)); color: #b9bfbd; }
.proto-start {
  position: relative;
  display: flex;
  align-items: center;
  gap: .26rem;
  width: 100%;
  min-height: max(1.04rem, 32px, calc(54px * var(--sp-ui, 1)));
  padding: .03rem 0 .03rem .26rem;
  overflow: hidden;
  font: inherit;
  color: #0d2a23;
  text-align: left;
  background: linear-gradient(180deg, #4fe0bf, #34c8a6);
  border: 3px solid #121313;
  box-shadow: 0 0 0 1px rgba(79, 224, 191, .5), 0 .06rem .2rem rgba(0, 0, 0, .55);
  transition: filter var(--t-fast);
}
.proto-start:hover:not(:disabled), .proto-start:focus-visible { filter: brightness(1.07); }
.proto-start:focus-visible { outline: 2px solid #eef0ef; outline-offset: 2px; }
.proto-start:disabled { filter: grayscale(.8) brightness(.6); cursor: default; }
.proto-start__mark { flex: none; display: flex; flex-direction: column; align-items: center; gap: 1px; }
.proto-start__rook { display: inline-flex; align-items: center; gap: 2px; font-size: calc(.36 * var(--t)); font-weight: 300; line-height: 1; }
.proto-start__rook i { font-style: normal; }
.proto-start__rook .icon { width: max(.34rem, 19px); height: max(.34rem, 19px); }
.proto-start__mark small { font-family: var(--font-display); font-size: calc(.08 * var(--t)); font-weight: 800; letter-spacing: .06em; line-height: 1.1; text-align: center; }
.proto-start__label { position: relative; display: inline-flex; align-items: center; gap: .1rem; min-width: 0; font-size: calc(.4 * var(--t)); font-weight: 900; letter-spacing: .08em; white-space: nowrap; }
/* 选择模拟协议's own button (.proto-foot; the room's GoButton shares the rules above and makes its own choice in
   css/screens/room.css — §35.18 review: these rules once reached it too): the label wraps onto a second line (the button
   grows: min-height above) rather than being cut, and stops at .46rem — 大's size — on a screen taller than 520 px, the
   mark's rook at .4rem (§35.18's leftover: English 开始独立模拟 was cut at every desktop size, even at 小 at 1440x900;
   the short-screen block has its own caps). [ASSUMED] the label's caps */
.proto-foot .proto-start__label { flex: 1 1 auto; padding-right: 8%; font-size: min(calc(.4 * var(--t)), .46rem); white-space: normal; line-height: 1.1; }
.proto-foot .proto-start__rook { font-size: min(calc(.36 * var(--t)), .4rem); }
.proto-start__deco {
  position: absolute;
  right: 0;
  top: 0;
  bottom: 0;
  width: 26%;
  clip-path: polygon(18% 0, 100% 0, 100% 100%, 0 100%);
  background: repeating-linear-gradient(135deg, rgba(0, 0, 0, .28) 0 5px, transparent 5px 11px), linear-gradient(90deg, rgba(13, 42, 35, .2), rgba(13, 42, 35, .6));
}

/* ---- 选择同盟方式: the radar, the 创建同盟 / 加入同盟 cards -------------------------------------------------- */
.ally__bg {
  background:
    radial-gradient(40% 55% at 30% 52%, rgba(46, 210, 160, .12), transparent 70%),
    repeating-linear-gradient(90deg, rgba(255, 255, 255, .022) 0 1px, transparent 1px 4px),
    linear-gradient(rgba(255, 255, 255, .03) 1px, transparent 1px) 0 0 / 1.1rem 1.1rem,
    linear-gradient(90deg, rgba(255, 255, 255, .03) 1px, transparent 1px) 0 0 / 1.1rem 1.1rem,
    radial-gradient(120% 90% at 50% 40%, #141616, #070808);
}
.ally__mode { color: var(--mint-400); }
.ally-body { grid-template-columns: minmax(0, 1fr) min(7.4rem, 46vw); }
.ally-stage { position: relative; min-width: 0; min-height: 0; }
.mf-radar { position: absolute; inset: 0 0 .8rem; width: 100%; height: calc(100% - .8rem); }
.mf-radar__grid line { stroke: rgba(78, 216, 175, .08); stroke-width: 1; }
.mf-radar__land path { fill: rgba(150, 170, 165, .1); stroke: rgba(150, 170, 165, .2); stroke-width: 1; }
.mf-radar__ring { fill: none; stroke: rgba(78, 216, 175, .25); stroke-width: 1.5; }
.mf-radar__ring--far { fill: rgba(30, 140, 110, .1); }
.mf-radar__ring--core { stroke: rgba(78, 216, 175, .75); stroke-width: 3; filter: drop-shadow(0 0 6px rgba(78, 216, 175, .6)); }
.mf-radar__sweep { transform-origin: 270px 250px; animation: mf-sweep 4.5s linear infinite; }
.mf-radar__sweep path { fill: rgba(60, 230, 180, .22); }
.mf-radar__sweep line { stroke: #5df0c6; stroke-width: 3; filter: drop-shadow(0 0 6px #5df0c6); }
@keyframes mf-sweep { to { transform: rotate(360deg); } }
.mf-radar__blip { fill: #ffc53d; filter: drop-shadow(0 0 8px #ffc53d); animation: mf-blip 2.2s ease-in-out infinite; }
.mf-radar__blip--b { fill: #5df0c6; filter: drop-shadow(0 0 6px #5df0c6); animation-delay: 1.1s; }
@keyframes mf-blip { 50% { opacity: .2; } }
.mf-radar__cross { stroke: #5df0c6; stroke-width: 3; }
.mf-radar__read rect { fill: rgba(0, 0, 0, .5); stroke: rgba(78, 216, 175, .45); }
.mf-radar__read text { fill: #9fe9d3; font: 700 14px var(--font-num, monospace); }
.mf-radar__frame { fill: none; stroke: rgba(78, 216, 175, .35); stroke-width: 2; }
.ally-guide {
  position: absolute;
  left: .1rem;
  bottom: .1rem;
  display: inline-flex;
  align-items: center;
  gap: .14rem;
  height: max(.64rem, 32px, calc(38px * var(--sp-ui, 1)));
  padding: 0 .3rem 0 .1rem;
  font: inherit;
  font-size: calc(.22 * var(--t));
  font-weight: 800;
  color: #1a1d1c;
  background: linear-gradient(180deg, #e9edeb, #c3cac7);
  border: 1px solid rgba(255, 255, 255, .6);
  box-shadow: 0 .04rem .14rem rgba(0, 0, 0, .5);
}
.ally-guide:hover, .ally-guide:focus-visible { filter: brightness(1.06); }
.ally-guide__icon { display: grid; place-items: center; width: max(.46rem, 28px); height: max(.4rem, 24px); color: #e9edeb; background: #2a2f2d; }
.ally-guide__icon .icon { width: 64%; height: 64%; }
/* centred safely: the auto margins give way when the column is taller than its space (justify-content: center would
   push it past both ends), so a short screen's scroll (below) starts at 创建同盟 */
.ally-side { min-height: 0; display: flex; flex-direction: column; gap: .2rem; padding: .1rem 0 .1rem .3rem; }
.ally-side > :first-child { margin-top: auto; }
.ally-side > :last-child { margin-bottom: auto; }
.ally-card {
  position: relative;
  flex: none;
  display: flex;
  flex-direction: column;
  width: 100%;
  padding: 0;
  overflow: hidden;
  font: inherit;
  color: #eef0ef;
  text-align: left;
  background: radial-gradient(70% 90% at 50% 40%, #161a19, #090a0a);
  border: 1px solid rgba(255, 255, 255, .14);
  border-radius: .08rem;
  box-shadow: 0 .06rem .2rem rgba(0, 0, 0, .5);
}
button.ally-card:hover, button.ally-card:focus-visible { border-color: rgba(93, 240, 198, .6); }
.ally-card__art { display: block; padding: .1rem .2rem 0; }
.mf-art { display: block; width: 100%; height: auto; max-height: 1.3rem; }
.mf-art text { font: 700 8px var(--font-display, monospace); letter-spacing: 2px; fill: currentColor; opacity: .7; }
.mf-art--create { color: #5df0c6; }
.mf-art--create .mf-art__wire { fill: none; stroke: rgba(93, 240, 198, .45); stroke-width: 2; }
.mf-art--create .mf-art__oct { fill: #2fd6a6; filter: drop-shadow(0 0 10px rgba(93, 240, 198, .6)); }
.mf-art--create .mf-art__plus { stroke: #08221b; stroke-width: 7; stroke-linecap: square; }
.mf-art--create .mf-art__brk { fill: none; stroke: #5df0c6; stroke-width: 4; }
.mf-art--create .mf-art__dot { fill: #5df0c6; }
.mf-art--join { color: #ff9a3c; }
.mf-art--join .mf-art__wire { fill: none; stroke: rgba(255, 154, 60, .6); stroke-width: 2; }
.mf-art--join .mf-art__tri { fill: #ff9a3c; }
.mf-art--join .mf-art__target { fill: rgba(255, 154, 60, .15); stroke: #ff9a3c; stroke-width: 2; }
.mf-art--join .mf-art__x { stroke: #ff9a3c; stroke-width: 3; }
.mf-blk path { stroke: rgba(0, 0, 0, .5); stroke-width: 1; }
.mf-blk__top { fill: #3a3d3d; } .mf-blk__l { fill: #2a2c2c; } .mf-blk__r { fill: #1f2121; }
.mf-blk.is-lit .mf-blk__top { fill: #f0a35a; } .mf-blk.is-lit .mf-blk__l { fill: #c96b23; } .mf-blk.is-lit .mf-blk__r { fill: #a5541a; }
.mf-blk.is-lit { animation: mf-blk 2.4s ease-in-out infinite; animation-delay: calc(var(--k) * 120ms); }
@keyframes mf-blk { 50% { transform: translateY(-3px); } }
.ally-card__bar {
  position: relative;
  display: flex;
  align-items: center;
  gap: .14rem;
  height: max(.74rem, 32px, calc(42px * var(--sp-ui, 1)));
  padding: 0 .2rem;
  font-family: inherit;
  font-size: calc(.3 * var(--t));
  font-weight: 900;
  letter-spacing: .06em;
  white-space: nowrap;
  text-align: left;
  color: #08221b;
  background: linear-gradient(180deg, #4fe8c0, #2fcf9f);
  border: 0;
}
/* the difficulty line wraps at the bar's right rather than ending in an ellipsis (§35.51: English 「Difficulty: Standard
   Simulat…」 at 1280–1440 px, Japanese at 1024×600 特大). It keeps a column of at least 10em beside the name, else it
   takes a row of its own under the name and the bar grows (§35.51 review: squeezed into the 96 px the name left in
   English at 特大 on 1024×600, six lines ran out of the 42 px bar); Korean breaks between words only (the review:
   「시뮬레이|션」 once balanced), Japanese by its line-breaking rules */
.ally-card--create .ally-card__bar { flex-wrap: wrap; align-content: center; row-gap: 1px; height: auto; min-height: max(.74rem, 32px, calc(42px * var(--sp-ui, 1)));
  padding-top: 4px; padding-bottom: 4px; }
.ally-card__bar small { flex: 0 1 auto; margin-left: auto; min-width: min(100%, 10em); white-space: normal; text-align: right; text-wrap: balance;
  line-height: 1.2; font-size: calc(.14 * var(--t)); font-weight: 700; letter-spacing: 0; color: rgba(8, 34, 27, .75); }
.ally-card__bar small:lang(ko) { word-break: keep-all; overflow-wrap: break-word; }
.ally-card__bar small:lang(ja) { line-break: strict; }
button.ally-card:disabled { cursor: default; }
button.ally-card:disabled .ally-card__bar { filter: grayscale(.5) brightness(.8); }
/* the test-room box under 创建同盟 (test mode only) */
.ally-test { padding: 0 .2rem; }
.ally-card__bar--join { width: 100%; color: #2a1404; background: linear-gradient(180deg, #ffb24f, #f08a26); }
.ally-card__bar--join:disabled { filter: grayscale(.6) brightness(.75); cursor: default; }
.ally-card__bar--join:hover:not(:disabled), .ally-card__bar--join:focus-visible { filter: brightness(1.06); }
.ally-card__icon { flex: none; display: grid; place-items: center; width: max(.36rem, 22px); height: max(.36rem, 22px); color: currentColor; background: rgba(0, 0, 0, .14); border: 2px solid currentColor; border-radius: 4px; }
.ally-card__icon .icon { width: 74%; height: 74%; }
/* the key field: the project's TextField (.field / .field__box / .field__input) restyled as the event's grey bar, with
   观战 beside it inside the same bar */
.ally-key {
  display: flex;
  align-items: center;
  gap: .1rem;
  height: max(.56rem, 32px, calc(34px * var(--sp-ui, 1)));
  margin: .06rem .2rem .08rem;
  padding: 0 .06rem 0 .12rem;
  background: #262929;
  border: 1px solid rgba(255, 255, 255, .2);
  border-radius: .06rem;
}
.ally-key:focus-within { border-color: #ff9a3c; }
.ally-key .field { flex: 1 1 auto; height: 100%; gap: 0; }
.ally-key .field__box { height: 100%; padding: 0; gap: .1rem; background: none; border: 0; box-shadow: none; }
.ally-key .field__box::after { display: none; }
.ally-key .field__icon { flex: none; width: max(.24rem, 15px); height: max(.24rem, 15px); color: #c9cecc; }
.ally-key .field__box:focus-within .field__icon { color: #ff9a3c; }
.ally-key input {
  flex: 1 1 auto;
  min-width: 0;
  height: 100%;
  font: inherit;
  font-size: calc(.22 * var(--t));
  font-weight: 700;
  letter-spacing: .08em;
  text-align: center;
  text-transform: uppercase;
  text-overflow: ellipsis;
  color: #f2f4f3;
  background: none;
  border: 0;
  outline: none;
}
.ally-key input::placeholder { color: #8d9391; font-family: inherit; font-size: calc(.22 * var(--t)); font-weight: 500; letter-spacing: .04em; text-transform: none; }
.ally-key__spec {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: .04rem;
  height: 80%;
  padding: 0 .12rem;
  font: inherit;
  font-size: calc(.15 * var(--t));
  color: #eef0ef;
  background: rgba(255, 255, 255, .08);
  border: 1px solid rgba(255, 255, 255, .2);
  border-radius: 4px;
}
.ally-key__spec:hover:not(:disabled), .ally-key__spec:focus-visible { border-color: rgba(255, 255, 255, .5); }
.ally-key__spec:disabled { opacity: .45; cursor: default; }
.ally-key__spec .icon { width: 1.1em; height: 1.1em; }
.ally-recent { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: .06rem .1rem; min-height: .3rem; margin: 0 .2rem .1rem; font-size: calc(.14 * var(--t)); text-align: center; }
.code-chip {
  padding: .03rem .12rem .03rem .16rem;
  border: 1px solid var(--line-2);
  background: rgba(0, 0, 0, .3);
  color: var(--amber);
  font-size: calc(.17 * var(--t));
  font-weight: 700;
  letter-spacing: .2em;
  transition: border-color var(--t-fast), background-color var(--t-fast);
}
.code-chip:hover { border-color: var(--amber); background: rgba(246, 163, 41, .08); }

/* ---- 选择模拟协议's cards when they do not fit their column (screens/lobby.js pickCardFit: data-fit), above 520 px tall --
   (§35.18's leftover there: at 大 / 特大, in a small window or a long language the list ran under 开始独立模拟 with 终极模拟
   out of view.) 'brief': the description only in the brief at the left, where the chosen difficulty's already is;
   'names': a line each, and the brief adds the chosen difficulty's effects and rounds. At both, the chosen card's name
   ends in an ellipsis beside the stamp should a long language need it (the brief names it in full); the names stop at
   .36rem (base rule: at 特大 in a 1024 px window English ran past the cards). The short-screen block below has its own
   one-line cards. [ASSUMED] the levels and the sizes */
.proto-brief__more { display: none; }
@media (min-height: 521px) {
  .proto__body[data-fit="brief"] .pcard__desc,
  .proto__body[data-fit="names"] .pcard__desc, .proto__body[data-fit="names"] .pcard__effects, .proto__body[data-fit="names"] .pcard__meta { display: none; }
  .proto__body[data-fit="names"] .pcard { padding-top: .08rem; padding-bottom: .08rem; }
  .proto__body[data-fit="brief"] .pcard__head, .proto__body[data-fit="names"] .pcard__head { min-width: 0; }
  .proto__body[data-fit="brief"] .pcard__glyph, .proto__body[data-fit="names"] .pcard__glyph { flex: none; }
  .proto__body[data-fit="brief"] .pcard__name, .proto__body[data-fit="names"] .pcard__name { min-width: 0; overflow: hidden; text-overflow: ellipsis; line-height: 1.3; }
  .proto__body[data-fit="names"] .pcard.is-on .pcard__head { padding-right: max(.9rem, calc(46px * var(--sp-ui, 1))); }
  .proto__body[data-fit="names"] .pcard.is-on .pcard__stamp { right: .1rem; width: max(.8rem, 32px, calc(40px * var(--sp-ui, 1))); height: max(.64rem, 32px, calc(34px * var(--sp-ui, 1))); }
  .proto__body[data-fit="names"] .pcard.is-on .pcard__tick { width: max(.4rem, 22px); height: max(.4rem, 22px); }
  .proto__body[data-fit="names"] .pcard__ok { display: none; }
  .proto__body[data-fit="names"] .proto-brief__more { display: flex; flex-direction: column; gap: .04rem; margin-top: .06rem; padding-top: .06rem; border-top: 1px solid rgba(255, 255, 255, .18); }
  .proto-brief__effects { display: flex; flex-direction: column; font-size: calc(.16 * var(--t)); line-height: 1.4; color: #e9eceb; }
  .proto-brief__effects span::before { content: '·'; margin-right: .06rem; }
  .proto-brief__meta { display: flex; flex-wrap: wrap; align-items: center; gap: .04rem .14rem; font-size: calc(.13 * var(--t)); color: #7f8583; }
  .proto-brief__meta b { color: #cfd3d1; }
}

/* ---- narrow windows: the dialogs stack their halves ------------------------------------------------- */
@media (max-aspect-ratio: 1/1) {
  .proto-body { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, .7fr) minmax(0, 1.3fr); }
  .ally-body { grid-template-rows: minmax(0, .5fr) minmax(0, 1.5fr); }
  .proto__pic { inset: 0 0 .9rem; }
  /* the list keeps the .5rem the chosen card slides into (§35.51: at .1rem its -.44rem ran past the screen's left edge) */
  .proto-foot { padding-left: .1rem; }
  .ally-side { padding-left: 0; }
  /* the cards and the button span the width here: the caps for the landscape column (a 5.6rem column) give way */
  .pcard__name { font-size: calc(.28 * var(--t)); }
  .proto-foot .proto-start__label { font-size: calc(.4 * var(--t)); }
  .proto-foot .proto-start__rook { font-size: calc(.36 * var(--t)); }
}

/* ---- short landscape phones (≤ 520 CSS px tall) ---------------------------------------------------------- */
/* The hub drops its left column and the radar; the dialogs keep the four cards and the button in view without scrolling
   at every 文字大小 (the cards keep only their names, the selected difficulty's description moves to the brief). */
@media (max-height: 520px) {
  /* the entries span the screen's width here: at least 128 px each, so a wrapped English name has a line of its own
     (at 2.1rem, 84 px, 「Simulation」 was 95 px at 小). [ASSUMED] the width */
  .lobby-hub { --hub-entry-w: max(2.1rem, 32px, calc(128px * var(--sp-ui, 1))); }
  .hub-stage {
    grid-template-columns: minmax(0, 1fr) minmax(0, calc(var(--hub-entry-w) * 2 + var(--hub-gap)));
    grid-template-areas: "center right" "entries entries";
    gap: .14rem .3rem;
    padding: .1rem .4rem .24rem;
  }
  .hub-center { grid-column: 1; }
  .hub-side, .hub-radar { display: none; }
  .hub-center__mark { min-height: 0; margin-bottom: 0; }
  .hub-center__logo { width: .9rem; }
  .hub-center__mark .emblem__svg { width: .9rem; height: 1rem; }
  .hub-center__title { max-width: none; font-size: calc(.46 * var(--t)); }
  .hub-right { padding-top: .1rem; }
  .lobby-hub .hub-plate { min-height: max(.7rem, 32px, calc(40px * var(--sp-ui, 1))); }
  .lobby-hub .hub-plate--ach { display: flex; }
  /* (here the hub's height is the limit: a top padding for the icon made the English and Korean cards so tall at 大 /
     特大 that the line above them ran into the title on a 640 / 740 px phone. The decorative line keeps clear of the icon
     beside it instead, .44rem — at 小 it stays on one line there in every language) */
  .hub-entry { min-height: max(1.1rem, 32px, calc(64px * var(--sp-ui, 1))); padding: .1rem .14rem; }
  .hub-entry__icon .icon { width: .42rem; height: .42rem; }

  .proto-top { padding-top: 8px; }
  /* 选择模拟协议 (§35.18's leftover: at 文字大小 中 and above the four cards ran under 开始独立模拟 — 终极模拟 out of sight,
     the label cut — in every language, 844×390 and smaller): a wider column (7.4rem as 选择同盟方式's, 296 px here), the cards one
     line each — the name, 16–20 px, an ellipsis in the chosen card of a long language (the brief names it in full) —, the
     chosen difficulty's description in the brief at the left (11–13 px, the event's own place for it, as on a desktop),
     the header and the label capped (below) and the label wrapping onto a second line rather than being cut. The list
     still scrolls should a pack's names not fit. [ASSUMED] every cap */
  /* the column and the brief keep their unscaled widths under 界面大小 (÷ --sp-ui): the names' 16 px floor, the brief's
     11 px floor and the px paddings and stamp space do not shrink, so at 75 % a 222 px column cut 'Perilous Simulation'
     in English and the brief broke a Korean word (DESIGN §35.47) */
  .proto-body { grid-template-columns: minmax(0, 1fr) min(calc(7.4rem / var(--sp-ui, 1)), 50vw); gap: 10px; padding-bottom: 10px; }
  .ally-body { grid-template-columns: minmax(0, 1fr) min(calc(7.4rem / var(--sp-ui, 1)), 54vw); }
  .proto__pic { inset: 0 0 1.6rem; }
  .proto-brief { max-width: min(calc(6.4rem / var(--sp-ui, 1)), 100%); padding: 6px 10px 7px; }
  .proto-brief p { margin-top: 2px; font-size: clamp(11px, calc(.26 * var(--t)), 13px); line-height: 1.35; }
  .proto-list { gap: 6px; padding-left: 22px; justify-content: flex-start; }
  .pcard { padding: 6px 10px; gap: 2px; border-radius: 10px; }
  .pcard.is-on { transform: translateX(-16px); }
  .pcard__desc, .pcard__effects, .pcard__meta { display: none; }
  .pcard__head { min-width: 0; }
  .pcard__glyph { flex: none; }
  .pcard__name { min-width: 0; overflow: hidden; text-overflow: ellipsis; line-height: 1.3; }
  .pcard.is-on .pcard__head { padding-right: 46px; }
  .pcard.is-on .pcard__stamp { right: 6px; width: 40px; height: 34px; }
  .pcard.is-on .pcard__tick { width: 22px; height: 22px; }
  .pcard__ok { display: none; }
  .proto-foot { padding-left: 22px; }
  .proto-hint { display: none; }
  .proto-start { height: auto; min-height: 44px; gap: 10px; padding: 3px 0 3px 10px; }
  .proto-start__label { letter-spacing: .02em; }
  /* a column still taller than its space (a long language, the recent keys, the test-room box) scrolls rather than being
     cut off; the 4 px pad on the three other sides keeps the focus ring and the shadows inside the clip */
  .ally-side { gap: 8px; margin: -4px -4px -4px 0; padding: 4px 4px 4px 10px; overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; }
  .ally-card__art { display: none; }
  .ally-key { margin: 6px 10px; }
  .ally-recent { margin: 0 10px 6px; }
  .mf-radar { inset: 0 0 .6rem; height: calc(100% - .6rem); }
  /* 1rem is ~40 px here: the text gets its own sizes (still following 文字大小) */
  .hub-center__en { font-size: calc(.24 * var(--t)); }
  /* the plates' labels, the entries' names and their decorative English capped so they stay whole (§35.18 review: at 大 /
     特大 the plates ended in an ellipsis and the entries cut both lines); each cap is its size at 中 and grows a pixel a
     step above it (--t-step, theme.css), the entries 7 px wider a step for the name's longest word (「Simulation」 ~6.2em).
     [ASSUMED] the caps */
  .lobby-hub .hub-plate { font-size: min(calc(.3 * var(--t)), calc(18px + var(--t-step))); }
  .hub-plate__tag { display: none; }
  .hub-entry__group { height: auto; font-size: calc(.22 * var(--t)); }
  /* 同盟模拟's line keeps only 「1–4 名博士」 here (§35.51: the whole line, nowrap, ran 81–320 px past its entry at 特大 —
     two to four lines if it wrapped; the AI teammates are the room's to show) */
  .hub-entry__long { display: none; }
  .hub-entry__short { display: inline; }
  .hub-entry { width: calc(var(--hub-entry-w) + 7 * max(0px, var(--t-step))); }
  .hub-entry__en { padding-right: .44rem; font-size: min(calc(.16 * var(--t)), calc(10px + var(--t-step))); letter-spacing: .12em; }
  .hub-entry__name { font-size: min(calc(.42 * var(--t)), calc(18px + var(--t-step))); }
  .proto-title .modal__title { font-size: min(calc(.46 * var(--t)), 24px); white-space: nowrap; }
  .proto-title__mode, .proto-title__mode i { font-size: min(calc(.24 * var(--t)), 16px); }
  /* the mode line stays one line at a big 文字大小 in a long language (en 特大 broke 「Team Simulation」 in two, the
     header growing by a line the column needs): the decorative ALLIANCE / SOLO SIMULATION stops at 15 px [ASSUMED] and
     drops under as a whole if it still does not fit */
  .proto-title__mode { flex-wrap: wrap; justify-content: flex-end; row-gap: 0; white-space: nowrap; }
  .proto-title__mode i { font-size: min(calc(.24 * var(--t)), 15px); }
  .proto-brief__code { font-size: min(calc(.22 * var(--t)), 14px); }
  .proto-brief__name { font-size: min(calc(.34 * var(--t)), 20px); }
  .pcard__name { font-size: clamp(16px, calc(.4 * var(--t)), 20px); }
  .proto-foot .proto-start__label { font-size: min(calc(.5 * var(--t)), 20px); }
  .proto-foot .proto-start__rook { font-size: min(calc(.36 * var(--t)), 16px); }
  .proto-foot .proto-start__mark small { font-size: min(calc(.08 * var(--t)), 6px); }
  /* the bars' names 16–26 px here ([ASSUMED] the cap: en 「Create Alliance」 on its row at 特大, the column on the screen) */
  .ally-card__bar { font-size: clamp(16px, calc(.3 * var(--t)), 26px); }
  /* 创建同盟 keeps its difficulty line (§35.18's leftover: it was hidden here): two columns, the icon and the name on the
     first row, the line under the name on the second, wrapping rather than cut short; 11–14 px, [ASSUMED] the cap */
  .ally-card--create .ally-card__bar { display: grid; grid-template-columns: auto minmax(0, 1fr); align-content: center; row-gap: 1px; height: auto;
    min-height: max(.74rem, 32px, calc(42px * var(--sp-ui, 1))); padding-top: 5px; padding-bottom: 5px; }
  .ally-card--create .ally-card__name { min-width: 0; overflow: hidden; text-overflow: ellipsis; line-height: 1.2; }
  .ally-card--create .ally-card__bar small { grid-column: 2; margin-left: 0; overflow: visible; white-space: normal; text-align: left; font-size: clamp(11px, calc(.28 * var(--t)), 14px); line-height: 1.3; }
  .ally-key input { font-size: calc(.32 * var(--t)); }
  /* the key field's placeholder fits beside 观战 (§35.18's leftover: clipped at 特大 in English and Japanese): the short
     text (screens/lobby.js AllianceSelect `short`), 11–13 px, and 观战 at most 14 px; an ellipsis should a pack's
     name still be longer. [ASSUMED] the caps */
  .ally-key input::placeholder { font-size: clamp(11px, calc(.26 * var(--t)), 13px); }
  /* the empty field takes the placeholder's size, so the placeholder sits in the middle like the key will (§35.51: on the
     28 px key's baseline it sat 6–9 px below the key icon and 观战 at 特大) */
  .ally-key input:placeholder-shown { font-size: clamp(11px, calc(.26 * var(--t)), 13px); }
  .ally-key__spec { font-size: min(calc(.26 * var(--t)), 14px); }
  .ally-recent { font-size: min(calc(.24 * var(--t)), 14px); line-height: 1.35; } /* [ASSUMED] the cap, like the difficulty line's */
  .code-chip { font-size: calc(.28 * var(--t)); }
  .ally-guide { font-size: calc(.3 * var(--t)); }
}
/* ---- 转场 (PR #643, the event's screen changes): a screen comes up from black, its panels slide in one after another ---- */
.lobby-hub, .modal__box.proto, .modal__box.ally { --tr-ease: cubic-bezier(.16, .84, .3, 1); }
@keyframes tr-fade { from { opacity: 0; } }
@keyframes tr-veil { from { background-color: transparent; } }
@keyframes tr-right { from { opacity: 0; transform: translateX(.36rem); } }
@keyframes tr-left { from { opacity: 0; transform: translateX(-.36rem); } }
@keyframes tr-rise { from { opacity: 0; transform: translateY(.22rem); } }
@keyframes tr-zoom { from { opacity: 0; transform: scale(1.04); } }
@keyframes tr-draw { to { stroke-dashoffset: 0; } }
@keyframes tr-diamond { 0% { opacity: 0; transform: translateX(-50%) rotate(45deg) scale(.5); } 30%, 72% { opacity: 1; transform: translateX(-50%) rotate(45deg) scale(1); }
  100% { opacity: 0; transform: translateX(-50%) rotate(45deg) scale(1.1); } }
/* the hub */
.lobby-hub .hub-bg { animation: tr-fade 560ms ease-out backwards; }
.lobby-hub > .topbar { animation: tr-fade 320ms ease-out 120ms backwards; } /* opacity only: its dialogs are fixed */
.lobby-hub .hub-center { animation: tr-zoom 600ms var(--tr-ease) 140ms backwards; }
.lobby-hub .hub-side { animation: tr-left 480ms var(--tr-ease) 220ms backwards; }
.lobby-hub .hub-right { animation: tr-right 480ms var(--tr-ease) 260ms backwards; }
.hub-entries .hub-entry-wrap { animation: tr-rise 440ms var(--tr-ease) 300ms backwards; }
.hub-entries .hub-entry-wrap:nth-child(2) { animation-delay: 360ms; }
.hub-entries .hub-entry-wrap:nth-child(3) { animation-delay: 420ms; }
.hub-entries .hub-entry-wrap:nth-child(4) { animation-delay: 480ms; }
/* 选择模拟协议 / 选择同盟方式: from black, then the title, the stage and the cards */
.modal__box.proto, .modal__box.ally { animation: tr-veil 150ms linear backwards; }
.proto__bg { animation: tr-fade 340ms ease-out 140ms backwards; }
.proto-top { animation: tr-fade 260ms ease-out 170ms backwards; }
.proto-title { animation: tr-right 400ms var(--tr-ease) 200ms backwards; }
.proto-stage, .ally-stage { animation: tr-zoom 480ms var(--tr-ease) 190ms backwards; }
.proto-list .pcard { animation: tr-right 400ms var(--tr-ease) backwards; animation-delay: calc(240ms + var(--n, 0) * 60ms); }
.proto-list .pcard:nth-child(2) { --n: 1; }
.proto-list .pcard:nth-child(3) { --n: 2; }
.proto-list .pcard:nth-child(4) { --n: 3; }
.proto-list .pcard:nth-child(5) { --n: 4; }
.proto-foot { animation: tr-rise 400ms var(--tr-ease) 440ms backwards; }
.ally-card--create { animation: tr-right 420ms var(--tr-ease) 240ms backwards; }
.ally-card--join { animation: tr-right 420ms var(--tr-ease) 380ms backwards; }
.ally-guide { animation: tr-rise 380ms var(--tr-ease) 450ms backwards; }
/* the diamond at the bottom while it comes up */
.proto__body::after, .ally__body::after { content: ''; position: absolute; left: 50%; bottom: .5rem; z-index: 9; width: .3rem; height: .3rem; pointer-events: none; opacity: 0;
  border: 2px solid rgba(223, 230, 226, .55); box-shadow: inset 0 0 0 3px #0a0b0b, inset 0 0 0 5px rgba(223, 230, 226, .3); animation: tr-diamond 720ms ease-out 60ms both; }
/* the stamp's ring is drawn each time a difficulty is chosen */
.pcard.is-on .pcard__ring path { stroke-dasharray: 1; stroke-dashoffset: 1; animation: tr-draw 380ms ease-out 90ms forwards; }
.pcard.is-on .pcard__ring path + path { animation-delay: 260ms; }

@media (prefers-reduced-motion: reduce) {
  .hub-bg__ship, .hub-center, .hub-entry-wrap, .hub-radar__sweep, .proto__pic, .modal__box.proto, .modal__box.ally, .pcard.is-on .pcard__stamp,
  .mf-radar__sweep, .mf-radar__blip, .mf-blk.is-lit, .hub-bg__own, .lobby-hub .hub-bg, .lobby-hub > .topbar, .lobby-hub .hub-center, .lobby-hub .hub-side,
  .lobby-hub .hub-right, .hub-entries .hub-entry-wrap, .proto__bg, .proto-top, .proto-title, .proto-stage, .ally-stage, .proto-list .pcard, .proto-foot,
  .ally-card--create, .ally-card--join, .ally-guide, .pcard.is-on .pcard__ring path, .ps, .ps-fig, .ps-spike, .ps-call, .ps-beacon, .ps-scan { animation: none; }
  .ps-cable__pulse { display: none; }
  .pcard.is-on .pcard__ring path { stroke-dashoffset: 0; }
  .proto__body::after, .ally__body::after { display: none; }
}

/* official versions (DESIGN §35.23): the version under the title, the cards' wait while a version's data loads */
.hub-center__ver { position: relative; margin-top: .04rem; font-size: calc(.22 * var(--t)); font-weight: 700; letter-spacing: .08em; color: #9fd3ff; text-shadow: 0 1px .08rem rgba(0, 0, 0, .85); overflow-wrap: anywhere; }
.proto-list__wait { display: flex; align-items: center; gap: .08rem; margin: 0; color: var(--text-lo); font-size: calc(.15 * var(--t)); }
.proto-list__wait.is-failed { flex-wrap: wrap; color: var(--amber); }
.proto-list__wait.is-failed .icon { flex: none; width: 1.1em; height: 1.1em; }
