/* GENERATED by tools/webx/build-css.mjs from website/assets/ds.css, website/assets/wx-base.css, website/assets/wx-charstage.css, website/assets/wx-lobbybg.css, website/assets/wx-tip.css, website/assets/wx-charts.css, website/assets/style.css - do not edit by hand. */
/* ==== website/assets/ds.css ==== */
/* Genesis design system: web components of the community website (docs/UI.md §11.2, DESIGN §11.6).
   Values come only from tokens.css (generated from shared/ui/tokens.json, loaded first). Rules of §11.3:
   only transform and opacity animate, every duration is a --ds-motion-* token (0 ms with prefers-reduced-motion),
   corners are square, cards/tiles shear 0.10, chips 0.15, outlines and hard shadows are ink. */

/* ---------- base ---------- */
.ds-page { background: var(--ds-color-bg-screen); color: var(--ds-color-text-primary); font-family: var(--ds-font-body); font-size: var(--ds-type-body); }
.ds-num { font-variant-numeric: tabular-nums; }
:focus-visible { outline: var(--ds-outline-bold) solid var(--ds-color-accent-info); outline-offset: var(--ds-outline-thin); }
/* on a character accent (web-fix C2) the ring is ink with a yellow edge: visible on light (Anna cyan) and dark accents */
.ds-hero--char :focus-visible { outline: var(--ds-outline-thin) solid var(--ds-color-outline-ink); outline-offset: var(--ds-outline-thin); box-shadow: 0 0 0 calc(var(--ds-outline-thin) * 3) var(--ds-color-accent-primary); }

/* dot grid (§5.1: step 64, dot 6); the colour is set per surface through --ds-dot */
.ds-dots { background-image: radial-gradient(circle, var(--ds-dot, var(--ds-color-surface-row)) calc(var(--ds-space-dot-grid-dot) / 2), transparent calc(var(--ds-space-dot-grid-dot) / 2 + 0.5px)); background-size: var(--ds-space-dot-grid-step) var(--ds-space-dot-grid-step); }

/* ---------- top-nav tabs (§5.2): GROSS, muted, active yellow with an 8 px underline that slides ---------- */
.ds-nav { position: relative; display: flex; align-items: center; gap: var(--ds-space-l); }
.ds-nav a { position: relative; font-family: var(--ds-font-display); font-size: var(--ds-type-body); text-transform: uppercase; letter-spacing: 0; color: var(--ds-color-text-muted); text-decoration: none; padding: var(--ds-space-xs) 0; white-space: nowrap; }
.ds-nav a:hover { color: var(--ds-color-text-nav-hover); text-decoration: none; }
.ds-nav a:active { color: var(--ds-color-text-nav-pressed); }
.ds-nav a[aria-current="true"] { color: var(--ds-color-accent-primary); }
/* one bar for the whole nav, moved with transform (translateX + scaleX of a 100 px base) */
.ds-nav__bar { position: absolute; left: 0; bottom: calc(var(--ds-underline-h) * -1 + var(--ds-space-xxs)); width: 100px; height: var(--ds-underline-h); background: var(--ds-color-accent-primary); transform-origin: 0 50%; transform: translateX(var(--x, 0px)) scaleX(var(--w, 0)); opacity: 0; pointer-events: none; transition: transform var(--ds-motion-select) var(--ds-ease-enter), opacity var(--ds-motion-select) var(--ds-ease-enter); }
.ds-nav__bar.on { opacity: 1; }

/* underline tabs inside a section (roster filter): same look as the nav, own underline per tab */
/* web-fix C6 (W-O1 pattern): one line, scrolls sideways on narrow screens instead of wrapping */
.ds-tabs { display: flex; flex-wrap: nowrap; gap: var(--ds-space-l); max-width: 100%; overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none; padding: 0 calc(var(--ds-underline-extend) / 2); }
.ds-tabs::-webkit-scrollbar { display: none; }
.ds-tabs button { position: relative; flex: none; white-space: nowrap; background: none; border: 0; padding: var(--ds-space-xs) 0 var(--ds-space-s); cursor: pointer; font-family: var(--ds-font-display); font-size: var(--ds-type-nav); text-transform: uppercase; color: var(--ds-color-text-muted); }
.ds-tabs button:hover { color: var(--ds-color-text-nav-hover); }
.ds-tabs button::after { content: ""; position: absolute; left: calc(var(--ds-underline-extend) / -2); right: calc(var(--ds-underline-extend) / -2); bottom: 0; height: var(--ds-underline-h); background: var(--ds-color-accent-primary); transform: scaleX(0); transform-origin: 0 50%; transition: transform var(--ds-motion-select) var(--ds-ease-enter); }
.ds-tabs button[aria-pressed="true"] { color: var(--ds-color-accent-primary); }
.ds-tabs button[aria-pressed="true"]::after { transform: scaleX(1); }

/* ---------- buttons (§5.3) ---------- */
.ds-btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--ds-space-xs); min-height: var(--ds-space-button-h); padding: 0 var(--ds-space-button-pad-x); border: 0; border-radius: 0; cursor: pointer; font-family: var(--ds-font-display); font-size: var(--ds-type-label); line-height: 1.1; text-decoration: none; text-align: center; white-space: nowrap;
  transition: transform var(--ds-motion-press-up) var(--ds-ease-smooth); }
.ds-btn:hover { text-decoration: none; transform: scale(var(--ds-motion-hover-scale-button)); transition-duration: var(--ds-motion-hover); }
.ds-btn:active { transform: translateY(var(--ds-motion-press-y)); transition-duration: var(--ds-motion-press-down); }
.ds-btn--primary { text-transform: uppercase; color: var(--ds-color-text-on-primary); background: linear-gradient(180deg, color-mix(in srgb, var(--ds-color-accent-primary), var(--ds-palette-white) 8%), var(--ds-color-accent-primary) 60%); box-shadow: var(--ds-shadow-hard); }
.ds-btn--secondary { color: var(--ds-color-text-primary); background: var(--ds-color-surface-panel-deep); box-shadow: inset 0 0 0 var(--ds-outline-thin) var(--ds-color-outline-soft); }
.ds-btn--tertiary { color: var(--ds-color-text-on-card); background: var(--ds-color-surface-card-white); box-shadow: var(--ds-shadow-hard); }
.ds-btn--small { min-height: var(--ds-space-button-h-small); padding: 0 var(--ds-space-m); font-size: var(--ds-type-body); }
.ds-btn--wide { width: 100%; }
.ds-btn--wide:hover { transform: scale(var(--ds-motion-hover-scale-card)); }
.ds-btn--icon { width: var(--ds-space-icon-button); min-height: var(--ds-space-icon-button); padding: 0; border-radius: 50%; color: var(--ds-color-text-primary); background: var(--ds-color-surface-panel-deep); font-size: var(--ds-type-body-l); }
.ds-btn--icon:hover { transform: scale(var(--ds-motion-hover-scale-icon)); }

/* ---------- chips: status pill (currency pill shape) and skewed social chips ---------- */
.ds-chip { display: inline-flex; align-items: center; gap: var(--ds-space-xs); min-height: var(--ds-space-chip); padding: 0 var(--ds-space-m); border-radius: calc(var(--ds-space-chip) / 2); background: var(--ds-color-surface-panel-deep); color: var(--ds-color-text-primary); font-family: var(--ds-font-label); font-size: var(--ds-type-small); white-space: nowrap; border: 0; }
.ds-chip b { font-family: var(--ds-font-display); font-weight: 400; }
button.ds-chip { cursor: pointer; transition: transform var(--ds-motion-press-up) var(--ds-ease-smooth); }
button.ds-chip:hover { transform: scale(var(--ds-motion-hover-scale-button)); transition-duration: var(--ds-motion-hover); }
.ds-chip--social { position: relative; isolation: isolate; border-radius: 0; background: none; font-family: var(--ds-font-display); text-transform: uppercase; color: var(--ds-color-text-primary); text-decoration: none; transition: transform var(--ds-motion-press-up) var(--ds-ease-smooth); }
.ds-chip--social::before { content: ""; position: absolute; inset: 0; z-index: -1; background: var(--chip, var(--ds-color-accent-secondary)); transform: skewX(var(--ds-skew-chip)); box-shadow: var(--ds-shadow-hard); }
.ds-chip--social:hover { text-decoration: none; transform: scale(var(--ds-motion-hover-scale-button)); transition-duration: var(--ds-motion-hover); }
.ds-chip--social:active { transform: translateY(var(--ds-motion-press-y)); transition-duration: var(--ds-motion-press-down); }
.ds-chip--light { color: var(--ds-color-text-on-card); --chip: var(--ds-color-surface-card-white); }
.ds-dot { width: 10px; height: 10px; border-radius: 50%; flex: none; background: var(--ds-status-offline); display: inline-block; }
.ds-dot--online { background: var(--ds-status-online); }
.ds-dot--error { background: var(--ds-status-error); }
.ds-dot--info { background: var(--ds-color-accent-secondary); }

/* ---------- badges (§5.10): caption, GROSS, corner 2 ---------- */
.ds-badge { display: inline-flex; align-items: center; gap: var(--ds-space-xxs); padding: 3px var(--ds-space-xs); border-radius: 2px; font-family: var(--ds-font-display); font-size: var(--ds-type-caption); line-height: 1.2; text-transform: uppercase; white-space: nowrap; background: var(--ds-color-surface-row); color: var(--ds-color-text-primary); }
.ds-badge--modern { background: var(--ds-color-accent-secondary); color: var(--ds-color-text-primary); }
.ds-badge--event { background: var(--ds-color-accent-hot); color: var(--ds-color-text-primary); }
.ds-badge--new { background: var(--ds-color-accent-primary); color: var(--ds-color-text-on-primary); }
.ds-badge--new::before { content: ""; width: 9px; height: 9px; background: currentColor; clip-path: polygon(50% 0, 62% 38%, 100% 50%, 62% 62%, 50% 100%, 38% 62%, 0 50%, 38% 38%); }
.ds-badge--done { background: var(--ds-status-ready); color: var(--ds-color-text-on-primary); }
.ds-badge--wip { background: var(--ds-status-warn); color: var(--ds-color-text-on-primary); }
.ds-badge--next { background: var(--ds-color-accent-secondary); color: var(--ds-color-text-primary); }
.ds-badge--tier { min-width: 38px; height: 38px; justify-content: center; font-size: var(--ds-type-label); color: var(--ds-color-text-on-card); transform: skewX(var(--ds-skew-card)); }
.ds-badge--tier-S { background: var(--ds-rarity-legendary); }
.ds-badge--tier-A { background: var(--ds-rarity-epic); }
.ds-badge--tier-B { background: var(--ds-rarity-rare); }
.ds-badge--tier-C { background: var(--ds-rarity-uncommon); }
.ds-badge--tier-D { background: var(--ds-rarity-common); }

/* ---------- cards (§5.4): square, 4 px ink outline, hard ink shadow ---------- */
.ds-card { position: relative; background: var(--ds-color-surface-panel); border: var(--ds-outline-bold) solid var(--ds-color-outline-ink); box-shadow: var(--ds-shadow-hard); }
.ds-card--light { background: var(--ds-color-surface-card-white); color: var(--ds-color-text-on-card); }
.ds-card--link { transition: transform var(--ds-motion-press-up) var(--ds-ease-smooth); }
.ds-card--link:hover { transform: scale(var(--ds-motion-hover-scale-card)); transition-duration: var(--ds-motion-hover); text-decoration: none; }
.ds-card--link:active { transform: translateY(var(--ds-motion-press-y)); transition-duration: var(--ds-motion-press-down); }
/* stat card: big value in the display face, caption label */
.ds-stat { display: flex; flex-direction: column; gap: var(--ds-space-xxs); padding: var(--ds-space-m); background: var(--ds-color-surface-panel); border: var(--ds-outline-bold) solid var(--ds-color-outline-ink); box-shadow: var(--ds-shadow-hard); }
.ds-stat b { font-family: var(--ds-font-display); font-weight: 400; font-size: var(--ds-type-title-s); line-height: 1; color: var(--ds-color-text-primary); font-variant-numeric: tabular-nums; }
.ds-stat span { font-family: var(--ds-font-display); font-size: var(--ds-type-caption); text-transform: uppercase; color: var(--ds-color-text-muted); }
/* sheared image tile (tile 0.10): the frame shears, the picture is counter-sheared and slightly wider so no corner shows */
.ds-tile { position: relative; overflow: hidden; border: var(--ds-outline-bold) solid var(--ds-color-outline-ink); box-shadow: var(--ds-shadow-hard); transform: skewX(var(--ds-skew-card)); background: var(--ds-color-surface-panel-deep); }
.ds-tile > img { width: 112%; max-width: none; margin-left: -6%; height: 100%; object-fit: cover; transform: skewX(calc(var(--ds-skew-card) * -1)); }

/* ---------- table-like rows (§5.5): 56 px, numbers right-aligned tabular, rank 1–3 with a star badge ---------- */
.ds-rows { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--ds-space-xxs); }
.ds-row { display: grid; grid-template-columns: 36px 1fr auto; align-items: center; gap: var(--ds-space-s); min-height: var(--ds-space-table-row); padding: 0 var(--ds-space-s); background: var(--ds-color-surface-row); }
.ds-row b { font-family: var(--ds-font-display); font-weight: 400; text-align: right; font-variant-numeric: tabular-nums; }
.ds-rank { width: 32px; height: 32px; display: grid; place-items: center; font-family: var(--ds-font-display); font-size: var(--ds-type-small); color: var(--ds-color-text-primary); background: var(--ds-color-surface-panel-deep); }
.ds-rank.r1, .ds-rank.r2, .ds-rank.r3 { color: var(--ds-color-text-on-card); clip-path: polygon(50% 0, 63% 30%, 96% 32%, 70% 54%, 80% 88%, 50% 70%, 20% 88%, 30% 54%, 4% 32%, 37% 30%); width: 36px; height: 36px; padding-top: 3px; }
.ds-rank.r1 { background: var(--ds-status-leader); }
.ds-rank.r2 { background: var(--ds-rarity-common); }
.ds-rank.r3 { background: var(--ds-color-accent-primary-deep); }

/* ---------- progress bar (§5.9): row track, deep-yellow fill that grows with scaleX ---------- */
.ds-bar { height: 10px; background: var(--ds-color-surface-panel-deep); overflow: hidden; }
.ds-bar > i { display: block; height: 100%; background: var(--fill, var(--ds-color-accent-primary-deep)); transform-origin: 0 50%; animation: ds-fill var(--ds-motion-bar-fill) var(--ds-ease-enter) both; }

/* ---------- character profile header (§11.2 .ds-hero--char): accent surface + vector shapes + dot grid + faded giant name ---------- */
.ds-hero--char { position: relative; overflow: hidden; isolation: isolate; color: var(--ds-color-text-on-card); border: var(--ds-outline-bold) solid var(--ds-color-outline-ink); box-shadow: var(--ds-shadow-hard); background: var(--ds-color-accent-secondary); }
.ds-hero--char .ds-accent { position: absolute; inset: 0; z-index: -3; background: var(--accent, var(--ds-color-accent-secondary)); opacity: 0; transition: opacity var(--ds-motion-char-switch-crossfade) var(--ds-ease-smooth); }
.ds-hero--char .ds-accent.on { opacity: 1; }
.ds-hero--char .ds-shape { position: absolute; inset: 0; z-index: -2; --ds-dot: color-mix(in srgb, var(--ds-color-outline-ink) 10%, transparent); }
.ds-hero--char .ds-shape::before { content: ""; position: absolute; inset: 0; background: color-mix(in srgb, var(--ds-color-outline-ink) 12%, transparent); mask: url("img/ds/vector-shape.webp") right center / cover no-repeat luminance; }
.ds-bgname { position: absolute; z-index: -1; left: -0.04em; bottom: -0.16em; font-family: var(--ds-font-display); font-size: clamp(calc(var(--ds-type-mega) + var(--ds-space-l)), 18vw, calc(var(--ds-space-unit) * 75)); line-height: 1; text-transform: uppercase; white-space: nowrap; color: transparent; -webkit-text-stroke: 3px color-mix(in srgb, var(--ds-palette-white) 45%, transparent); opacity: 0; pointer-events: none; user-select: none;
  transition: opacity calc(var(--ds-motion-char-switch-crossfade) * 0.45) var(--ds-ease-exit); }
/* web-fix C4: the new giant name only fades in after the old one is gone (45 % of the switch), never two at once */
.ds-bgname.on { opacity: 0.4; transition: opacity calc(var(--ds-motion-char-switch-crossfade) * 0.55) var(--ds-ease-enter) calc(var(--ds-motion-char-switch-crossfade) * 0.45); }

/* ---------- loading / empty / error (§11.2) ---------- */
.ds-loading { display: flex; align-items: center; gap: var(--ds-space-s); color: var(--ds-color-text-muted); font-size: var(--ds-type-small); }
.ds-loading::before { content: ""; width: 24px; height: 24px; flex: none; background: var(--ds-color-accent-primary); clip-path: polygon(50% 0, 62% 38%, 100% 50%, 62% 62%, 50% 100%, 38% 62%, 0 50%, 38% 38%); animation: ds-spin var(--ds-motion-loading-spin) linear infinite; }
.ds-empty { color: var(--ds-color-text-muted); font-size: var(--ds-type-small); grid-column: 1 / -1; }
.ds-empty--error { color: var(--ds-status-error); }

/* ---------- motion (§11.3) ---------- */
/* card pop: scale .96 → 1 + opacity, panel-in, enter curve; staggered by --i (set by app.js, first 12 only) */
.ds-pop { animation: ds-pop var(--ds-motion-panel-in) var(--ds-ease-enter) both; animation-delay: calc(var(--ds-motion-stagger-tile) * var(--i, 0)); }
/* panel in: opacity + translateY(16 px) */
.ds-wait > * { opacity: 0; }
.ds-enter { animation: ds-panel-in var(--ds-motion-panel-in) var(--ds-ease-enter) both; }
@keyframes ds-pop { from { opacity: 0; transform: scale(var(--ds-motion-pop-scale)); } to { opacity: 1; transform: none; } }
@keyframes ds-panel-in { from { opacity: 0; transform: translateY(var(--ds-motion-panel-offset)); } to { opacity: 1; transform: none; } }
@keyframes ds-fill { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes ds-spin { to { transform: rotate(360deg); } }
/* character switch: old slides out to the left, new comes in from the right (crossfade 500 ms + 48 px) */
@keyframes ds-char-out { to { opacity: 0; transform: translateX(calc(var(--ds-motion-char-switch-slide) * -1)); } }
@keyframes ds-char-in { from { opacity: 0; transform: translateX(var(--ds-motion-char-switch-slide)); } to { opacity: 1; transform: none; } }
.ds-char-in { animation: ds-char-in-seq var(--ds-motion-char-switch-crossfade) linear both; }
/* View Transition of the character switch (app.js, with fallback .ds-char-in): only the named parts animate, the root is
   not captured (no full-page snapshot, the rest of the page stays live) */
:root { view-transition-name: none; }
/* web-fix C4 (W-O5): in sequence like the stats site - the old name and figure leave in 0–45 % (exit curve), the new ones
   come in during 45–100 % (enter curve), so two names are never readable at the same time */
::view-transition-old(ds-char-fig), ::view-transition-old(ds-char-text) { animation: ds-char-out-seq var(--ds-motion-char-switch-crossfade) linear both; }
::view-transition-new(ds-char-fig), ::view-transition-new(ds-char-text) { animation: ds-char-in-seq var(--ds-motion-char-switch-crossfade) linear both; }
@keyframes ds-char-out-seq { 0% { opacity: 1; transform: none; animation-timing-function: var(--ds-ease-exit); } 45%, 100% { opacity: 0; transform: translateX(calc(var(--ds-motion-char-switch-slide) * -1)); } }
@keyframes ds-char-in-seq { 0%, 45% { opacity: 0; transform: translateX(var(--ds-motion-char-switch-slide)); animation-timing-function: var(--ds-ease-enter); } 100% { opacity: 1; transform: none; } }
::view-transition-group(ds-char-fig), ::view-transition-group(ds-char-text) { animation-duration: var(--ds-motion-char-switch-crossfade); }
@media (prefers-reduced-motion: reduce) {
  .ds-pop, .ds-enter, .ds-char-in, .ds-bar > i { animation: none; }
  .ds-loading::before { animation: none; }
}

/* ==== website/assets/wx-base.css ==== */
/* wx-base.css: base rules of the WEBX2 kit (DESIGN WEBX2 §4.1, §5, §9.1). Source of truth: tools/webx/shared/, copied by sync-shared. */

/* §9.1 rule 1: one-line text with an ellipsis that never cuts glyphs vertically (accents, dotted İ, Й, i dots).
   overflow-x: clip keeps the y axis visible; the @supports branch pads the line box for browsers without clip. */
.wx-line { display: block; min-width: 0; white-space: nowrap; overflow-x: clip; overflow-y: visible; overflow-clip-margin: 0.25em; text-overflow: ellipsis; }
@supports not (overflow: clip) {
  .wx-line { overflow: hidden; padding-block: 0.2em; margin-block: -0.2em; }
}

/* §9.1 rule 3 (M-1): a Name#Tag only breaks between name and tag, never inside the number. */
.tag { white-space: nowrap; }

/* screen-reader only (data tables of the charts, §8.1) */
.wx-sr { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; border: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

/* §7.3 TMP <sprite=N>: an icon of Icons_Atlas_SpriteFont at the text baseline; tint=1 paints it in the colour of the text */
.wx-sprite { display: inline-block; width: 1.1em; height: 1.1em; margin-inline: 0.08em; vertical-align: -0.15em; background: var(--wx-sprite) center / contain no-repeat; }
.wx-sprite--tint { background: currentColor; -webkit-mask: var(--wx-sprite) center / contain no-repeat; mask: var(--wx-sprite) center / contain no-repeat; }

/* §5.1 StarWipe: the cover over the content area. The star edge (G13, TransitionEdge_Star.png) runs along the leading side. */
.wx-wipe { position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 40; pointer-events: auto; background: var(--wx-wipe-color, var(--ds-color-accent-primary)); transform: translateX(-102%); will-change: transform; }
.wx-wipe::before, .wx-wipe::after { content: ""; position: absolute; top: 0; bottom: 0; width: 28px; background: var(--wx-wipe-color, var(--ds-color-accent-primary)); -webkit-mask: var(--wx-wipe-edge, none) 0 0 / 28px 64px repeat-y; mask: var(--wx-wipe-edge, none) 0 0 / 28px 64px repeat-y; }
.wx-wipe::after { left: 100%; }
.wx-wipe::before { right: 100%; transform: scaleX(-1); }
.wx-wipe__star { position: absolute; top: 50%; left: 50%; width: 56px; height: 56px; margin: -28px 0 0 -28px; opacity: 0; color: var(--ds-color-outline-ink); }
.wx-wipe--hold .wx-wipe__star { opacity: 1; transition: opacity var(--ds-motion-fade-selectable) linear; }
.wx-wipe__star svg { width: 100%; height: 100%; animation: wx-spin var(--ds-motion-loading-spin) linear infinite; }
@keyframes wx-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .wx-wipe__star svg { animation: none; } }

/* §5.3 skeleton plates: static, no shimmer (DS §5.14) */
.sk { background: color-mix(in srgb, var(--ds-color-text-primary) 8%, transparent); border-radius: 0; color: transparent !important; }
.sk * { visibility: hidden; }

/* §9.2 fit text: the giant name always fits its stage. The stage is an inline-size container; --wx-name-em is the
   width of the name in em (gen-game nameEm for characters, WxFit for run-time names); --wx-bgname-hmax caps the height. */
.wx-fitbox { display: block; container-type: inline-size; min-width: 0; }
/* WEBX3 WN19: a run-time name (player) in its own box: the font size follows the box width (96cqi for sub-pixel room),
   at least 11 px (docs/UI.md), at most --fit-max; no overflow clip (i dots, accents). Invisible with its final height
   until WxFit has measured it (data-fit-ok); is-tall reserves two lines when the name may need them, is-wrap lets it wrap. */
.wx-fitline { display: block; font-family: var(--ds-font-display); font-weight: 400; font-size: clamp(11px, calc(96cqi / var(--wx-name-em, 8)), var(--fit-max, var(--ds-type-label))); white-space: nowrap; line-height: 1.15; padding-block: 0.12em; min-height: calc(var(--fit-max, var(--ds-type-label)) * 1.15 + 0.24em); overflow: visible; text-transform: none; }
.wx-fitline:not([data-fit-ok]) { visibility: hidden; }
.wx-fitline.is-tall { min-height: calc(var(--fit-max, var(--ds-type-label)) * 1.15 * 2 + 0.24em); }
.wx-fitline.is-wrap { white-space: normal; overflow-wrap: anywhere; }
.wx-fitname { font-size: min(var(--wx-bgname-max, var(--ds-type-bg-name, 640px)), calc(94cqw / var(--wx-name-em, 4)), var(--wx-bgname-hmax, 40vh)); white-space: nowrap; overflow: visible; line-height: 1.12; }

/* §5.1 card deal and morph helpers */
.wx-deal > * { transform-origin: 50% 80%; }
::view-transition-group(wx-morph) { animation-duration: var(--ds-motion-wipe-in); animation-timing-function: var(--ds-ease-enter); }

/* ==== website/assets/wx-charstage.css ==== */
/* wx-charstage.css: the character stage of the Genesis web pages, the web version of the in-game character page
   (WEBX DESIGN §4.4, look of the owner video f001 as reference only). Source of truth: tools/webx/shared/, copied
   byte-identical into site/ and website/assets/ by tools/webx/sync-shared.mjs. Tokens only (tokens.css), no colour,
   font or duration literals; motion = transform/opacity (the sequence itself runs in wx-charstage.js).
   Layers: full-bleed accent of the character (two layers A/B for the colour cross-fade) with the flat vector shapes of
   the lobby and the dot grid, the pale giant name, the character illustration cut by the edge, then name / role /
   badges left, abilities right, the character bar at the bottom. Variants: --page (character page / roster),
   --hero (overview hero), --mini (profile head, podium, compare). */

.wx-stage { position: relative; isolation: isolate; overflow-x: clip; display: grid; grid-template-columns: minmax(0, 4fr) minmax(0, 3fr) minmax(0, 3fr); grid-template-rows: 1fr auto; column-gap: var(--ds-space-l); min-height: clamp(520px, 64vh, 760px); margin-top: var(--ds-space-xxl); padding: var(--ds-space-xxl) var(--ds-space-screen-margin-x) var(--ds-space-l); color: var(--ds-color-text-primary); }
.wx-stage--hero { min-height: clamp(480px, 58vh, 680px); }
.wx-stage--mini { min-height: 300px; grid-template-columns: minmax(0, 6fr) minmax(0, 4fr); padding-top: var(--ds-space-xl); padding-bottom: var(--ds-space-xl); margin-top: var(--ds-space-xl); }

/* ---- background: accent A/B, vector shapes, dot grid, giant name (clipped to the stage) */
.wx-stage__bg { position: absolute; inset: 0; z-index: -2; overflow: hidden; border-top: var(--ds-outline-bold) solid var(--ds-color-outline-ink); border-bottom: var(--ds-outline-bold) solid var(--ds-color-outline-ink); }
.wx-stage__accent { position: absolute; inset: 0; background: var(--accent, var(--ds-color-accent-secondary)); }
.wx-stage__accent--b { opacity: 0; background: var(--accent-b, var(--accent, var(--ds-color-accent-secondary))); }
.wx-stage__bg::before { content: ""; position: absolute; inset: -10% -5%; background: color-mix(in srgb, var(--ds-palette-white) 22%, transparent); -webkit-mask-image: url("img/ds/vector-shape.webp"); mask-image: url("img/ds/vector-shape.webp"); -webkit-mask-size: cover; mask-size: cover; -webkit-mask-position: 60% 40%; mask-position: 60% 40%; }
.wx-stage__bg::after { content: ""; position: absolute; inset: 0; background-image: radial-gradient(circle, color-mix(in srgb, var(--ds-color-outline-ink) 12%, transparent) calc(var(--ds-space-dot-grid-dot) / 2), transparent calc(var(--ds-space-dot-grid-dot) / 2 + 0.5px)); background-size: var(--ds-space-dot-grid-step) var(--ds-space-dot-grid-step); }
/* WS12/WC03 (WEBX2 §9.2): one name that always fits (.wx-fitname, 94 % of the stage width via --wx-name-em), centred, never cut */
.wx-stage { container-type: inline-size; }
.wx-stage__bgname { position: absolute; left: 0; right: 0; top: 50%; z-index: 1; overflow: visible; font-family: var(--ds-font-display); --wx-bgname-max: var(--ds-type-bg-name); --wx-bgname-hmax: 44vh; line-height: 1.12; text-align: center; text-transform: uppercase; white-space: nowrap; color: transparent; -webkit-text-stroke: 3px color-mix(in srgb, var(--ds-palette-white) 30%, transparent); transform: translateY(-50%); pointer-events: none; user-select: none; }
.wx-stage--mini .wx-stage__bgname { --wx-bgname-max: 320px; --wx-bgname-hmax: 24vh; }

/* ---- the illustration: big, cut by the edge, over the top border; Genesis renders are framed by their figure box */
/* the figure box (--fx0…--fy1, game-data.json art.fullBox, every character) puts the top of the figure on the top of
   the art box, i.e. above the stage edge; its height is --wx-art-h of the art box, a wide figure is capped at
   --wx-art-w of the art box width (container units, the art box is the size container) */
.wx-stage__art { position: absolute; z-index: -1; top: calc(-1 * var(--ds-space-xxl)); bottom: 0; left: 30%; right: 22%; pointer-events: none; container-type: size; --wx-art-h: 112; --wx-art-w: 1.5; }
.wx-stage--hero .wx-stage__art { left: 38%; right: 6%; bottom: calc(-1 * var(--ds-space-xl)); --wx-art-h: 100; --wx-art-w: 1.25; }
.wx-stage--mini .wx-stage__art { left: 52%; right: 0; top: calc(-1 * var(--ds-space-xl)); }
.wx-stage__img { position: absolute; left: 50%; top: 0; height: min(calc(var(--wx-art-h) * 1cqh / (var(--fy1, 1) - var(--fy0, 0))), calc(var(--wx-art-w) * 100cqw / (var(--fx1, 1) - var(--fx0, 0)))); width: auto; max-width: none; transform: translate(calc(-100% * (var(--fx0, 0) + var(--fx1, 1)) / 2), calc(-100% * var(--fy0, 0))); }
.wx-stage__img--portrait { height: 100%; }
.wx-stage__img.is-old { z-index: -1; }

/* ---- identity (left): badges, name, role, meta; the page puts its own block in .wx-stage__extra */
.wx-stage__id { grid-column: 1; grid-row: 1; align-self: center; display: flex; flex-direction: column; align-items: flex-start; gap: var(--ds-space-s); min-width: 0; z-index: 1; }
.wx-stage__badges { display: flex; flex-wrap: wrap; gap: var(--ds-space-xs); }
.wx-stage__name { margin: 0; font-family: var(--ds-font-display); font-weight: 400; font-size: var(--ds-type-hero); line-height: 0.95; text-transform: uppercase; overflow-wrap: normal; word-break: keep-all; text-wrap: balance; }
.wx-stage__name--player { text-transform: none; font-size: var(--ds-type-headline); overflow-wrap: anywhere; } /* player names are data, shown as written like in the game (DR-14) */
.wx-stage__role { margin: 0; font-family: var(--ds-font-display); font-size: var(--ds-type-label); line-height: 1.15; }
.wx-stage__extra { display: flex; flex-direction: column; align-items: flex-start; gap: var(--ds-space-m); margin-top: var(--ds-space-s); }
.wx-stage--mini .wx-stage__name { font-size: var(--ds-type-headline); }
.wx-stage--mini .wx-stage__name--player { font-size: var(--ds-type-title); }
/* WN19: the fit name box takes the width of the identity column (a flex child of align-items:start would be 0 wide) */
.wx-stage--mini .wx-stage__name--player { width: 100%; }

/* text colour on the accent: ink where ink has the higher WCAG contrast (light accents, like in the game), otherwise
   off-white with the hard ink shadow */
.wx-stage.wx-on-ink { color: var(--ds-color-text-on-card); }
.wx-stage.wx-on-light .wx-stage__name, .wx-stage.wx-on-light .wx-stage__role, .wx-stage.wx-on-light .wx-abil__name { text-shadow: 0 var(--ds-outline-bold) 0 var(--ds-color-outline-ink); }
/* focus on the accent: ink 3 px plus off-white 2 px outside (DR-8 point 2), never the info cyan */
.wx-stage :focus-visible { outline: 3px solid var(--ds-color-outline-ink); outline-offset: 0; box-shadow: 0 0 0 5px var(--ds-palette-off-white); }

/* ---- badges (UI.md §5.10 form): parallelogram, caption GROSS, 20 high */
.wx-badge { display: inline-flex; align-items: center; height: 20px; padding: 0 var(--ds-space-xs); font-family: var(--ds-font-display); font-size: var(--ds-type-caption); line-height: 1; text-transform: uppercase; white-space: nowrap; transform: skewX(var(--ds-skew-chip)); border: var(--ds-outline-thin) solid var(--ds-color-outline-ink); }
.wx-badge > span { display: inline-block; transform: skewX(calc(-1 * var(--ds-skew-chip))); }
.wx-badge--original { background: var(--ds-palette-off-white); color: var(--ds-color-text-on-card); }
.wx-badge--genesis, .wx-badge--modern { background: var(--ds-color-accent-secondary); color: var(--ds-palette-white); }
.wx-badge--season { background: var(--ds-color-outline-ink); color: var(--ds-palette-off-white); }

/* ---- abilities (right): four round icons, the chosen one with the yellow ring, name | slot and the short text */
.wx-stage__abilities { grid-column: 3; grid-row: 1; align-self: center; display: flex; flex-direction: column; gap: var(--ds-space-m); min-width: 0; z-index: 1; }
.wx-abil__icons { display: flex; gap: var(--ds-space-s); flex-wrap: wrap; }
.wx-abil__btn { position: relative; display: grid; place-items: center; width: var(--ds-icon-ability); height: var(--ds-icon-ability); padding: 0; border: var(--ds-outline-bold) solid var(--ds-color-outline-ink); border-radius: 50%; background: var(--ds-color-outline-ink); color: var(--ds-palette-off-white); font-family: var(--ds-font-display); font-size: var(--ds-type-small); cursor: pointer; transform: scale(1); transition: transform var(--ds-motion-hover) var(--ds-ease-smooth); }
.wx-abil__btn img { width: 78%; height: 78%; object-fit: contain; pointer-events: none; }
.wx-abil__btn:hover { transform: scale(var(--ds-motion-hover-scale-icon)); }
.wx-abil__btn[aria-selected="true"] { box-shadow: 0 0 0 var(--ds-outline-bold) var(--ds-color-accent-primary), 0 0 0 calc(var(--ds-outline-bold) * 2) var(--ds-color-outline-ink); }
.wx-abil__panel { min-height: 6.5em; max-width: 34ch; }
.wx-abil__name { margin: 0 0 2px; overflow-wrap: normal; word-break: normal; text-wrap: balance; font-family: var(--ds-font-display); font-weight: 400; font-size: var(--ds-type-title-s); line-height: 1.1; }
.wx-abil__type { display: block; margin: 0 0 var(--ds-space-xs); font-family: var(--ds-font-body); font-size: var(--ds-type-small); line-height: 1.25; white-space: normal; } /* M-2: own line under the title */
.wx-abil__btn .wx-abil__glyph { width: 46%; height: 46%; fill: var(--ds-color-accent-primary); pointer-events: none; }
.wx-abil__short { margin: 0; font-family: var(--ds-font-body); font-size: var(--ds-type-body-l); line-height: 1.45; }
.wx-abil__later { margin: 0; font-family: var(--ds-font-body); font-size: var(--ds-type-body); }

/* ---- character bar (bottom): cards like the in-game bar, chosen one taller with the yellow inner edge */
.wx-bar { grid-column: 1 / -1; grid-row: 2; position: relative; z-index: 2; display: flex; align-items: flex-end; gap: var(--ds-space-xs); margin-top: var(--ds-space-l); }
.wx-bar__track { display: flex; align-items: flex-end; gap: var(--ds-space-xs); min-width: 0; flex: 1; overflow-x: auto; overflow-y: hidden; padding: var(--ds-space-xs) var(--ds-space-xs) var(--ds-space-xs); scroll-snap-type: x proximity; scrollbar-width: none; }
.wx-bar__track::-webkit-scrollbar { display: none; }
.wx-bar__c { position: relative; flex: 0 0 auto; width: var(--ds-space-char-card-w); height: var(--ds-space-char-card-h); padding: 0; overflow: hidden; border: var(--ds-outline-bold) solid var(--ds-color-outline-ink); background: var(--ds-palette-navy); cursor: pointer; scroll-snap-align: center; transform: skewX(var(--ds-skew-card)) scale(1); transition: transform var(--ds-motion-hover) var(--ds-ease-smooth); }
.wx-bar__c:hover { transform: skewX(var(--ds-skew-card)) scale(var(--ds-motion-hover-scale-card)); }
.wx-bar__c img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: var(--crop, 50% 20%); transform: skewX(calc(-1 * var(--ds-skew-card))) scale(var(--zoom, 1.15)); transform-origin: var(--crop, 50% 20%); }
.wx-bar__c img.is-crop { inset: auto; height: auto; max-width: none; object-fit: fill; transform: skewX(calc(-1 * var(--ds-skew-card))); transform-origin: 0 0; }
.wx-bar__c .wx-bar__ini { position: absolute; inset: 0; display: grid; place-items: center; font-family: var(--ds-font-display); font-size: var(--ds-type-title-s); color: var(--ds-palette-off-white); transform: skewX(calc(-1 * var(--ds-skew-card))); }
.wx-bar__c[aria-selected="true"] { height: var(--ds-space-char-card-h-selected); box-shadow: inset 0 0 0 var(--ds-outline-bold) var(--ds-color-accent-primary); }
.wx-bar__c[aria-selected="true"]::after { content: ""; position: absolute; inset: 0; box-shadow: inset 0 0 0 var(--ds-outline-bold) var(--ds-color-accent-primary); }
.wx-bar__tag { position: absolute; left: var(--ds-space-xxs); bottom: var(--ds-space-xxs); z-index: 1; padding: 0 var(--ds-space-xxs); background: var(--ds-color-outline-ink); color: var(--ds-palette-off-white); font-family: var(--ds-font-display); font-size: var(--ds-type-caption); line-height: 1.6; transform: skewX(calc(-1 * var(--ds-skew-card))); }
.wx-bar__arrow { flex: 0 0 auto; width: var(--ds-space-icon-button); height: var(--ds-space-icon-button); margin-bottom: var(--ds-space-xxl); padding: 0; border: var(--ds-outline-bold) solid var(--ds-color-outline-ink); border-radius: 50%; background: var(--ds-palette-off-white); color: var(--ds-color-text-on-card); cursor: pointer; }
.wx-bar__arrow svg { width: 60%; height: 60%; fill: none; stroke: currentColor; stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; }
.wx-bar__arrow:disabled { opacity: 0.4; cursor: default; }

/* ---- side slot of the hero (live plate etc.) */
.wx-stage__side { grid-column: 3; grid-row: 1; align-self: start; justify-self: end; z-index: 1; }
.wx-stage--mini .wx-stage__side { grid-column: 2; align-self: center; }

/* ---- phone */
@media (max-width: 1023px) {
  .wx-stage { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .wx-stage__abilities { grid-column: 1 / -1; grid-row: 2; align-self: end; margin-top: var(--ds-space-l); }
  .wx-bar { grid-row: 3; }
  .wx-stage__art { left: 40%; right: -6%; }
  .wx-stage__side { grid-column: 2; }
}
@media (max-width: 767px) {
  .wx-stage { grid-template-columns: minmax(0, 1fr); min-height: 560px; margin-top: var(--ds-space-xl); padding: var(--ds-space-l) var(--ds-space-m) var(--ds-space-m); }
  .wx-stage--hero { min-height: 520px; }
  .wx-stage--mini { min-height: 260px; }
  .wx-stage__id { align-self: start; max-width: 100%; }
  .wx-stage__id > :not(.wx-stage__name):not(.wx-stage__badges) { max-width: 72%; }
  .wx-stage--hero .wx-stage__id { max-width: 100%; }
  .wx-stage__name { font-size: clamp(32px, 12vw, calc(var(--ds-type-hero) * 0.6)); }
  .wx-stage__name--player { font-size: calc(var(--ds-type-headline) * 0.6); }
  .wx-stage--mini .wx-stage__name { font-size: calc(var(--ds-type-headline) * 0.6); }
  .wx-stage--mini .wx-stage__name--player { font-size: calc(var(--ds-type-title) * 0.7); }
  .wx-stage__role { font-size: var(--ds-type-body-l); }
  .wx-stage__art { left: 46%; right: -34%; top: var(--ds-space-xxl); bottom: 42%; }
  .wx-stage--hero .wx-stage__art { left: 42%; right: -36%; bottom: 0; top: 34%; }
  .wx-stage--mini .wx-stage__art { left: 56%; right: -36%; top: 0; }
  .wx-stage__abilities { grid-column: 1; grid-row: 2; margin-top: var(--ds-space-xxxl); }
  .wx-stage__side { grid-column: 1; grid-row: 2; justify-self: start; margin-top: var(--ds-space-l); }
  .wx-abil__btn { width: 56px; height: 56px; }
  .wx-abil__short { font-size: var(--ds-type-body); }
  .wx-abil__type { white-space: normal; } /* narrow: the slot words may wrap among themselves, "|" stays glued (no-break spaces) */
  .wx-bar { margin-top: var(--ds-space-m); }
  .wx-bar__arrow { display: none; }
  .wx-bar__c { width: 60px; height: 104px; }
  .wx-bar__c[aria-selected="true"] { height: 124px; }
}

/* ---- language switcher of genesis-i18n.js (button + listbox with the endonyms of every client language) */
.wx-lang { position: relative; flex: none; }
.wx-lang__btn { display: inline-flex; align-items: center; gap: var(--ds-space-xs); height: var(--ds-space-chip); padding: 0 var(--ds-space-s); border: var(--ds-outline-thin) solid var(--ds-color-outline-soft); background: var(--ds-color-surface-panel-deep); color: var(--ds-color-text-primary); font-family: var(--ds-font-display); font-size: var(--ds-type-small); cursor: pointer; white-space: nowrap; }
.wx-lang__btn svg { width: var(--ds-icon-xs); height: var(--ds-icon-xs); fill: none; stroke: currentColor; stroke-width: 2; }
.wx-lang__list { position: absolute; right: 0; top: calc(100% + var(--ds-space-xs)); z-index: 50; min-width: 200px; max-height: min(70vh, 520px); overflow-y: auto; margin: 0; padding: var(--ds-space-xs) 0; list-style: none; background: var(--ds-color-surface-panel-deep); border: var(--ds-outline-bold) solid var(--ds-color-outline-ink); box-shadow: var(--ds-shadow-hard); outline: none; }
.wx-lang__list li { padding: var(--ds-space-xs) var(--ds-space-m); font-family: var(--ds-font-body); font-size: var(--ds-type-body); color: var(--ds-color-text-primary); cursor: pointer; }
.wx-lang__list li[aria-selected="true"] { color: var(--ds-color-accent-primary); }
.wx-lang__list li.is-active, .wx-lang__list li:hover { background: var(--ds-color-surface-row); }
.wx-lang__list:focus-visible li.is-active { box-shadow: inset 3px 0 0 var(--ds-color-accent-primary); }

@media (prefers-reduced-motion: reduce) {
  .wx-abil__btn, .wx-bar__c { transition: none !important; }
}

/* ==== website/assets/wx-lobbybg.css ==== */
/* wx-lobbybg.css: layers of the lobby splash (DESIGN WEBX2 §6.3). Source of truth: tools/webx/shared/. */
.wx-lobbybg { position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: -1; overflow: hidden; pointer-events: none; contain: strict; view-transition-name: wx-lobbybg; background: var(--ds-color-bg-screen); }
.wx-lobbybg--hero { position: absolute; z-index: 0; }
.wx-lobbybg__bg, .wx-lobbybg__kitsu, .wx-lobbybg__front { position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; }
.wx-lobbybg__scrim { position: absolute; top: 0; right: 0; bottom: 0; left: 0; background: var(--ds-color-bg-lobby-scrim); }
.wx-lobbybg__smoke { position: absolute; left: 0; bottom: 0; height: calc(var(--wx-smoke-h, 0.24) * 100%); width: calc(100% + var(--wx-smoke-tile, 0px)); background: var(--wx-smoke-img) repeat-x 0 100% / auto 100%; opacity: var(--wx-smoke-op, 1); will-change: transform; }
.wx-lobbybg__sparks { position: absolute; top: 0; right: 0; bottom: 0; left: 0; }
.wx-lobbybg__sparks i { position: absolute; left: 0; top: 0; background: var(--wx-spark-img) center / contain no-repeat; will-change: transform, opacity; }
.wx-lobbybg__figure, .wx-lobbybg__fx, .wx-lobbybg__fy { position: absolute; top: 0; right: 0; bottom: 0; left: 0; }
.wx-lobbybg__front { opacity: 1; }
/* a missing texture: the static background of WEBX (§6.5) shows through */
.wx-lobbybg--off { display: none; }
@media (prefers-reduced-motion: reduce) {
  .wx-lobbybg__sparks { display: none; }
}
@view-transition { navigation: auto; }
@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
}

/* ==== website/assets/wx-tip.css ==== */
/* wx-tip.css: tooltip like UITooltip of the client (DESIGN WEBX2 §7.4, docs/UI.md §5.7). Source: tools/webx/shared/. */
.wx-tip { position: absolute; z-index: 60; box-sizing: border-box; max-width: min(320px, calc(100vw - 16px)); padding: var(--ds-space-m); background: var(--ds-color-surface-tooltip); color: var(--ds-color-text-primary); border: var(--ds-outline-bold) solid var(--ds-color-outline-ink); box-shadow: var(--ds-shadow-hard); pointer-events: none; transform-origin: 50% 100%; }
.wx-tip--sheet { position: fixed; left: 0 !important; right: 0; bottom: 0; top: auto !important; max-width: none; padding-bottom: calc(var(--ds-space-l) + env(safe-area-inset-bottom, 0px)); pointer-events: auto; border-width: var(--ds-outline-bold) 0 0; }
.wx-tip__head { display: flex; align-items: center; gap: var(--ds-space-s); }
.wx-tip__icon { flex: none; display: grid; place-items: center; width: 52px; height: 52px; background: var(--ds-color-surface-panel-deep); border: var(--ds-outline-bold) solid var(--wx-rar, var(--ds-color-outline-ink)); }
.wx-tip__icon img { width: 44px; height: 44px; object-fit: contain; }
.wx-tip__icon .wx-sprite { width: 32px; height: 32px; margin: 0; }
.wx-tip__icon[data-rarity="0"] { --wx-rar: var(--ds-rarity-common); }
.wx-tip__icon[data-rarity="1"] { --wx-rar: var(--ds-rarity-uncommon); }
.wx-tip__icon[data-rarity="2"] { --wx-rar: var(--ds-rarity-rare); }
.wx-tip__icon[data-rarity="3"] { --wx-rar: var(--ds-rarity-epic); }
.wx-tip__icon[data-rarity="4"] { --wx-rar: var(--ds-rarity-legendary); }
.wx-tip__titles { min-width: 0; }
.wx-tip__name { font-family: var(--ds-font-display); font-size: var(--ds-type-title-s); line-height: 1.12; overflow-wrap: anywhere; }
.wx-tip__sub { font-family: var(--ds-font-body); font-size: var(--ds-type-small); line-height: 1.25; color: var(--ds-color-text-tooltip); }
.wx-tip__body { margin-top: var(--ds-space-s); font-family: var(--ds-font-body); font-size: var(--ds-type-body); line-height: 1.35; }
.wx-tip__body p { margin: 0; }
.wx-tip__body p + p { margin-top: var(--ds-space-xs); }
.wx-tip__body strong { font-weight: 400; font-family: var(--ds-font-display); }
.wx-tip__none, .wx-tip__order { color: var(--ds-color-text-tooltip); font-size: var(--ds-type-small); margin: var(--ds-space-xs) 0 0; }
[data-tip] { cursor: help; }
[data-tip]:focus-visible { outline: var(--ds-outline-bold) solid var(--ds-color-accent-primary); outline-offset: 2px; }

/* ==== website/assets/wx-charts.css ==== */
/* wx-charts.css: the DS look of the WEBX2 charts (DESIGN WEBX2 §8.1). Source: tools/webx/shared/. Motion: transform only, once. */
.wx-chart { margin: 0; position: relative; }
.wx-legend { display: flex; flex-wrap: wrap; gap: var(--ds-space-xs) var(--ds-space-m); margin-top: var(--ds-space-s); font-size: var(--ds-type-caption); color: var(--ds-color-text-muted); }
.wx-legend span::before { content: ""; display: inline-block; width: 10px; height: 10px; margin-right: 4px; vertical-align: -1px; background: var(--c); border: var(--ds-outline-thin) solid var(--ds-color-outline-ink); }
.wx-legend b { color: var(--ds-color-text-primary); font-weight: 400; font-family: var(--ds-font-display); }
/* radar */
.wx-radar svg { width: 100%; max-width: 380px; height: auto; display: block; margin: 0 auto; overflow: visible; }
.wx-radar__ring { fill: none; stroke: var(--ds-color-outline-soft); stroke-width: 1.5; }
.wx-radar__spoke { stroke: var(--ds-color-outline-soft); stroke-width: 1; }
.wx-radar__area { fill: color-mix(in srgb, var(--c) 45%, transparent); stroke: var(--c); stroke-width: 3; stroke-linejoin: round; }
.wx-radar__shadow { fill: var(--ds-color-outline-ink); opacity: 0.6; }
.wx-radar__label { fill: var(--ds-color-text-muted); font-family: var(--ds-font-body); font-size: 12px; }
.wx-radar__grow { transition: transform calc(var(--ds-motion-bar-fill) * 1.5) var(--ds-ease-enter); }
.wx-chart.is-wait .wx-radar__grow { transform: scale(0.6); }
/* columns (+ line) */
.wx-cols__plot { position: relative; display: flex; align-items: flex-end; gap: 2px; height: 180px; padding-top: var(--ds-space-m); border-bottom: var(--ds-outline-bold) solid var(--ds-color-outline-ink); }
.wx-col { flex: 1 1 0; min-width: 2px; height: 100%; background: var(--c); transform: scaleY(var(--h)); transform-origin: 50% 100%; border: var(--ds-outline-thin) solid var(--ds-color-outline-ink); border-bottom: 0; transition: transform var(--ds-motion-bar-fill) var(--ds-ease-enter); transition-delay: calc(var(--i) * var(--ds-motion-stagger-tile)); }
.wx-col[data-mark] { background: var(--ds-color-accent-primary); }
.wx-chart.is-wait .wx-col { transform: scaleY(0); }
.wx-col-line { position: absolute; inset: var(--ds-space-m) 0 0 0; width: 100%; height: calc(100% - var(--ds-space-m)); overflow: visible; pointer-events: none; }
.wx-col-line path { fill: none; stroke-width: 3; vector-effect: non-scaling-stroke; stroke-dasharray: 1; stroke-dashoffset: 0; transition: stroke-dashoffset calc(var(--ds-motion-bar-fill) * 2) var(--ds-ease-smooth); }
.wx-chart.is-wait .wx-col-line path { stroke-dashoffset: 1; }
.wx-cols__max, .wx-cols__lmax { position: absolute; top: 0; font-family: var(--ds-font-display); font-weight: 400; font-size: var(--ds-type-caption); line-height: 1.12; }
.wx-cols__max { left: 0; color: var(--ds-color-text-muted); }
.wx-cols__lmax { right: 0; }
.wx-cols__x { position: relative; height: 22px; font-size: var(--ds-type-caption); color: var(--ds-color-text-muted); }
.wx-cols__x span { position: absolute; top: 4px; left: calc(var(--x) * 100%); transform: translateX(calc(var(--x) * -100%)); white-space: nowrap; }
/* butterfly (WEBX3 WN19): one column template for the whole chart (--vw = longest value + 1ch), value | bar A | bar B |
   value; the label stands above the bars and may wrap; every row is scaled to its larger value, so a value never leaves
   its column. The names in the head fit their own column (.wx-fitbox, wx-base.css). */
.wx-bf__head { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: var(--ds-space-m); margin-bottom: var(--ds-space-xs); font-family: var(--ds-font-display); }
.wx-bf__head .wx-bf__na { color: var(--ca); } .wx-bf__head .wx-bf__nb { color: var(--cb); text-align: right; }
.wx-bf__row { display: grid; grid-template-columns: var(--vw, 6ch) minmax(0, 1fr) minmax(0, 1fr) var(--vw, 6ch); grid-template-rows: auto 16px; row-gap: var(--ds-space-xxs); column-gap: var(--ds-space-xs); align-items: center; padding: var(--ds-space-xs) 0 var(--ds-space-xxs); }
.wx-bf__row + .wx-bf__row { border-top: 1px solid var(--ds-color-outline-soft); }
.wx-bf__label { grid-column: 1 / -1; grid-row: 1; text-align: center; font-size: var(--ds-type-small); line-height: 1.3; color: var(--ds-color-text-muted); overflow-wrap: normal; text-wrap: balance; }
.wx-bf__va, .wx-bf__vb { grid-row: 2; font-family: var(--ds-font-display); font-weight: 400; font-size: var(--ds-type-small); line-height: 1.15; font-variant-numeric: tabular-nums; white-space: nowrap; }
.wx-bf__va { grid-column: 1; text-align: right; } .wx-bf__vb { grid-column: 4; text-align: left; }
.wx-bf__bars { grid-column: 2 / 4; grid-row: 2; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); height: 16px; transform-origin: 50% 50%; transition: transform var(--ds-motion-bar-fill) var(--ds-ease-enter); transition-delay: calc(var(--i, 0) * var(--ds-motion-stagger-tile)); }
.wx-chart.is-wait .wx-bf__bars { transform: scaleX(0); }
.wx-bf__ha { display: flex; justify-content: flex-end; } .wx-bf__hb { display: flex; justify-content: flex-start; }
.wx-bf__ha i, .wx-bf__hb i { display: block; box-sizing: border-box; height: 16px; width: calc(var(--w) * 100%); min-width: 3px; border: var(--ds-outline-thin) solid var(--ds-color-outline-ink); }
.wx-bf__ha i { background: var(--ca); } .wx-bf__hb i { background: var(--cb); }
.wx-bf__ha i.is-zero, .wx-bf__hb i.is-zero { min-width: 0; border: 0; }
/* the better value: the yellow edge inside the bar (an outside ring made the bar look longer and touched the label above) */
.wx-bf__ha i.is-win, .wx-bf__hb i.is-win { border: 3px solid var(--ds-color-accent-primary); }
.wx-bf__va.is-win, .wx-bf__vb.is-win { color: var(--ds-color-accent-primary); }
.wx-bf__row[data-tip] { cursor: help; }
.wx-bf__row[data-tip]:hover .wx-bf__label, .wx-bf__row[data-tip]:focus-visible .wx-bf__label { color: var(--ds-color-text-primary); }
/* legend of a duel (radar): colour field + fit name, one column per player */
.wx-legend--duel { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: var(--ds-space-s); font-family: var(--ds-font-display); color: var(--ds-color-text-primary); }
.wx-legend--duel .wx-legend__item { display: flex; align-items: center; gap: var(--ds-space-xxs); min-width: 0; }
/* no generic legend square on the item or on the spans of the fit name (WN20: "two offset squares") */
.wx-legend--duel span::before { content: none; display: none; }
.wx-legend--duel .wx-legend__sw { flex: none; width: 12px; height: 12px; background: var(--c); border: var(--ds-outline-thin) solid var(--ds-color-outline-ink); }
.wx-legend--duel .wx-fitbox { flex: 1 1 0; }/* horizontal bars */
.wx-hb__row { display: grid; grid-template-columns: minmax(0, 10rem) minmax(0, 1fr) auto; gap: var(--ds-space-s); align-items: center; padding: 3px 0; }
.wx-hb__track { height: 16px; background: var(--ds-color-surface-panel-deep); }
.wx-hb__track i { display: block; height: 100%; background: var(--c); transform: scaleX(var(--w)); transform-origin: 0 50%; border-right: var(--ds-outline-thin) solid var(--ds-color-outline-ink); transition: transform var(--ds-motion-bar-fill) var(--ds-ease-enter); transition-delay: calc(var(--i) * var(--ds-motion-stagger-tile)); }
.wx-chart.is-wait .wx-hb__track i { transform: scaleX(0); }
.wx-hb__val { font-family: var(--ds-font-display); font-weight: 400; font-size: var(--ds-type-small); }
/* share band */
.wx-band__bar { display: flex; height: 28px; border: var(--ds-outline-bold) solid var(--ds-color-outline-ink); box-shadow: var(--ds-shadow-hard); overflow: hidden; }
.wx-band__bar span { flex: 0 0 calc(var(--w) * 100%); background: var(--c); transform-origin: 0 50%; transition: transform var(--ds-motion-bar-fill) var(--ds-ease-enter); transition-delay: calc(var(--i) * var(--ds-motion-stagger-tile)); }
.wx-band__bar span + span { border-left: var(--ds-outline-thin) solid var(--ds-color-outline-ink); }
.wx-chart.is-wait .wx-band__bar span { transform: scaleX(0); }
/* ==== WEBX3 WN20: compare charts. Every chart has its final size before its data; motion = transform, opacity and
   stroke-dashoffset only, once (is-wait → is-in); prefers-reduced-motion: end state. Player colours: --cmp-a / --cmp-b. */
[data-tip].wx-ring, .wx-radar__hl[data-tip], .wx-tug[data-tip], .wx-form__col[data-tip], .wx-form__lbl[data-tip], .wx-modes__seg[data-tip] { cursor: help; }
.wx-chart [data-tip]:focus-visible { outline: 3px solid var(--ds-color-accent-primary); outline-offset: 2px; }
/* rings: A outside, B inside; the one orchestrated moment of the view (they run full once) */
.wx-rings { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--ds-space-m); }
.wx-rings .wx-legend--duel { grid-column: 1 / -1; margin-top: 0; }
.wx-ring { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); grid-template-rows: auto auto auto; justify-items: center; row-gap: var(--ds-space-xxs); column-gap: var(--ds-space-xs); min-width: 0; padding: var(--ds-space-xs) 0; }
.wx-ring svg { grid-column: 1 / -1; width: 120px; aspect-ratio: 1; height: auto; display: block; transform: rotate(-90deg); }
.wx-ring__track { fill: none; stroke: var(--ds-color-surface-row); stroke-width: 10; }
.wx-ring__arc { fill: none; stroke-width: 10; stroke-dasharray: 100 100; stroke-dashoffset: var(--off); transition: stroke-dashoffset calc(var(--ds-motion-bar-fill) * 2) var(--ds-ease-enter); transition-delay: calc(var(--i, 0) * var(--ds-motion-stagger-card)); }
.wx-ring__arc--a { stroke: var(--cmp-a); } .wx-ring__arc--b { stroke: var(--cmp-b); }
.wx-chart.is-wait .wx-ring__arc { stroke-dashoffset: 100; }
.wx-ring__va, .wx-ring__vb { font-family: var(--ds-font-display); font-weight: 400; font-size: var(--ds-type-small); line-height: 1.15; font-variant-numeric: tabular-nums; white-space: nowrap; }
.wx-ring__va { color: var(--cmp-a); justify-self: end; } .wx-ring__vb { color: var(--cmp-b); justify-self: start; }
.wx-ring__label { grid-column: 1 / -1; font-size: var(--ds-type-small); line-height: 1.3; color: var(--ds-color-text-muted); text-align: center; overflow-wrap: normal; text-wrap: balance; }
/* radar with HTML axis labels (they wrap inside the box; each is a tooltip trigger) */
.wx-radar__box { position: relative; width: 100%; max-width: 380px; margin: 0 auto; aspect-ratio: 320 / 290; }
.wx-radar--html svg { width: 100%; height: 100%; max-width: none; }
.wx-radar__hl { position: absolute; display: block; width: max-content; font-size: var(--ds-type-small); line-height: 1.3; color: var(--ds-color-text-muted); text-wrap: balance; overflow-wrap: normal; }
.wx-radar__hl[data-side="end"] { text-align: right; transform: translateX(-100%); }
.wx-radar__hl[data-side="middle"] { text-align: center; transform: translateX(-50%); }
.wx-radar__hl[data-vert="top"][data-side="middle"] { transform: translate(-50%, -100%); }
.wx-radar__hl[data-vert="mid"][data-side="end"] { transform: translate(-100%, -50%); } .wx-radar__hl[data-vert="mid"][data-side="start"] { transform: translateY(-50%); }
.wx-radar__hl:hover, .wx-radar__hl:focus-visible { color: var(--ds-color-text-primary); }
/* tug of war (direct duels) */
.wx-tug { display: grid; gap: var(--ds-space-xxs); padding: var(--ds-space-xs) 0; }
.wx-tug + .wx-tug { margin-top: var(--ds-space-s); }
.wx-tug__label { font-size: var(--ds-type-small); line-height: 1.3; color: var(--ds-color-text-muted); }
.wx-tug__names, .wx-tug__vals { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: var(--ds-space-m); }
.wx-tug__na { color: var(--cmp-a); } .wx-tug__nb { color: var(--cmp-b); text-align: right; }
.wx-tug__bar { position: relative; display: flex; height: 20px; background: var(--ds-color-surface-row); border: var(--ds-outline-bold) solid var(--ds-color-outline-ink); box-shadow: var(--ds-shadow-hard); overflow: hidden; }
.wx-tug__a, .wx-tug__b { display: block; height: 100%; transition: transform var(--ds-motion-bar-fill) var(--ds-ease-enter); }
.wx-tug__a { flex: 0 0 calc(var(--s) * 100%); background: var(--cmp-a); transform-origin: 0 50%; }
.wx-tug__b { flex: 1 1 0; background: var(--cmp-b); transform-origin: 100% 50%; border-left: var(--ds-outline-thin) solid var(--ds-color-outline-ink); }
.wx-chart.is-wait .wx-tug__a, .wx-chart.is-wait .wx-tug__b { transform: scaleX(0); }
.wx-tug__va, .wx-tug__vb, .wx-tug__zero { font-family: var(--ds-font-display); font-weight: 400; font-size: var(--ds-type-label); line-height: 1.15; font-variant-numeric: tabular-nums; }
.wx-tug__va { color: var(--cmp-a); } .wx-tug__vb { color: var(--cmp-b); text-align: right; } .wx-tug__zero { grid-column: 1 / -1; text-align: center; color: var(--ds-color-text-muted); }
/* form: switcher + plot; three pre-rendered groups cross-fade; Ø lines dashed with their label at the right end */
.wx-form { display: flex; flex-direction: column; gap: var(--ds-space-xs); height: 100%; }
.wx-form__tabs { display: flex; gap: var(--ds-space-xs); flex: none; }
.wx-form__tab { height: 32px; padding: 0 var(--ds-space-s); font: inherit; font-size: var(--ds-type-small); color: var(--ds-color-text-primary); background: var(--ds-color-surface-row); border: var(--ds-outline-thin) solid var(--ds-color-outline-ink); cursor: pointer; }
.wx-form__tab[aria-pressed="true"] { background: var(--ds-color-accent-primary); color: var(--ds-color-text-on-primary); }
.wx-form__plot { position: relative; flex: 1 1 auto; min-height: 160px; margin-right: 5.5em; border-left: var(--ds-outline-thin) solid var(--ds-color-outline-soft); border-bottom: var(--ds-outline-thin) solid var(--ds-color-outline-soft); }
.wx-form__g { position: absolute; inset: 0; opacity: 0; pointer-events: none; transition: opacity var(--ds-motion-panel-out) var(--ds-ease-exit); }
.wx-form__g.is-on { opacity: 1; pointer-events: auto; transition: opacity var(--ds-motion-panel-in) var(--ds-ease-enter); }
.wx-form__g svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; }
/* the plot is stretched (preserveAspectRatio none) with a non-scaling stroke: a dash draw-in would cut the line, so it fades in */
.wx-form__line { fill: none; stroke-width: 3; vector-effect: non-scaling-stroke; stroke-linejoin: round; transition: opacity calc(var(--ds-motion-bar-fill) * 2) var(--ds-ease-smooth); }
.wx-form__line--a { stroke: var(--cmp-a); } .wx-form__line--b { stroke: var(--cmp-b); }
.wx-chart.is-wait .wx-form__line { opacity: 0; }
.wx-form__avg { stroke-width: 2; stroke-dasharray: 6 5; vector-effect: non-scaling-stroke; }
.wx-form__avg--a { stroke: var(--cmp-a); } .wx-form__avg--b { stroke: var(--cmp-b); }
.wx-form__pt { position: absolute; width: 10px; height: 10px; margin: -5px 0 0 -5px; border: var(--ds-outline-thin) solid var(--ds-color-outline-ink); pointer-events: none; transition: opacity var(--ds-motion-panel-in) var(--ds-ease-enter); transition-delay: calc(var(--ds-motion-bar-fill) + var(--i, 0) * var(--ds-motion-stagger-tile)); }
.wx-form__pt--a { background: var(--cmp-a); } .wx-form__pt--b { background: var(--cmp-b); border-radius: 50%; }
.wx-chart.is-wait .wx-form__pt { opacity: 0; }
.wx-form__lbl { position: absolute; left: 100%; margin-left: var(--ds-space-xxs); transform: translateY(-50%); font-family: var(--ds-font-display); font-size: var(--ds-type-small); line-height: 1.3; white-space: nowrap; font-variant-numeric: tabular-nums; }
.wx-form__lbl--a { color: var(--cmp-a); } .wx-form__lbl--b { color: var(--cmp-b); }
.wx-form__col { position: absolute; top: 0; bottom: 0; z-index: 1; }
.wx-form__col:hover, .wx-form__col:focus-visible { background: color-mix(in srgb, var(--ds-color-text-primary) 8%, transparent); }
.wx-form__g.is-on .wx-form__lbl { z-index: 2; }
/* modes: two 100 % bands (A over B, the player colour as the leading edge) and a 6-slot legend */
.wx-modes__band { display: flex; height: 28px; box-sizing: border-box; background: var(--ds-color-surface-row); border: var(--ds-outline-bold) solid var(--ds-color-outline-ink); border-left-width: 10px; overflow: hidden; }
.wx-modes__band--a { border-left-color: var(--cmp-a); } .wx-modes__band--b { border-left-color: var(--cmp-b); border-top: 0; }
.wx-modes__seg { flex: 0 0 calc(var(--w) * 100%); background: var(--c); transform-origin: 0 50%; transition: transform var(--ds-motion-bar-fill) var(--ds-ease-enter); transition-delay: calc(var(--i) * var(--ds-motion-stagger-tile)); }
.wx-modes__seg + .wx-modes__seg { border-left: var(--ds-outline-thin) solid var(--ds-color-outline-ink); }
.wx-chart.is-wait .wx-modes__seg { transform: scaleX(0); }
.wx-modes__legend { --cmp-legend-row: calc(var(--ds-type-small) * 1.3 * 2 + 4px); display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); grid-auto-flow: column; grid-template-rows: repeat(3, var(--cmp-legend-row)); gap: 4px var(--ds-space-m); margin: 8px 0 0; padding: 0; list-style: none; }
.wx-modes__li { display: grid; grid-template-columns: 12px minmax(0, 1fr) auto auto; column-gap: var(--ds-space-xs); align-items: center; min-width: 0; font-size: var(--ds-type-small); line-height: 1.3; }
.wx-modes__li.is-empty { visibility: hidden; }
.wx-modes__sw { width: 12px; height: 12px; background: var(--c); border: var(--ds-outline-thin) solid var(--ds-color-outline-ink); }
.wx-modes__name { min-width: 0; overflow-wrap: normal; text-wrap: balance; color: var(--ds-color-text-muted); }
.wx-modes__va, .wx-modes__vb { font-family: var(--ds-font-display); font-weight: 400; font-variant-numeric: tabular-nums; white-space: nowrap; }
.wx-modes__va { color: var(--cmp-a); } .wx-modes__vb { color: var(--cmp-b); }
@media (max-width: 720px) {
  .wx-ring svg { width: 96px; }
  .wx-modes__legend { grid-template-columns: minmax(0, 1fr); grid-template-rows: repeat(6, var(--cmp-legend-row)); }
}
@media (prefers-reduced-motion: reduce) {
  .wx-ring__arc, .wx-tug__a, .wx-tug__b, .wx-form__line, .wx-form__pt, .wx-form__g, .wx-modes__seg, .wx-bf__bars { transition: none !important; }
}

/* ==== website/assets/style.css ==== */
/* BAPBAP Genesis community website: page layout (WEBX2 DESIGN Â§12). Only --ds-* tokens (tokens.css), components from
   ds.css, the character page from wx-charstage.css, the lobby background from wx-lobbybg.css (shared kit). Bundled into
   app.css (tools/webx/build-css.mjs). Order of the page: hero â†’ roster â†’ modes â†’ download/Discord â†’ Nexus â†’ FAQ â†’ footer.
   Motion: transform and opacity only; the one orchestrated moment is the hero (app.js heroIntro). */

/* ---------- base ---------- */
html { scroll-behavior: smooth; scroll-padding-top: calc(var(--top-h, var(--ds-space-top-bar-height)) + var(--ds-space-m)); }
* { box-sizing: border-box; }
body { margin: 0; min-height: 100vh; line-height: 1.5; -webkit-font-smoothing: antialiased;
  background: var(--ds-color-bg-screen) url("img/ds/lobby-bg-scroll.webp") center top / 1600px auto repeat; }
img { display: block; max-width: 100%; height: auto; }
video { display: block; }
a { color: var(--ds-color-text-primary); }
a:hover { color: var(--ds-color-accent-primary); }
h1, h2, h3, h4 { margin: 0; font-family: var(--ds-font-display); font-weight: 400; line-height: 1.12; text-wrap: balance; overflow-wrap: break-word; hyphens: auto; }
/* long words of the longest languages (de, ru, bg) break instead of pushing the page wider */
summary, .steps__list b, .ds-btn span, .livebar dt, .nexus__feats span { overflow-wrap: break-word; hyphens: auto; }
p { margin: 0; }
button { font: inherit; color: inherit; }
[hidden] { display: none !important; }
.anchor-alias { position: absolute; top: 0; }
/* texts below the first screen wait for their language (max 400 ms, boot script) */
.wx-l10n-pending .wx-below [data-t] { visibility: hidden; }
.skip { position: absolute; left: var(--ds-space-m); top: var(--ds-space-m); z-index: 60; transform: translateY(-200%); }
.skip:focus { transform: none; }

/* WS07: the lobby background behind the page (wx-lobbybg variant "page"); without the kit the body pattern above stays.
   It is the one layer that stays when the browser moves between this page and /stats/ (DESIGN Â§5.1, DR2-15). */
.pagebg { position: fixed; inset: 0; z-index: -1; pointer-events: none; }
/* only the page layer carries the view-transition name of the kit (two equal names would cancel the transition) */
.wx-lobbybg--hero { view-transition-name: none; }
/* WN02 (owner 28.10.): the smoke only at the top of the page (the hero splash), not a second time behind the page. Below the
   hero the page now looks like the menu pages of the client lobby (LobbyBg_Menus, GenesisSplashLobby.cs MenusBackground):
   the dark indigo panel fill (SurfacePanel) with its dot pattern and the dim Kitsu silhouette at 22 % text.primary; the
   sparkles keep drifting over it. */
#pagebg .wx-lobbybg__bg, #pagebg .wx-lobbybg__smoke, #pagebg .wx-lobbybg__scrim { display: none; }
#pagebg .wx-lobbybg { --ds-dot: color-mix(in srgb, var(--ds-color-text-primary) 7%, transparent); background-color: var(--ds-color-surface-panel);
  background-image: radial-gradient(circle, var(--ds-dot) calc(var(--ds-space-dot-grid-dot) / 2), transparent calc(var(--ds-space-dot-grid-dot) / 2 + 0.5px));
  background-size: var(--ds-space-dot-grid-step) var(--ds-space-dot-grid-step); }
/* the client draws the silhouette at 22 %; here the page text lies on top of it, so it is dimmer (14 %) to keep small text legible */
#pagebg .wx-lobbybg::before { content: ""; position: absolute; inset: 0; background: color-mix(in srgb, var(--ds-color-text-primary) 14%, transparent);
  -webkit-mask: url("img/game/lobby/splash-kitsu.1600.webp") 100% 100% / auto 92% no-repeat; mask: url("img/game/lobby/splash-kitsu.1600.webp") 100% 100% / auto 92% no-repeat; }
@media (max-width: 1279px) { #pagebg .wx-lobbybg::before { -webkit-mask-image: url("img/game/lobby/splash-kitsu.960.webp"); mask-image: url("img/game/lobby/splash-kitsu.960.webp"); } }
@media (max-width: 767px) { #pagebg .wx-lobbybg::before { -webkit-mask-size: auto 60%; mask-size: auto 60%; } }

/* ---------- header: fixed, transparent over the hero, navy plate after 80 px (app.js .is-solid) ---------- */
.top { position: fixed; top: 0; left: 0; right: 0; z-index: 40; display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: var(--ds-space-l);
  padding: var(--ds-space-s) var(--ds-space-screen-margin-x); }
/* the plate is a layer of its own, so only its opacity moves */
.top::before { content: ""; position: absolute; inset: 0; z-index: -1; background: var(--ds-palette-navy); box-shadow: var(--ds-shadow-hard); opacity: 0; transition: opacity var(--ds-motion-select) var(--ds-ease-smooth); }
.top.is-solid::before { opacity: 1; }
.brand { display: inline-flex; align-items: center; gap: var(--ds-space-xs); text-decoration: none; }
.brand__logo { font-family: var(--ds-font-display); font-size: var(--ds-type-title-s); line-height: 1.12; color: var(--ds-color-text-primary); text-shadow: 0 var(--ds-outline-thin) 0 var(--ds-color-outline-ink); }
.brand:hover .brand__logo { color: var(--ds-color-accent-primary); }
.menu { justify-self: center; }
.menu a { font-size: var(--ds-type-nav); text-shadow: 0 var(--ds-outline-thin) 0 var(--ds-color-outline-ink); }
.actions { display: flex; align-items: center; gap: var(--ds-space-s); }
/* R-C-03: another page language than the HTML (class wx-l10n-wait, set in <head>, removed by app.js once the texts are
   applied): the English nav, actions and hero text wait for their translation, at most until the input lock. Otherwise the
   labels change width and lines when the translation arrives and move the centred nav and the bottom-aligned hero */
.wx-l10n-wait .top .menu, .wx-l10n-wait .top .actions, .wx-l10n-wait .hero__text { opacity: 0; animation: wx-failopen-text var(--ds-motion-instant) linear var(--ds-motion-wipe-input-lock) forwards; }
@keyframes wx-failopen-text { to { opacity: 1; } }
/* R-C-03: one row (from 1440 px) centres the nav between logo and actions: the language button (mounted by the script)
   gets its place up front, the widest endonym button is 139 px (nl-NL) */
@media (min-width: 1440px) { .lang { display: flex; justify-content: flex-end; min-inline-size: 140px; } }
.burger { display: none; width: var(--ds-space-icon-button); height: var(--ds-space-icon-button); padding: var(--ds-space-s) var(--ds-space-xs); border: 0; background: var(--ds-color-surface-panel-deep); cursor: pointer; flex-direction: column; justify-content: space-between; }
.burger i { display: block; height: var(--ds-outline-bold); background: var(--ds-color-text-primary); }
/* two rows up to 1439 px: at 1280 px the tabs of es/fr/nl/pt do not fit next to logo and actions */
@media (max-width: 1439px) {
  .top { grid-template-columns: auto minmax(0, 1fr); row-gap: var(--ds-space-xs); padding-bottom: 0; }
  .actions { justify-self: end; }
  .menu { grid-column: 1 / -1; grid-row: 2; justify-self: stretch; overflow-x: auto; scrollbar-width: none; padding: var(--ds-space-xs) calc(var(--ds-underline-extend) / 2) var(--ds-space-m); }
  .menu::-webkit-scrollbar { display: none; }
}
@media (max-width: 767px) {
  .top { grid-template-columns: auto minmax(0, 1fr) auto; column-gap: var(--ds-space-s); padding: var(--ds-space-xs) var(--ds-space-m); }
  .brand__logo { font-size: var(--ds-type-label); }
  .stats-link, .actions .ds-chip--social { display: none; }
  .actions { min-width: 0; }
  .burger { display: flex; }
  .menu { display: none; grid-row: 2; flex-direction: column; align-items: flex-start; gap: 0; padding: 0 0 var(--ds-space-m); }
  .menu.open { display: flex; }
  .menu a { padding: var(--ds-space-s) 0; }
  .menu .ds-nav__bar { display: none; }
}
.wx-lang__list { animation: ds-panel-in var(--ds-motion-panel-in) var(--ds-ease-enter) both; }
@media (max-width: 479px) { .wx-lang__btn > span { display: none; } }

/* ---------- page grid ---------- */
main { overflow-x: clip; }
main > section { position: relative; max-width: 1600px; margin: 0 auto; padding: var(--ds-space-xxxl) var(--ds-space-screen-margin-x); }
.sec-title { font-size: var(--ds-type-headline); text-transform: uppercase; color: var(--ds-color-text-primary); text-shadow: 0 var(--ds-outline-bold) 0 var(--ds-color-outline-ink); }
.sec-lead { margin-top: var(--ds-space-xs); font-size: var(--ds-type-body-l); color: var(--ds-color-text-muted); max-width: 64ch; }
.sub-title { margin: 0 0 var(--ds-space-m); font-family: var(--ds-font-display); font-size: var(--ds-type-title-s); }
@media (max-width: 767px) {
  main > section { padding: var(--ds-space-xxl) var(--ds-space-m); }
  .sec-title { font-size: calc(var(--ds-type-headline) * 0.6); }
  .sub-title { font-size: var(--ds-type-label); }
}

/* ---------- hero: the PLAY page of the lobby (wx-lobbybg variant "hero"), ink scrim on the left, text on it ---------- */
main > section.hero { max-width: none; padding: 0; display: grid; align-items: end; min-height: clamp(640px, 100svh, 1080px); overflow: hidden; isolation: isolate;
  border-bottom: var(--ds-outline-bold) solid var(--ds-color-outline-ink); }
/* static fallback (DESIGN Â§6.5) until the lobby textures are there: the storm pink of the splash with the lobby pattern */
.hero__bg { position: absolute; inset: 0; z-index: 0; background-color: var(--ds-palette-storm-pink); --ds-dot: color-mix(in srgb, var(--ds-color-outline-ink) 18%, transparent);
  background-image: radial-gradient(circle, var(--ds-dot) calc(var(--ds-space-dot-grid-dot) / 2), transparent calc(var(--ds-space-dot-grid-dot) / 2 + 0.5px)); background-size: var(--ds-space-dot-grid-step) var(--ds-space-dot-grid-step); }
.has-lobbybg .hero__bg { background: none; }
.hero::before { content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(90deg, var(--ds-color-bg-lobby-scrim) 0%, var(--ds-color-bg-lobby-scrim) 22%, color-mix(in srgb, var(--ds-color-bg-lobby-scrim), transparent 100%) 55%),
              linear-gradient(180deg, color-mix(in srgb, var(--ds-color-bg-lobby-scrim), transparent 30%) 0%, color-mix(in srgb, var(--ds-color-bg-lobby-scrim), transparent 100%) 22%); }
/* the wipe of the entrance: an ink plate that runs out to the right and frees the splash */
.hero__wipe { position: absolute; inset: 0; z-index: 1; background: var(--ds-color-outline-ink); transform: translateX(110%); pointer-events: none; }
/* the star edge of the client's StarWipe (G13, TransitionEdge_Star.png) on the trailing side, like .wx-wipe of the kit */
.hero__wipe::before, .dplate__wipe::after { content: ""; position: absolute; top: 0; bottom: 0; width: 28px; background: inherit;
  -webkit-mask: url("img/game/ui/transition-edge-star.webp") 0 0 / 28px 64px repeat-y; mask: url("img/game/ui/transition-edge-star.webp") 0 0 / 28px 64px repeat-y; }
.hero__wipe::before { right: 100%; transform: scaleX(-1); }
.dplate__wipe::after { left: 100%; }
/* R-C-03: the top padding is static (not the measured --top-h of app.js), so the bottom-aligned text box does not move when
   the script measures the header; it only keeps the text clear of the fixed header */
.hero__text { position: relative; z-index: 2; display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--ds-space-m); justify-items: start; align-content: end; max-width: min(820px, 100%); min-width: 0;
  padding: calc(var(--ds-space-top-bar-height) + var(--ds-space-xl)) var(--ds-space-screen-margin-x) var(--ds-space-xxxl); }
.hero__title { font-size: var(--ds-type-mega); line-height: 0.95; text-transform: uppercase; color: var(--ds-color-text-primary); text-shadow: 0 var(--ds-outline-bold) 0 var(--ds-color-outline-ink); }
.hero__w { display: inline-block; }
.hero__sub { font-size: var(--ds-type-body-l); max-width: 44ch; text-shadow: 0 var(--ds-outline-thin) 0 var(--ds-color-outline-ink); }
.hero__online { display: inline-flex; align-items: center; gap: var(--ds-space-xs); min-block-size: 1lh; font-size: var(--ds-type-body); font-variant-numeric: tabular-nums; }
/* DR2-20/R-C-03: the hero text sits at the bottom of the hero; the live line keeps its place until /v1/status answered
   (a class, not [hidden]: the global [hidden] rule would take the line out of the layout) */
.hero__online.is-empty { visibility: hidden; }
.hero__cta { display: flex; flex-wrap: wrap; gap: var(--ds-space-s); margin-top: var(--ds-space-xs); }
.hero__more a { font-family: var(--ds-font-display); font-size: var(--ds-type-small); text-transform: uppercase; }
/* before the entrance (class set in <head>, removed by app.js): the wipe covers only the splash, fail-open after the input
   lock. R-C-02: title and actions lie above the wipe and are readable and usable from the first paint (DESIGN §12.2) */
.wx-intro .hero__wipe { transform: none; animation: wx-failopen-wipe var(--ds-motion-instant) linear var(--ds-motion-wipe-input-lock) forwards; }
@keyframes wx-failopen-wipe { to { transform: translateX(110%); } }
@media (max-width: 767px) {
  main > section.hero { align-items: start; min-height: clamp(640px, 100svh, 900px); }
  .hero::before { background: linear-gradient(180deg, var(--ds-color-bg-lobby-scrim) 0%, var(--ds-color-bg-lobby-scrim) 30%, color-mix(in srgb, var(--ds-color-bg-lobby-scrim), transparent 100%) 62%); }
  /* the phone header is one row: icon button + its padding (static like above, R-C-03) */
  .hero__text { align-content: start; padding: calc(var(--ds-space-icon-button) + 2 * var(--ds-space-xs) + var(--ds-space-l)) var(--ds-space-m) var(--ds-space-xxl); }
  .hero__title { font-size: min(calc(var(--ds-type-mega) * 0.5), 10.5vw); }
  .hero__cta { width: 100%; }
  .hero__cta .ds-btn { flex: 1 1 100%; white-space: normal; padding: var(--ds-space-xs) var(--ds-space-m); }
}

/* ---------- roster (the stage itself: wx-charstage.css) ---------- */
.roster__head { display: grid; grid-template-columns: 1fr auto; align-items: end; gap: var(--ds-space-s) var(--ds-space-l); margin-bottom: var(--ds-space-l); }
.roster__head .sec-lead { grid-column: 1; }
.roster__filter { grid-column: 2; grid-row: 1 / span 2; align-self: end; }
.roster__stage { min-height: 560px; }
.roster__stage .wx-stage { margin-left: calc(var(--ds-space-screen-margin-x) * -1); margin-right: calc(var(--ds-space-screen-margin-x) * -1); }
.roster__stage .wx-stage__art { --wx-art-w: 1.25; }
.roster__stage .wx-stage__bg { background: var(--ds-palette-navy); }
.wx-pre .wx-stage__bg::before, .wx-entering .wx-stage__bg::before { visibility: hidden; }
.wx-pre .wx-stage__accent--a { transform: scaleX(0); transform-origin: 0 50%; }
.wx-pre .wx-stage__bgname, .wx-pre .wx-stage__id > *, .wx-pre .wx-stage__abilities, .wx-pre .wx-bar__c { opacity: 0; }
@media (max-width: 767px) {
  .roster__stage .wx-stage { margin-left: calc(var(--ds-space-m) * -1); margin-right: calc(var(--ds-space-m) * -1); }
  .roster__stage .wx-stage__art { left: 40%; right: -20%; top: calc(-1 * var(--ds-space-xl)); bottom: 44%; --wx-art-w: 1; }
  .roster__stage .wx-stage__abilities { margin-top: calc(var(--ds-space-xxxl) * 1.5); }
  .roster__stage .wx-abil__name { font-size: var(--ds-type-label); }
  .roster__head { grid-template-columns: 1fr; }
  .roster__filter { grid-column: 1; grid-row: auto; }
  .roster__filter button { font-size: var(--ds-type-body); }
}

/* ---------- modes: sheared card band of the client mode picker, the chosen card is wider and plays its loop ---------- */
/* two rows of three; the chosen card takes more of its row at once (no layout animation), only scale and edge move */
.modes__band { display: flex; flex-wrap: wrap; gap: var(--ds-space-l) var(--ds-space-xl); margin-top: var(--ds-space-l); padding: 0 var(--ds-space-s); }
.mcard { --fam: var(--ds-color-surface-panel-deep); position: relative; display: block; flex: 1 1 calc(33.333% - var(--ds-space-xl)); min-width: 0; height: clamp(200px, 16vw, 300px); padding: 0;
  border: var(--ds-outline-bold) solid var(--ds-color-outline-ink); background: var(--ds-color-surface-panel-deep); cursor: pointer; text-align: left; overflow: hidden;
  transform: skewX(var(--ds-skew-card)); box-shadow: var(--ds-shadow-hard); transition: transform var(--ds-motion-press-up) var(--ds-ease-smooth); }
.mcard[aria-selected="true"] { flex-grow: 1.7; transform: skewX(var(--ds-skew-card)) scale(var(--ds-motion-hover-scale-card)); box-shadow: 0 0 0 var(--ds-outline-extra) var(--ds-color-accent-primary), var(--ds-shadow-hard); }
.mcard:hover { transform: skewX(var(--ds-skew-card)) scale(var(--ds-motion-hover-scale-card)); transition-duration: var(--ds-motion-hover); }
.mcard:active { transform: skewX(var(--ds-skew-card)) translateY(var(--ds-motion-press-y)); transition-duration: var(--ds-motion-press-down); }
/* family colours of the client picker (GenesisModeSelectV3.AccentFor) */
.mcard[data-mode="br"] { --fam: var(--ds-color-accent-primary); }
.mcard[data-mode="arena"] { --fam: var(--ds-color-accent-hot); }
.mcard[data-mode="bossrush"] { --fam: var(--ds-color-team-red); }
.mcard[data-mode="rogue"] { --fam: var(--ds-palette-gold); }
.mcard[data-mode="custom"] { --fam: var(--ds-color-accent-secondary); }
.mcard[data-mode="mapmaker"] { --fam: var(--ds-color-accent-info); }
.mcard__media { position: absolute; inset: 0; background: var(--fam); }
.mcard__vid { width: 112%; max-width: none; height: 100%; margin-left: -6%; object-fit: cover; transform: skewX(calc(var(--ds-skew-card) * -1)); }
/* placeholder poster until the loop is there (DESIGN Â§12.4, DR2-04): the family colour with the dot grid of the game */
.mcard--ph .mcard__media { --ds-dot: color-mix(in srgb, var(--ds-color-outline-ink) 22%, transparent);
  background-image: radial-gradient(circle, var(--ds-dot) calc(var(--ds-space-dot-grid-dot) / 2), transparent calc(var(--ds-space-dot-grid-dot) / 2 + 0.5px)); background-size: var(--ds-space-dot-grid-step) var(--ds-space-dot-grid-step); }
.mcard--ph .mcard__vid { visibility: hidden; }
.mcard--ph[aria-selected="true"] .mcard__title { color: var(--ds-color-text-primary); }
.mcard::after { content: ""; position: absolute; inset: 0; background: linear-gradient(0deg, var(--ds-color-bg-scrim) 0%, color-mix(in srgb, var(--ds-color-bg-scrim), transparent 100%) 55%); }
.mcard__text { position: absolute; z-index: 1; left: var(--ds-space-m); right: var(--ds-space-m); bottom: var(--ds-space-s); transform: skewX(calc(var(--ds-skew-card) * -1)); }
.mcard__title { display: block; font-family: var(--ds-font-display); font-size: var(--ds-type-title-s); line-height: 1.12; text-transform: uppercase; color: var(--ds-color-text-primary); text-shadow: 0 var(--ds-outline-thin) 0 var(--ds-color-outline-ink); overflow-wrap: break-word; hyphens: auto; }
.mcard[aria-selected="true"] .mcard__title { font-size: var(--ds-type-title); color: var(--ds-color-accent-primary); }
.modes__panel { display: grid; justify-items: start; gap: var(--ds-space-m); margin-top: var(--ds-space-xl); padding-left: var(--ds-space-m); border-left: var(--ds-outline-extra) solid var(--ds-color-accent-primary); max-width: 900px; }
.modes__panel:focus-visible { outline-offset: var(--ds-space-xs); }
.modes__desc { font-size: var(--ds-type-body-l); max-width: 64ch; }
.modes__subs { display: flex; flex-wrap: wrap; gap: var(--ds-space-xs); margin: 0; padding: 0; list-style: none; }
.modes__subs:empty { display: none; }
.modes__subs .ds-chip { min-height: 0; padding: var(--ds-space-xxs) var(--ds-space-s); border: var(--ds-outline-bold) solid var(--ds-color-outline-ink); border-radius: 0; background: var(--ds-color-surface-panel-deep); box-shadow: var(--ds-shadow-hard); transform: skewX(var(--ds-skew-chip)); font-family: var(--ds-font-display); font-size: var(--ds-type-small); text-transform: uppercase; }
.modes__subs .ds-chip > span { display: inline-block; transform: skewX(calc(-1 * var(--ds-skew-chip))); }
.modes__panel.is-swap > * { animation: ds-panel-in var(--ds-motion-panel-in) var(--ds-ease-enter) both; }
@media (max-width: 1279px) { .mcard[aria-selected="true"] .mcard__title { font-size: var(--ds-type-title-s); } }
@media (max-width: 767px) {
  .modes__band { flex-wrap: nowrap; overflow-x: auto; scroll-snap-type: x mandatory; gap: var(--ds-space-l); padding: var(--ds-space-s) var(--ds-space-l) var(--ds-space-m); margin: var(--ds-space-m) calc(var(--ds-space-m) * -1) 0; scrollbar-width: none; }
  .modes__band::-webkit-scrollbar { display: none; }
  .mcard, .mcard[aria-selected="true"] { flex: 0 0 78%; height: auto; aspect-ratio: 16 / 10; scroll-snap-align: center; container-type: inline-size; }
  /* WS02: the longest family name of the 12 languages ("Пользовательская", "personnalisé") fits the card as a whole word */
  .mcard__title, .mcard[aria-selected="true"] .mcard__title { font-size: min(var(--ds-type-title-s), 6.4cqi); }
}

/* ---------- download: the Discord plate, three steps, the live bar ---------- */
.download__grid { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: var(--ds-space-xxl); margin-top: var(--ds-space-l); align-items: start; }
.dplate { position: relative; display: grid; justify-items: start; gap: var(--ds-space-l); padding: var(--ds-space-xl); overflow: hidden; background: var(--ds-color-accent-secondary);
  border: var(--ds-outline-bold) solid var(--ds-color-outline-ink); box-shadow: var(--ds-shadow-hard); }
/* WN01: "Join Discord" and the Nexus download side by side, same height */
.dplate__cta { display: flex; align-items: stretch; gap: var(--ds-space-s); }
.dplate__cta .ds-btn { flex: 1 1 0; min-width: 0; white-space: normal; text-align: center; padding-left: var(--ds-space-m); padding-right: var(--ds-space-m); }
@media (max-width: 767px) { .dplate__cta { flex-direction: column; } .dplate__cta .ds-btn { flex: 1 1 auto; } }
.dplate.has-wipe { background: transparent; }
.dplate__wipe { position: absolute; inset: 0; z-index: 0; background: var(--ds-color-accent-secondary); }
.dplate > :not(.dplate__wipe) { position: relative; z-index: 1; }
.dplate.is-pre .dplate__wipe { transform: translateX(-101%); }
.dplate.is-pre > :not(.dplate__wipe) { opacity: 0; }
.dplate__text { font-family: var(--ds-font-display); font-size: var(--ds-type-title-s); line-height: 1.2; text-transform: uppercase; max-width: 22ch; text-shadow: 0 var(--ds-outline-thin) 0 var(--ds-color-outline-ink); }
.dplate__build { display: flex; flex-wrap: wrap; gap: var(--ds-space-xs) var(--ds-space-xl); margin: 0; }
.dplate__build div { display: flex; flex-direction: column-reverse; }
.dplate__build dt { font-size: var(--ds-type-small); }
.dplate__build dd { margin: 0; font-family: var(--ds-font-display); font-size: var(--ds-type-label); font-variant-numeric: tabular-nums; }
.dplate__alt { display: flex; flex-wrap: wrap; gap: var(--ds-space-l); font-family: var(--ds-font-display); }
.dplate__alt a { color: var(--ds-color-text-primary); }
.steps__list { counter-reset: s; display: grid; gap: var(--ds-space-l); margin: 0; padding: 0; list-style: none; }
.steps__list li { counter-increment: s; display: grid; grid-template-columns: 72px minmax(0, 1fr); align-content: center; column-gap: var(--ds-space-m); min-height: 64px; }
.steps__list li::before { content: counter(s); grid-row: 1 / span 2; display: grid; place-items: center; width: 64px; height: 64px; font-family: var(--ds-font-display); font-size: var(--ds-type-title); color: var(--ds-color-text-on-primary); background: var(--ds-color-accent-primary); border: var(--ds-outline-bold) solid var(--ds-color-outline-ink); box-shadow: var(--ds-shadow-hard); transform: skewX(var(--ds-skew-card)); }
.steps__list b { align-self: center; font-family: var(--ds-font-display); font-weight: 400; font-size: var(--ds-type-label); line-height: 1.2; }
.steps__list span { grid-column: 2; color: var(--ds-color-text-muted); font-size: var(--ds-type-body); }
/* WN16: step 3 carries the asterisk of the note under the list ("*Only available to playtesters") */
.steps__star b::after, .steps__note::before { content: "*"; color: var(--ds-color-accent-primary); font-family: var(--ds-font-display); }
.steps__star b::after { margin-left: var(--ds-space-xxs); }
.steps__note { margin-top: var(--ds-space-l); font-size: var(--ds-type-body); color: var(--ds-color-text-muted); }
.steps__note::before { margin-right: var(--ds-space-xxs); }
.steps__req { margin-top: var(--ds-space-xl); font-size: var(--ds-type-small); color: var(--ds-color-text-muted); max-width: 72ch; }
.steps__req b { font-family: var(--ds-font-display); font-weight: 400; color: var(--ds-color-text-primary); margin-right: var(--ds-space-xs); }
.livebar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--ds-space-m) var(--ds-space-xxl); margin-top: var(--ds-space-xxl); padding: var(--ds-space-m) var(--ds-space-l);
  background: var(--ds-color-surface-panel); border: var(--ds-outline-bold) solid var(--ds-color-outline-ink); box-shadow: var(--ds-shadow-hard); }
.livebar__title { display: flex; align-items: center; gap: var(--ds-space-xs); font-size: var(--ds-type-label); }
.livebar__vals { display: flex; flex-wrap: wrap; gap: var(--ds-space-s) var(--ds-space-xl); margin: 0; flex: 1 1 auto; }
.livebar__vals div { display: flex; align-items: baseline; gap: var(--ds-space-xs); }
.livebar dt { order: 2; font-size: var(--ds-type-small); color: var(--ds-color-text-muted); }
.livebar dd { margin: 0; font-family: var(--ds-font-display); font-size: var(--ds-type-title-s); line-height: 1.12; font-variant-numeric: tabular-nums; }
@media (max-width: 1023px) { .download__grid { grid-template-columns: minmax(0, 1fr); gap: var(--ds-space-xl); } }
@media (max-width: 767px) {
  .dplate { padding: var(--ds-space-l); }
  .dplate__text { font-size: var(--ds-type-label); }
  .dplate .ds-btn { width: 100%; white-space: normal; }
  .steps__list b { font-size: var(--ds-type-body-l); }
  .steps__list li { grid-template-columns: 56px minmax(0, 1fr); min-height: 48px; }
  .steps__list li::before { width: 48px; height: 48px; font-size: var(--ds-type-title-s); }
  .livebar { padding: var(--ds-space-m); }
}

/* ---------- Nexus (WC07, WN05): the section wears the launcher's own look, "graphite glass" of the BAPBAP Nexus launcher
   (src/renderer/styles/index.css + design-system.css + app/shell/splash.css of v7.0, read only): graphite surfaces, a hairline
   white rim, warm white ink, round 18 px corners, a chrome wordmark and glossy white pills. The colours are the launcher's,
   not game tokens, so each literal carries its source. Entrance: app.js nexusIntro (transform and opacity only). ---------- */
.nexus {
  --nx-bg: #08090b; /* ds-allow DS101: Nexus launcher --background (index.css) */
  --nx-card: #111214; /* ds-allow DS101: Nexus launcher --card */
  --nx-ink: #f1f0ea; /* ds-allow DS101: Nexus launcher --foreground, warm near-white */
  --nx-ink-dim: rgba(241, 240, 234, 0.62); /* ds-allow DS101: Nexus launcher --ink-dim */
  --nx-muted: #9a9ca3; /* ds-allow DS101: Nexus launcher --muted-foreground */
  --nx-on-primary: #0a0b0d; /* ds-allow DS101: Nexus launcher --primary-foreground */
  --nx-rim: rgba(255, 255, 255, 0.085); /* ds-allow DS101: Nexus launcher --glass-rim */
  --nx-rim-strong: rgba(255, 255, 255, 0.16); /* ds-allow DS101: Nexus launcher --glass-rim-strong */
  --nx-highlight: rgba(255, 255, 255, 0.09); /* ds-allow DS101: Nexus launcher --glass-highlight */
  --nx-light: rgba(255, 252, 246, 0.95); /* ds-allow DS101: light scan of the launcher splash wordmark (splash.css) */
  --nx-pill-rim: rgba(255, 255, 255, 0.7); /* ds-allow DS101: rim of the launcher's glossy white pill */
  --nx-radius: 18px;
  --nx-radius-pill: 999px;
}
main > section.nexus { padding-top: var(--ds-space-xxl); padding-bottom: var(--ds-space-xxl); }
.nexus__panel { position: relative; display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); grid-template-areas: "head head" "media text"; column-gap: var(--ds-space-xxl); row-gap: var(--ds-space-xl);
  align-items: center; padding: var(--ds-space-xxl) var(--ds-space-xxl) var(--ds-space-xxxl); overflow: hidden; isolation: isolate; color: var(--nx-ink);
  border: 1px solid var(--nx-rim); border-radius: var(--nx-radius);
  background: radial-gradient(60% 42% at 50% -6%, rgba(255, 255, 255, 0.055), transparent 70%), radial-gradient(80% 50% at 50% 110%, rgba(255, 255, 255, 0.025), transparent 70%), var(--nx-bg); /* ds-allow DS101: .ds-page-ambient of the launcher */
  box-shadow: inset 0 1px 0 0 var(--nx-highlight), 0 34px 70px -34px rgba(0, 0, 0, 0.9); } /* ds-allow DS101: .ds-surface--hero shadow of the launcher */
/* the rim light of the entrance: a hairline across the top edge */
.nexus__rim { position: absolute; left: 0; right: 0; top: 0; height: 1px; z-index: 1; transform-origin: 50% 50%; background: linear-gradient(90deg, transparent, var(--nx-light), transparent); opacity: 0.55; }
.nexus__head { grid-area: head; display: grid; gap: var(--ds-space-s); justify-items: start; min-width: 0; }
/* the chrome wordmark: the launcher's own display face (Archivo Black ships with the launcher) with the studio gradient of
   the splash wordmark (cool sky, horizon line, graphite floor) */
.nexus__title { position: relative; display: inline-block; max-width: 100%; overflow-x: clip; overflow-y: visible; margin: 0; padding: 0 0.04em; font-family: var(--ds-font-display); font-weight: 400;
  font-size: clamp(var(--ds-type-hero), 12vw, calc(var(--ds-type-mega) * 1.6)); line-height: 1.12; letter-spacing: -0.03em; text-transform: uppercase; }
.nexus__word { display: block; color: var(--nx-ink);
  background: linear-gradient(180deg, #f6f7fa 0%, #dfe3ea 18%, #aab0ba 40%, #eef0f3 49.5%, #2c2f35 51%, #50545c 62%, #9aa0a9 84%, #e3e6ea 100%); /* ds-allow DS101: chrome of the launcher splash wordmark (splash.css .splash-logo-chrome) */
  -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; }
@media (forced-colors: active) { .nexus__word { -webkit-text-fill-color: currentColor; background: none; } }
/* the cover pours the chrome in from the left (its leading edge is the light scan), then the glint runs over the letters */
.nexus__cover { position: absolute; inset: 0; z-index: 1; background: var(--nx-bg); transform: translateX(120%); pointer-events: none; }
.nexus__cover::before { content: ""; position: absolute; top: 0; bottom: 0; left: 0; width: 3px; background: var(--nx-light); box-shadow: 0 0 24px 6px rgba(255, 252, 246, 0.35); } /* ds-allow DS101: light scan of the launcher splash */
.nexus__glint { position: absolute; top: 0; bottom: 0; left: 0; width: 40%; z-index: 2; pointer-events: none; mix-blend-mode: overlay; opacity: 0;
  background: linear-gradient(104deg, transparent 0 30%, var(--nx-light) 50%, transparent 70% 100%); transform: translateX(-120%); }
.nexus__sub { font-family: var(--ds-font-label); font-size: var(--ds-type-body-l); color: var(--nx-muted); }
.nexus__media { grid-area: media; margin: 0; display: grid; gap: var(--ds-space-xs); min-width: 0; }
/* the launcher window: its own round corner and glass rim instead of the game's ink outline */
.nexus__win { position: relative; aspect-ratio: 16 / 9; overflow: hidden; background: var(--nx-card); border: 1px solid var(--nx-rim-strong); border-radius: var(--nx-radius);
  box-shadow: inset 0 1px 0 0 var(--nx-highlight), 0 2px 4px rgba(0, 0, 0, 0.45), 0 34px 70px -34px rgba(0, 0, 0, 0.9); } /* ds-allow DS101: .ds-surface--hero of the launcher */
.nexus__win.is-pre { opacity: 0; }
/* before the entrance (class set by app.js only when it will animate): wordmark covered, rim dark, features waiting */
.nexus__panel.is-pre .nexus__cover { transform: none; }
.nexus__panel.is-pre .nexus__cover::before { opacity: 0; }
.nexus__panel.is-pre .nexus__rim, .nexus__panel.is-pre .nexus__feats li, .nexus__panel.is-pre .nexus__ver, .nexus__panel.is-pre .nexus__cta { opacity: 0; }
.nexus__vid { width: 100%; height: 100%; object-fit: cover; }
.nexus__cap { font-size: var(--ds-type-small); color: var(--nx-muted); }
.nexus--noclip .nexus__panel { grid-template-areas: "head" "text"; grid-template-columns: minmax(0, 1fr); }
.nexus--noclip .nexus__media { display: none; }
.nexus__text { grid-area: text; display: grid; justify-items: start; gap: var(--ds-space-l); min-width: 0; }
.nexus__feats { display: grid; gap: var(--ds-space-s); margin: 0; padding: 0; list-style: none; }
.nexus__feats li { display: grid; grid-template-columns: var(--ds-space-m) minmax(0, 1fr); align-items: baseline; gap: var(--ds-space-s); font-size: var(--ds-type-body-l); color: var(--nx-ink); }
/* the launcher's lit status dot (.ds-dot--on) */
.nexus__mark { width: 7px; height: 7px; border-radius: var(--nx-radius-pill); background: var(--nx-ink); box-shadow: 0 0 8px rgba(241, 240, 234, 0.55); transform: translateY(-2px); } /* ds-allow DS101: .ds-dot--on of the launcher */
.nexus__ver { font-family: var(--ds-font-label); font-size: var(--ds-type-small); color: var(--nx-ink-dim); }
.nexus__cta { display: flex; flex-wrap: wrap; gap: var(--ds-space-s); }
/* the launcher pills: glossy white = the one main action, glass = the second */
.nx-btn { position: relative; display: inline-flex; align-items: center; justify-content: center; min-height: var(--ds-space-button-h); padding: 0 var(--ds-space-l);
  border: 1px solid transparent; border-radius: var(--nx-radius-pill); font-family: var(--ds-font-label); font-size: var(--ds-type-body); text-decoration: none; white-space: nowrap;
  transition: transform var(--ds-motion-select) var(--ds-ease-smooth), opacity var(--ds-motion-select) var(--ds-ease-smooth); }
.nx-btn:hover { transform: translateY(-1px); }
.nx-btn:active { transform: translateY(1px); }
.nx-btn:focus-visible { outline: 2px solid var(--nx-ink); outline-offset: 3px; }
.nx-btn--primary { color: var(--nx-on-primary); border-color: var(--nx-pill-rim);
  background: linear-gradient(180deg, #ffffff 0%, #e9e8e3 55%, #d6d5d0 100%); /* ds-allow DS101: .ds-btn--primary of the launcher (glossy white) */
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.95), inset 0 -1px 0 rgba(0, 0, 0, 0.12), 0 8px 22px -10px rgba(255, 255, 255, 0.35), 0 2px 6px rgba(0, 0, 0, 0.4); } /* ds-allow DS101: .ds-btn--primary of the launcher */
.nx-btn--primary:hover { color: var(--nx-on-primary); }
.nx-btn--glass { color: var(--nx-ink); border-color: var(--nx-rim-strong);
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.02) 55%), rgba(14, 15, 18, 0.72); /* ds-allow DS101: .ds-btn--glass of the launcher */
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16), 0 2px 8px rgba(0, 0, 0, 0.35); } /* ds-allow DS101: .ds-btn--glass of the launcher */
.nx-btn--glass:hover { color: var(--nx-ink); }
@media (max-width: 1023px) { .nexus__panel { grid-template-columns: minmax(0, 1fr); grid-template-areas: "head" "media" "text"; padding: var(--ds-space-xl) var(--ds-space-l) var(--ds-space-xxl); } }
@media (max-width: 767px) {
  main > section.nexus { padding-left: var(--ds-space-s); padding-right: var(--ds-space-s); }
  .nexus__panel { padding: var(--ds-space-l) var(--ds-space-m) var(--ds-space-xl); row-gap: var(--ds-space-l); }
  .nexus__title { font-size: min(var(--ds-type-hero), 22vw); }
  .nexus__feats li { font-size: var(--ds-type-body); }
  .nexus__cta .nx-btn { flex: 1 1 100%; white-space: normal; text-align: center; }
}

/* ---------- FAQ ---------- */
.faq__list { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--ds-space-xs); margin-top: var(--ds-space-l); max-width: 960px; }
.faq details { background: var(--ds-color-surface-panel); border: var(--ds-outline-bold) solid var(--ds-color-outline-ink); box-shadow: var(--ds-shadow-hard); }
.faq summary { position: relative; list-style: none; cursor: pointer; padding: var(--ds-space-m) calc(var(--ds-space-xxxl) + var(--ds-space-xs)) var(--ds-space-m) var(--ds-space-l); font-family: var(--ds-font-display); font-size: var(--ds-type-label); line-height: 1.25; }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: ""; position: absolute; right: var(--ds-space-l); top: 50%; width: 14px; height: 14px; margin-top: -10px; border-right: var(--ds-outline-bold) solid currentColor; border-bottom: var(--ds-outline-bold) solid currentColor; transform: rotate(45deg); transition: transform var(--ds-motion-select) var(--ds-ease-enter); }
.faq details[open] { box-shadow: inset var(--ds-outline-extra) 0 0 var(--ds-color-accent-primary), var(--ds-shadow-hard); }
.faq details[open] summary::after { transform: translateY(6px) rotate(225deg); }
.faq details p { padding: 0 var(--ds-space-l) var(--ds-space-l); max-width: 64ch; color: var(--ds-color-text-primary); font-size: var(--ds-type-body-l); }
.faq details[open] p { animation: ds-panel-in var(--ds-motion-panel-in) var(--ds-ease-enter) both; }
@media (max-width: 767px) { .faq summary { font-size: var(--ds-type-nav); } .faq details p { font-size: var(--ds-type-body); } }

/* ---------- footer: the closing band (Discord is the yellow action), then fan note and links ---------- */
.foot { margin-top: var(--ds-space-xl); }
.foot__band { display: grid; gap: var(--ds-space-m); justify-items: start; padding: var(--ds-space-xxxl) var(--ds-space-screen-margin-x); background-color: var(--ds-color-accent-hot);
  --ds-dot: color-mix(in srgb, var(--ds-color-outline-ink) 14%, transparent);
  background-image: radial-gradient(circle, var(--ds-dot) calc(var(--ds-space-dot-grid-dot) / 2), transparent calc(var(--ds-space-dot-grid-dot) / 2 + 0.5px)); background-size: var(--ds-space-dot-grid-step) var(--ds-space-dot-grid-step);
  border-top: var(--ds-outline-bold) solid var(--ds-color-outline-ink); border-bottom: var(--ds-outline-bold) solid var(--ds-color-outline-ink); }
.foot__title { font-size: var(--ds-type-hero); text-transform: uppercase; color: var(--ds-color-text-primary); text-shadow: 0 var(--ds-outline-bold) 0 var(--ds-color-outline-ink); }
.foot__band p { max-width: 56ch; font-size: var(--ds-type-body-l); color: var(--ds-color-text-primary); }
.foot__cta { display: flex; flex-wrap: wrap; gap: var(--ds-space-s); }
.foot__base { max-width: 1600px; margin: 0 auto; padding: var(--ds-space-xl) var(--ds-space-screen-margin-x) var(--ds-space-xxl); display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--ds-space-m); font-size: var(--ds-type-small); color: var(--ds-color-text-muted); }
.foot__base p { max-width: 70ch; }
.foot__links { display: flex; flex-wrap: wrap; gap: var(--ds-space-l); }
.foot__links a { color: var(--ds-color-text-muted); font-family: var(--ds-font-display); text-transform: uppercase; text-decoration: none; }
.foot__links a:hover { color: var(--ds-color-text-primary); }
@media (max-width: 767px) {
  .foot__band { padding: var(--ds-space-xxl) var(--ds-space-m); }
  .foot__title { font-size: calc(var(--ds-type-hero) * 0.55); }
  .foot__base { padding: var(--ds-space-l) var(--ds-space-m) var(--ds-space-xl); }
}

/* ---------- privacy page (privacy.html, S32 lab P0-20): one readable column on a panel over the page background.
   body.ds-page sets the text colour, the card the surface (text-primary on surface-panel, docs/UI.md >= 4.5:1). ---------- */
.legal-top, .legal { max-width: 80ch; margin: 0 auto; padding-left: var(--ds-space-screen-margin-x); padding-right: var(--ds-space-screen-margin-x); }
.legal-top { display: flex; align-items: center; justify-content: space-between; gap: var(--ds-space-m); padding-top: var(--ds-space-l); }
.legal { padding-top: var(--ds-space-l); padding-bottom: var(--ds-space-xxl); }
.legal__card { padding: var(--ds-space-xl); background: var(--ds-color-surface-panel); box-shadow: var(--ds-shadow-hard); }
.legal h1 { font-size: var(--ds-type-headline); }
.legal h2 { margin-top: var(--ds-space-xl); font-size: var(--ds-type-title-s); }
.legal p, .legal ul { margin-top: var(--ds-space-s); line-height: 1.6; }
.legal ul { padding-left: var(--ds-space-l); }
.legal li + li { margin-top: var(--ds-space-xs); }
.legal code { overflow-wrap: anywhere; }
.legal__asof { color: var(--ds-color-text-muted); }
.legal__links { display: flex; flex-wrap: wrap; gap: var(--ds-space-l); margin-top: var(--ds-space-l); }
.legal__links a { color: var(--ds-color-text-muted); font-family: var(--ds-font-display); text-transform: uppercase; text-decoration: none; }
.legal__links a:hover { color: var(--ds-color-text-primary); }
@media (max-width: 767px) {
  .legal-top, .legal { padding-left: var(--ds-space-m); padding-right: var(--ds-space-m); }
  .legal__card { padding: var(--ds-space-l) var(--ds-space-m); }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .wx-lang__list, .modes__panel.is-swap > *, .faq details[open] p { animation: none; }
  .top::before { transition: none; }
}
