/* The typefaces, served by the page server from their npm packages (packages/frontend/src/index.ts).
   Two subsets each: Latin, and Latin Extended for the accented names a username can carry. unicode-range
   means a page with no such character never downloads the second file. `swap` shows text in the
   fallback at once and swaps the face in when it lands, rather than hiding text while it loads. */
@font-face {
  font-family: "Chakra Petch"; font-style: normal; font-weight: 700; font-display: swap;
  src: url("/fonts/chakra-petch/chakra-petch-latin-700-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
  font-family: "Chakra Petch"; font-style: normal; font-weight: 700; font-display: swap;
  src: url("/fonts/chakra-petch/chakra-petch-latin-ext-700-normal.woff2") format("woff2");
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face {
  font-family: "Manrope"; font-style: normal; font-weight: 200 800; font-display: swap;
  src: url("/fonts/manrope/manrope-latin-wght-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
  font-family: "Manrope"; font-style: normal; font-weight: 200 800; font-display: swap;
  src: url("/fonts/manrope/manrope-latin-ext-wght-normal.woff2") format("woff2");
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face {
  font-family: "JetBrains Mono"; font-style: normal; font-weight: 100 800; font-display: swap;
  src: url("/fonts/jetbrains-mono/jetbrains-mono-latin-wght-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
  font-family: "JetBrains Mono"; font-style: normal; font-weight: 100 800; font-display: swap;
  src: url("/fonts/jetbrains-mono/jetbrains-mono-latin-ext-wght-normal.woff2") format("woff2");
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}

/* The palette is the logo's: a neutral black like its outline, white and silver like its chrome, and
   the green of its X. Nothing in the greys leans blue, so the green is the only colour on a page until a
   result puts one there.
   --brand is for what the player acts on and where they are; --win is money coming in — a win, a gem, a
   balance going up. They are the same green today, as the logo and a win both mean "up", but they are two
   tokens so either can move without dragging the other. --loss is red, and nothing but a loss uses it. */
:root {
  --bg: #0a0a0b; --panel: #131315; --panel-2: #1c1c1f; --line: #2a2a2f;
  --text: #f4f4f5; --muted: #9b9ba4; --silver: #d4d4d8;
  /* The green is light, so text on it is dark: white on #4ade80 is under 2:1. */
  --brand: #4ade80; --brand-lo: #36c56c; --brand-deep: #1f8a4c; --brand-ink: #06210f;
  --brand-text: #4ade80;
  --win: #4ade80; --win-ink: #06210f; --loss: #f87171; --gold: #f2b632;
  /* Surfaces are lit from above: a raised panel is a shade lighter at its top edge than at its foot, and
     carries a one-pixel highlight along that edge. The flat colours above stay for the places a gradient
     cannot go — a sticky table header has to match the panel it scrolls over, and a gradient cannot. */
  --surface: linear-gradient(180deg, #18181b, var(--panel) 70%);
  --surface-raised: linear-gradient(180deg, #1d1d21, #141417);
  --inset: radial-gradient(120% 100% at 50% 0%, #212125, #151517 70%);
  --edge: inset 0 1px 0 rgba(255, 255, 255, .045);
  --radius: 12px;
  /* Three roles. Titles in Chakra Petch, whose clipped corners are the site's one typographic flourish,
     and only in its bold. Everything read in Manrope. Every amount, multiplier, seed and hash in
     JetBrains Mono, so digits line up and a hash reads as a hash. */
  --font-body: "Manrope", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-display: "Chakra Petch", var(--font-body);
  --font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  /* The top bar's height, in one place because the sidebar is sized from it. A sticky element still takes
     its space in normal flow, so anything below the bar that wants to fill the viewport has to subtract it. */
  --topbar-h: 72px;
}
* { box-sizing: border-box; }
body {
  margin: 0; background: var(--bg); color: var(--text);
  font: 15px/1.5 var(--font-body);
}
/* Titles. Chakra Petch is square and wide, and reads best in capitals: every heading gets it, and the
   large ones are set uppercase in their own rules. */
h1, h2, h3 { font-family: var(--font-display); font-weight: 700; }
.level-title, .reveal-tier, .home-jackpot-label, .nav-head, .audit-head { font-family: var(--font-display); }
/* The room the page sits in: a faint green light from the top left, where the logo is, and a cooler one
   from the far corner. Fixed layers rather than `background-attachment: fixed`, which mobile browsers
   ignore or repaint on every scroll. Behind everything, and never in the way of a click.

   Each light drifts, very slowly, on its own clock — 47s and 61s, so the two never fall into a loop the
   eye can learn. Only `transform` and `opacity` move: the compositor animates those without repainting
   the gradients, where animating a gradient's position would repaint the whole screen every frame. The
   layers overhang the viewport by 15% a side so a drifted edge is never seen. The motion is the point
   of a quiet background, not a feature: if it ever reads as movement rather than as light, it is too
   much — shorten the distance before touching the duration. */
body::before, body::after {
  content: ''; position: fixed; inset: -15%; z-index: -1; pointer-events: none;
  will-change: transform, opacity;
  animation: 47s ease-in-out infinite alternate drift-green;
}
body::before {
  background:
    radial-gradient(46% 38% at 12% 12%, color-mix(in srgb, var(--brand) 9%, transparent), transparent 70%),
    linear-gradient(180deg, #0d0d0f, var(--bg) 50%);
}
body::after {
  background: radial-gradient(38% 35% at 88% 88%, rgba(120, 130, 160, .07), transparent 70%);
  animation-name: drift-cool; animation-duration: 61s;
}
@keyframes drift-green {
  from { transform: translate3d(0, 0, 0) scale(1); opacity: .8; }
  to { transform: translate3d(5vw, 4vh, 0) scale(1.08); opacity: 1; }
}
@keyframes drift-cool {
  from { transform: translate3d(0, 0, 0) scale(1.06); opacity: 1; }
  to { transform: translate3d(-4vw, -5vh, 0) scale(1); opacity: .7; }
}
@media (prefers-reduced-motion: reduce) { body::before, body::after { animation: none; } }
.mono { font-family: var(--font-mono); font-size: 13px; }
.hidden { display: none !important; }
.muted { color: var(--muted); }
.small { font-size: 13px; }
.error { color: var(--loss); min-height: 1.2em; margin: 8px 0 0; font-size: 13px; }

header {
  display: flex; justify-content: space-between; align-items: center;
  padding: 14px 20px; border-bottom: 1px solid var(--line);
  /* Frosted: the top bar is sticky on the player page, so the page scrolls underneath it and shows through. */
  background: rgba(14, 14, 16, .72);
  -webkit-backdrop-filter: blur(16px) saturate(150%); backdrop-filter: blur(16px) saturate(150%);
}
.brand { font-weight: 700; letter-spacing: .14em; display: flex; align-items: center; gap: 10px; }
/* Height-capped, width automatic. The mark is now the tallest thing in the bar, so --topbar-h is sized
   from it rather than from the avatar: 52px plus the bar's 10px padding either side is the 72px token,
   and the sidebar reads that token, so the two cannot drift apart.
   `width: auto` with the intrinsic ratio on the tag keeps it from reserving the full 252px while it
   loads. The file is 120px tall, so it stays sharp to 2x here and 3x at the phone size below. */
.brand-logo { height: 52px; width: auto; display: block; }
/* A phone's bar also holds the wallet pill and the avatar; at 52px the mark crowds them off the row. */
@media (max-width: 640px) { .brand-logo { height: 34px; } }
.brand em { font-style: normal; font-weight: 400; letter-spacing: .04em; color: var(--muted); font-size: 12px; }
.dot { width: 9px; height: 9px; border-radius: 50%; background: var(--win); box-shadow: 0 0 12px var(--win); }
.account { font-size: 13px; color: var(--muted); display: flex; gap: 12px; align-items: center; }

main { padding: 20px; max-width: 1180px; margin: 0 auto; }
/* The game, then its history. Balances live in the top bar. */
.grid { display: grid; gap: 16px; grid-template-columns: minmax(0, 1fr); align-items: start; }
.wide { grid-column: 1 / -1; }

.card {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 16px;
  box-shadow: var(--edge);
}
.card h2 { margin: 0 0 12px; font-size: 13px; text-transform: uppercase; letter-spacing: .1em; color: var(--muted); }

button {
  font: inherit; border-radius: 8px; border: 1px solid transparent; cursor: pointer; padding: 9px 14px;
}
button:disabled { opacity: .5; cursor: not-allowed; }
.primary {
  background: linear-gradient(180deg, var(--brand), var(--brand-lo)); color: var(--brand-ink); font-weight: 600;
  border-color: var(--brand-deep);
}
.primary:hover:not(:disabled) {
  /* The glow is the button's own colour: --glow, which a button in another colour sets alongside its fill. */
  filter: brightness(1.08); box-shadow: 0 6px 22px color-mix(in srgb, var(--glow, var(--brand)) 30%, transparent);
}
.big { width: 100%; padding: 13px; font-size: 16px; margin-top: 4px; }
.ghost { background: var(--surface-raised); color: var(--text); border-color: var(--line); box-shadow: var(--edge); }
.ghost:hover:not(:disabled) { border-color: var(--muted); }
.small-btn { padding: 6px 10px; font-size: 13px; }
.row { display: flex; gap: 10px; flex-wrap: wrap; }

input, select {
  font: inherit; background: var(--panel-2); color: var(--text);
  border: 1px solid var(--line); border-radius: 8px; padding: 9px 11px; width: 100%;
}
input:focus, select:focus { outline: 2px solid var(--silver); outline-offset: -1px; }
::selection { background: color-mix(in srgb, var(--brand) 35%, transparent); color: var(--text); }
label { display: block; font-size: 13px; color: var(--muted); margin-bottom: 12px; }
label input, label select { margin-top: 6px; }


.tabs { display: flex; gap: 6px; margin-bottom: 14px; }
.tab { background: none; color: var(--muted); border: 1px solid var(--line); }
.tab.active { background: var(--panel-2); color: var(--text); border-color: var(--brand); }

.result {
  height: 108px; display: grid; place-items: center; border-radius: var(--radius);
  background: var(--inset); margin-bottom: 16px; text-align: center;
}
.result .big-num { font-size: 38px; font-weight: 700; font-family: var(--font-mono); }
.result .win { color: var(--win); }
.result .lose { color: var(--loss); }
.result .sub { font-size: 13px; color: var(--muted); margin-top: 2px; }

/* An instant game: its controls on the left, the outcome large on the right. */
.instant { display: grid; grid-template-columns: minmax(260px, 320px) minmax(0, 1fr); gap: 20px; }
.instant .result { height: auto; min-height: 250px; margin-bottom: 0; }
.instant .result .big-num { font-size: 56px; }
@media (max-width: 760px) {
  .instant { grid-template-columns: 1fr; }
  .instant .result { order: -1; min-height: 120px; }
  .instant .result .big-num { font-size: 40px; }
}

.payout-preview {
  display: flex; justify-content: space-between; font-size: 13px; color: var(--muted);
  padding: 10px 0; border-top: 1px solid var(--line); margin-bottom: 6px;
}
.payout-preview b { color: var(--text); font-family: var(--font-mono); }

.kv { display: grid; grid-template-columns: 1fr; gap: 4px; margin: 0 0 14px; }
.kv dt { font-size: 12px; color: var(--muted); }
.kv dd { margin: 0 0 10px; }
.seed-edit { display: flex; gap: 6px; align-items: center; }
.seed-edit input { flex: 1; min-width: 0; }
.trunc { overflow-wrap: anywhere; color: var(--silver); }
.revealed {
  background: var(--panel-2); border-radius: 8px; padding: 10px; margin-top: 12px;
  font-size: 12px; overflow-wrap: anywhere;
}

.scroll { max-height: 320px; overflow-y: auto; }
.history { width: 100%; border-collapse: collapse; font-size: 13px; }
.history th {
  text-align: left; color: var(--muted); font-weight: 500; font-size: 12px;
  padding: 6px 8px; position: sticky; top: 0; background: var(--panel);
}
.history td { padding: 7px 8px; border-top: 1px solid var(--line); font-family: var(--font-mono); }
.history .w { color: var(--win); }
.history .l { color: var(--loss); }

/* ------------------------------------------------------- explainer page -- */
.link { color: var(--brand-text); text-decoration: none; }
.link:hover { text-decoration: underline; }
.seed-link { float: right; font-size: 12px; text-transform: none; letter-spacing: 0; }

.prose { max-width: 760px; }
.prose h1 { font-size: 30px; margin: 8px 0 4px; letter-spacing: .01em; text-transform: uppercase; }
.prose h2 {
  font-size: 13px; text-transform: uppercase; letter-spacing: .1em; color: var(--muted);
  margin: 38px 0 12px; padding-bottom: 8px; border-bottom: 1px solid var(--line);
}
.prose p { margin: 0 0 14px; }
.prose .lead { font-size: 17px; line-height: 1.6; color: var(--text); margin-bottom: 4px; }
.prose code { background: var(--panel-2); padding: 1px 5px; border-radius: 4px; font-size: 13px; }
.note { color: var(--muted); border-left: 2px solid var(--line); padding-left: 14px; }

.defs { margin: 0; }
.defs dt { font-weight: 600; margin-top: 14px; }
.defs dt:first-child { margin-top: 0; }
.defs dd { margin: 4px 0 0; color: var(--muted); }

.steps { counter-reset: s; list-style: none; padding: 0; margin: 0; }
.steps li {
  counter-increment: s; position: relative; padding: 0 0 18px 40px;
  border-left: 1px solid var(--line); margin-left: 13px;
}
.steps li:last-child { border-left-color: transparent; padding-bottom: 0; }
.steps li::before {
  content: counter(s); position: absolute; left: -13px; top: -2px;
  width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center;
  background: var(--panel-2); border: 1px solid var(--line); font-size: 12px; color: var(--brand-text);
}

.code {
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 14px; overflow-x: auto; font-family: var(--font-mono); font-size: 13px;
  line-height: 1.6; margin: 0 0 14px;
}

.verifier { margin-bottom: 10px; }
.fields2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 14px; }
.fields2 label:first-child, .fields2 label:nth-child(2) { grid-column: 1 / -1; }
@media (max-width: 620px) { .fields2 { grid-template-columns: 1fr; } }

.v-out { margin-top: 14px; font-size: 13px; }
.v-out:empty { display: none; }
.v-out.good { border-left: 2px solid var(--win); padding-left: 12px; }
.v-out.bad { border-left: 2px solid var(--loss); padding-left: 12px; color: var(--loss); }
.v-row { display: flex; justify-content: space-between; gap: 16px; padding: 4px 0; }
.v-row span { color: var(--muted); }
.v-row b { overflow-wrap: anywhere; text-align: right; font-weight: 500; }

.proves { width: 100%; border-collapse: collapse; font-size: 14px; }
.proves td { padding: 10px 12px 10px 0; border-top: 1px solid var(--line); vertical-align: top; }
.proves td:first-child { white-space: nowrap; font-weight: 600; width: 1%; }
.proves .yes { color: var(--win); }
.proves .no { color: var(--muted); }

/* --------------------------------------------------------- deposit popup -- */
.deposit-grid { display: flex; gap: 20px; align-items: flex-start; flex-wrap: wrap; }
.qr {
  width: 168px; height: 168px; padding: 12px; background: #fff; border-radius: var(--radius);
  flex-shrink: 0;
}
.qr svg { width: 100%; height: 100%; display: block; }
.addr-block { flex: 1; min-width: 260px; }
.addr {
  background: var(--panel-2); border: 1px solid var(--line); border-radius: 8px;
  padding: 12px; overflow-wrap: anywhere; font-size: 14px; line-height: 1.5; margin-bottom: 10px;
}
.warn {
  margin: 18px 0 0; padding: 12px 14px; border-radius: 8px; font-size: 13px; line-height: 1.5;
  background: color-mix(in srgb, var(--loss) 8%, transparent); border: 1px solid color-mix(in srgb, var(--loss) 35%, transparent);
}
.warn strong { color: var(--loss); }
.networks { margin-top: 20px; display: grid; }
.network { border-top: 1px solid var(--line); padding: 14px 0 12px; }
.network-head { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.tokens { width: 100%; border-collapse: collapse; margin: 8px 0 6px; }
.tokens td { padding: 4px 10px 4px 0; vertical-align: middle; }
.tokens .tok { width: 1%; white-space: nowrap; color: var(--muted); font-size: 13px; }
.contract { font-size: 12.5px; overflow-wrap: anywhere; }
.tokens .nowrap { white-space: nowrap; width: 1%; }
@media (max-width: 560px) {
  .tokens, .tokens tbody, .tokens tr, .tokens td { display: block; width: auto; }
  .tokens tr { padding: 6px 0; border-bottom: 1px solid var(--line); }
  .tokens .tok { color: var(--text); font-weight: 600; }
}
.history .p { color: var(--gold); }

/* Two ways in: a segmented switch, not two buttons of equal weight to hunt between. */
.dep-tabs {
  display: grid; grid-template-columns: 1fr 1fr; gap: 4px; padding: 4px; margin-bottom: 18px;
  background: var(--bg); border: 1px solid var(--line); border-radius: 10px;
}
.dep-tab { padding: 8px 10px; border-radius: 7px; background: none; color: var(--muted); font-size: 14px; font-weight: 600; }
.dep-tab:hover { color: var(--text); }
.dep-tab.active { background: var(--panel-2); color: var(--text); box-shadow: inset 0 0 0 1px var(--line); }

.dep-status {
  display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap;
  margin-bottom: 14px; padding: 12px 14px; border-radius: 10px; background: var(--panel-2);
  font-size: 14px; line-height: 1.45;
}
.dep-label {
  display: flex; justify-content: space-between; align-items: baseline; margin: 0 0 8px;
  font-size: 12px; letter-spacing: .08em; text-transform: uppercase; color: var(--muted);
}
.link-btn {
  padding: 0; background: none; border: 0; color: var(--brand-text);
  font-size: 12px; letter-spacing: 0; text-transform: none;
}
.link-btn:hover { text-decoration: underline; }

.dep-holdings { display: grid; gap: 6px; max-height: 250px; margin-bottom: 18px; overflow-y: auto; }
.holding {
  display: flex; align-items: center; gap: 10px; width: 100%; padding: 9px 12px; text-align: left;
  background: var(--bg); border: 1px solid var(--line); border-radius: 10px; color: var(--text);
}
.holding:hover:not(:disabled) { border-color: var(--muted); }
.holding[aria-checked="true"] { border-color: var(--brand); background: color-mix(in srgb, var(--brand) 7%, transparent); }
.holding:disabled { opacity: .45; cursor: default; }
.holding .coin { width: 28px; height: 28px; flex-basis: 28px; font-size: 14px; }
.holding-name { display: grid; flex: 1; min-width: 0; line-height: 1.25; }
.holding-name b { font-size: 14px; }
.holding-name small { font-size: 12px; color: var(--muted); }
.holding-bal { font-size: 14px; font-variant-numeric: tabular-nums; }

.dep-amount {
  display: flex; align-items: center; gap: 8px; padding: 4px 4px 4px 12px;
  background: var(--bg); border: 1px solid var(--line); border-radius: 10px;
}
.dep-amount:focus-within { border-color: var(--silver); }
.dep-amount input {
  flex: 1; min-width: 0; padding: 8px 0; border: 0; background: none;
  font: 600 18px var(--font-mono); font-variant-numeric: tabular-nums;
}
.dep-amount input:focus { outline: none; }
.dep-amount-asset { display: inline-flex; align-items: center; gap: 5px; font-size: 13px; font-weight: 600; color: var(--muted); }
.dep-hint { min-height: 1.3em; margin: 8px 2px 14px; line-height: 1.45; }
.dep-hint.bad { color: var(--loss); }
#dep-send { margin-top: 0; }

.dep-contracts { margin-top: 16px; }
.dep-contracts summary { cursor: pointer; font-size: 13px; color: var(--muted); }
.dep-contracts summary:hover { color: var(--text); }
.dep-contracts .networks { margin-top: 8px; }
@media (max-width: 560px) { .qr { margin: 0 auto; } }

/* ------------------------------------------------------------ admin page -- */
.admin-page { max-width: 1180px; }
.admin-page .tabs { margin-bottom: 0; border-bottom: 1px solid var(--line); gap: 0; }
.admin-page .tab {
  border: 0; border-bottom: 2px solid transparent; border-radius: 0; padding: 10px 16px;
  background: none; color: var(--muted); display: inline-block; text-decoration: none;
}
.admin-page .tab:hover { color: var(--text); }
.admin-page .tab.active { background: none; color: var(--text); border-bottom-color: var(--brand); }
.panel { padding-top: 18px; }

.status { font-size: 12px; }
.status.ok { color: var(--win); }
.status.bad { color: var(--loss); }
.msg { font-size: 13px; margin: 8px 0 0; min-height: 1.2em; }
.msg.ok { color: var(--win); }
.msg.bad { color: var(--loss); }

/* Dense data table: the admin console is for scanning many rows, not reading prose.
   Named `data`, not `grid`: `.grid` is the player page's three-column layout, and a table that
   inherited `display: grid` from it put its thead and tbody in different columns. */
.data {
  width: 100%; border-collapse: collapse; font-size: 13px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden;
}
.data th {
  text-align: left; font-weight: 500; font-size: 11px; color: var(--muted);
  text-transform: uppercase; letter-spacing: .07em;
  padding: 10px 12px; background: var(--panel-2); border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
.data td { padding: 8px 12px; border-bottom: 1px solid var(--line); vertical-align: middle; }
.data tr:last-child td { border-bottom: 0; }
.data tbody tr:hover { background: rgba(255, 255, 255, .02); }
.data .num { text-align: right; }
.data .mid { text-align: center; }
.data .mid input[type="checkbox"] { width: auto; margin: 0; accent-color: var(--brand); }

/* Inputs sit inside cells without looking like a form. */
.cell {
  background: transparent; border: 1px solid transparent; border-radius: 6px;
  padding: 4px 8px; width: 100%; font-size: 13px;
}
.cell:hover { border-color: var(--line); }
.cell:focus { background: var(--panel-2); border-color: var(--silver); outline: none; }
.cell.num { text-align: right; }
.data td:has(> .cell) { padding: 4px 6px; }

.pill {
  display: inline-block; padding: 1px 8px; border-radius: 999px; font-size: 11px;
  background: color-mix(in srgb, var(--win) 12%, transparent); color: var(--win); border: 1px solid color-mix(in srgb, var(--win) 30%, transparent);
}

.addbar {
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-top: 16px;
  padding: 12px; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
}
.addbar input, .addbar select { width: auto; }
.addbar .grow { flex: 1; min-width: 220px; }
.addbar .narrow { width: 110px; }
.inline { display: flex; align-items: center; gap: 6px; margin: 0; font-size: 13px; white-space: nowrap; }
.inline input { width: auto; margin: 0; }

@media (max-width: 900px) {
  .admin-page { overflow-x: auto; }
  .data { min-width: 760px; }
}

/* ---------------------------------------------------------------- crash -- */

/* Recent crash points. The strip is the first thing a crash player looks at. */
/* Newest is leftmost, so the pills that matter are always in view and the 24th needs no scrollbar to
   advertise it. The bar is hidden rather than the overflow clipped — a swipe still reaches the rest. */
.strip { display: flex; gap: 6px; overflow-x: auto; margin-bottom: 12px; scrollbar-width: none; }
.strip::-webkit-scrollbar { display: none; }
.pop {
  font-family: var(--font-mono); font-size: 12px; padding: 3px 8px; border-radius: 999px;
  white-space: nowrap; border: 1px solid var(--line); background: var(--panel-2); color: var(--muted);
}
.pop.ok { color: var(--text); }
.pop.hot { color: var(--win); border-color: color-mix(in srgb, var(--win) 35%, transparent); background: color-mix(in srgb, var(--win) 10%, transparent); }
.pop.cold { color: var(--loss); }

.stage {
  position: relative; height: 300px; margin-bottom: 16px; overflow: hidden;
  border-radius: var(--radius); border: 1px solid var(--line);
  /* The canvas is cleared to transparent each frame, so this is the sky the curve is drawn on. Neutral:
     the curve is the only green on the stage, so a tint behind it would only dull it. */
  background: var(--inset);
}
.stage canvas { width: 100%; height: 100%; display: block; }
.stage-overlay {
  position: absolute; inset: 0; display: grid; place-content: center;
  text-align: center; pointer-events: none;
}
.crash-mult {
  font-family: var(--font-mono); font-size: 52px; font-weight: 700;
  letter-spacing: -0.02em; text-shadow: 0 2px 24px rgba(0, 0, 0, .65);
}
.crash-mult.busted { color: var(--loss); }
.crash-phase { font-size: 13px; color: var(--muted); margin-top: 2px; }
.stage-round {
  position: absolute; top: 10px; right: 12px;
  font-family: var(--font-mono); font-size: 12px; color: var(--muted);
}
@media (max-width: 560px) {
  .stage { height: 220px; }
  .crash-mult { font-size: 38px; }
}

.crash-form { display: grid; grid-template-columns: 1fr 1fr; gap: 0 14px; }
@media (max-width: 560px) { .crash-form { grid-template-columns: 1fr; } }
/* A bet field: a label with a note on its right, over an input that carries its unit and its quick buttons
   inside one box — the amount's coin with 1/2 and 2×, the auto cashout's × with ‹ and ›. The box is what
   takes focus, so the input and its buttons read as one control. */
.field { display: grid; gap: 6px; margin-bottom: 12px; min-width: 0; }
.field-head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; margin: 0; }
.field-note { font-size: 12px; font-variant-numeric: tabular-nums; }
.field-toggle { display: inline-flex; align-items: center; gap: 8px; margin: 0; cursor: pointer; }
/* Off, the field stays usable — typing or stepping switches it back on — but reads as not in play. */
.input-group.off { opacity: .5; }
.input-group.off:focus-within { opacity: 1; }

/* An on/off switch: a checkbox, restyled. Still a checkbox to the keyboard and to a screen reader. The knob is
   a gradient, not ::before — browsers do not all draw pseudo-elements on a form control. */
input.switch {
  appearance: none; -webkit-appearance: none; flex: 0 0 auto;
  width: 32px; height: 18px; margin: 0; padding: 0; cursor: pointer; border: 0; border-radius: 999px;
  background: radial-gradient(circle at 9px 50%, var(--silver) 6px, transparent 6.5px), var(--line);
}
input.switch:checked {
  background: radial-gradient(circle at 23px 50%, var(--brand-ink) 6px, transparent 6.5px), var(--brand);
}
input.switch:focus { outline: none; }
input.switch:focus-visible { outline: 2px solid var(--silver); outline-offset: 2px; }
.input-group {
  display: flex; align-items: stretch; min-width: 0; overflow: hidden;
  background: var(--panel-2); border: 1px solid var(--line); border-radius: 8px;
}
.input-group:focus-within { border-color: var(--silver); }
.input-group input { flex: 1; min-width: 0; margin: 0; border: 0; border-radius: 0; background: none; }
.input-group input:focus { outline: none; }
/* A field's unit. For an amount it is the currency chosen in the wallet, shown rather than picked here. */
.input-suffix {
  display: flex; align-items: center; gap: 5px; padding: 0 10px 0 2px;
  font-size: 13px; font-weight: 600; color: var(--muted); white-space: nowrap;
}
.input-suffix .coin-img { margin-right: 0; }
.input-step {
  flex: 0 0 auto; min-width: 38px; padding: 0 10px; border: 0; border-left: 1px solid var(--line); border-radius: 0;
  background: var(--surface-raised); color: var(--text); font: 600 13px/1 var(--font-mono);
}
.input-step:hover { color: var(--brand-text); }
/* A monospace face gives the slash a digit's full width, which spreads "1/2" wide; pulled together, it reads
   as one fraction. The same amount of padding on the left keeps it centred, since letter-spacing also
   trims the space after the last character. */
.input-step-tight { letter-spacing: -0.18em; padding-left: calc(10px - 0.18em); }
.input-step:focus-visible { outline: 2px solid var(--silver); outline-offset: -2px; }

/* Cashing out is a different act from betting, so it is a different colour: the bet button is the brand
   green, and a cash-out in the same green is one misclick away from the wrong one. */
button.cash { --glow: var(--gold); background: var(--gold); color: #241800; border-color: transparent; }

/* The game on the left, the round's players on the right. The players column is exactly as tall as the game and
   its list scrolls inside it, so a round filling up never pushes the curve or the bet button around. */
.crash-layout {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(260px, 320px); gap: 20px; align-items: stretch;
}
.crash-main { min-width: 0; }
.crash-commit-line { margin-bottom: 0; }
.crash-side {
  display: flex; flex-direction: column; min-width: 0;
  padding-left: 20px; border-left: 1px solid var(--line);
}
.crash-side h3 {
  margin: 0 0 8px; font-size: 12px; font-weight: 500;
  text-transform: uppercase; letter-spacing: .1em; color: var(--muted);
}
/* Absolutely placed, the list adds nothing to the column's height: the game decides it. */
.crash-players-box { position: relative; flex: 1; min-height: 240px; }
.crash-players-box > .scroll { position: absolute; inset: 0; max-height: none; }
.crash-side .history { font-size: 12px; }
.crash-side .history td { padding: 6px 4px; }
@media (max-width: 760px) {
  .crash-layout { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .crash-side { padding: 12px 0 0; margin-top: 16px; border-left: 0; border-top: 1px solid var(--line); }
  .crash-players-box { min-height: 0; }
  .crash-players-box > .scroll { position: static; max-height: 320px; }
}
.history .right { text-align: right; }
#crash-players td { border-top: 0; border-bottom: 1px solid var(--line); }
#crash-commit {
  display: inline-block; max-width: 240px; vertical-align: bottom;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ---------------------------------------------------------------- sound -- */
/* The speaker beside the avatar mutes on click. Hovering it reveals a vertical slider beneath, with a
   mute button under that; the wheel over the speaker moves the level (app.js). A phone gets no slider at
   all — its own volume buttons do that better — so it is not rendered at that width. */
.sound { position: relative; display: flex; }
.sound-btn {
  width: 40px; height: 40px; padding: 0; display: grid; place-items: center;
  background: var(--bg); color: var(--muted); border: 1px solid var(--line); border-radius: 10px;
}
.sound-btn:hover { color: var(--text); border-color: var(--muted); }
.sound-btn svg { width: 19px; height: 19px; }
.sound-btn .sound-off, .sound-btn.muted .sound-on { display: none; }
.sound-btn.muted .sound-off { display: block; }

/*
 * Nothing but the slider. Its box is transparent and stretched across `.sound` — `left: 0; right: 0` on
 * a container that is exactly the button's width — so the slider centres under the button with no
 * offset to get wrong. The top padding is the gap: the box starts flush at the button's lower edge, so
 * the pointer moving down to the slider stays inside `.sound` the whole way. With a real gap the hover
 * would break halfway down and the slider would flicker away.
 *
 * Hidden by opacity rather than `display: none`, because a display-none control cannot be focused — and
 * `:focus-within` is what opens this for a keyboard, which hover alone would lock out entirely.
 */
.sound-panel {
  position: absolute; top: 100%; left: 0; right: 0; z-index: 30; padding-top: 10px;
  display: grid; justify-items: center;
  opacity: 0; pointer-events: none; transition: opacity .12s ease;
}
.sound:hover .sound-panel, .sound:focus-within .sound-panel { opacity: 1; pointer-events: auto; }
/* Upright, with zero at the bottom: `writing-mode` turns a range, and `direction: rtl` puts its start at the
   bottom. The old `-webkit-appearance: slider-vertical` is gone — Chrome warns it is being removed. */
.sound-range {
  width: 28px; height: 120px; margin: 0; padding: 0; border: 0; background: none;
  writing-mode: vertical-lr; direction: rtl;
  accent-color: var(--brand);
}

@media (prefers-reduced-motion: reduce) { .sound-panel { transition: none; } }
@media (max-width: 640px) { .sound-panel { display: none; } }

/* ---------------------------------------------------------------- mines -- */

/* The controls on the left and the board large on the right: the shape of an instant game. */
.mines { display: grid; grid-template-columns: minmax(240px, 300px) minmax(0, 1fr); gap: 20px; align-items: start; }
.mines-board {
  display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 8px;
  width: 100%; max-width: 460px; margin: 0 auto; padding: 12px;
  border-radius: var(--radius); background: var(--inset); border: 1px solid var(--line);
}
@media (max-width: 760px) {
  .mines { grid-template-columns: 1fr; }
  .mines-board { order: -1; }
}
.tile {
  aspect-ratio: 1; padding: 0; display: grid; place-items: center; opacity: 1; cursor: default;
  border-radius: 10px; border: 1px solid var(--line); background: var(--bg); color: var(--muted);
  transition: transform .08s ease, border-color .12s ease, background .12s ease;
}
.tile svg { width: 56%; height: 56%; }
/* Only a tile that can be turned looks like it can be. */
.tile.live { cursor: pointer; background: var(--surface-raised); box-shadow: var(--edge); }
.tile.live:hover { border-color: var(--silver); transform: translateY(-2px); }
.tile.working { background: var(--panel); border-color: var(--silver); animation: tile-pulse .7s ease-in-out infinite alternate; }
.tile.gem { color: var(--win); background: color-mix(in srgb, var(--win) 10%, transparent); border-color: color-mix(in srgb, var(--win) 40%, transparent); }
.tile.mine { color: var(--loss); }
.tile.hit { background: color-mix(in srgb, var(--loss) 18%, transparent); border-color: var(--loss); }
/* After the game: what was never turned, shown faintly so what was turned stands out. */
.tile.dim { opacity: .4; background: var(--bg); border-color: var(--line); }
@keyframes tile-pulse { from { opacity: .55; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .tile { transition: none; }
  .tile.working { animation: none; }
}
.mines-foot { margin: 14px 0 0; padding-top: 12px; border-top: 1px solid var(--line); }
#mines-commit {
  display: inline-block; max-width: 240px; vertical-align: bottom;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ------------------------------------------------------- admin: users tab -- */
.audit-head {
  margin: 26px 0 10px; font-size: 12px; font-weight: 500;
  text-transform: uppercase; letter-spacing: .1em; color: var(--muted);
}
/* Rows are the way a player is picked, so they have to look pickable. */
.user-cell { display: inline-flex; align-items: center; gap: 8px; }
.avatar.avatar-xs { width: 22px; height: 22px; }
.avatar.avatar-sm { width: 28px; height: 28px; }
#rows-users tr { cursor: pointer; }
#rows-users tr.picked { background: color-mix(in srgb, var(--brand) 10%, transparent); }
#rows-users tr.picked td:first-child { box-shadow: inset 2px 0 0 var(--brand); }
.tag {
  display: inline-block; margin-left: 6px; padding: 0 6px; border-radius: 999px;
  font-size: 10px; letter-spacing: .06em; text-transform: uppercase;
  background: color-mix(in srgb, var(--brand) 14%, transparent); color: var(--brand-text); border: 1px solid color-mix(in srgb, var(--brand) 40%, transparent);
}
/* A self-adjustment is the shape abuse takes; it should catch the eye in the log. */
.data tr.self td { background: color-mix(in srgb, var(--loss) 7%, transparent); }
.data .warnmark { color: var(--loss); }
/* A hidden game should read as switched off at a glance. */
.data tr.off td { opacity: .55; }
.data tr.off td:first-child b { text-decoration: line-through; }

/* ------------------------------------------------------------ game menu -- */
/* A column of its own down the left of the player page. Below 900px it folds into a scrolling row
   under the header, so a phone keeps the whole width for the game. */
.shell { display: flex; align-items: flex-start; }
.shell > main { flex: 1; min-width: 0; }

/* Sized against the top bar, not the viewport. The bar is sticky, and a sticky element keeps its place in
   normal flow — so a full-viewport sidebar underneath one made every page exactly a top bar taller than the
   screen, and every page scrolled a little however little it held.
   `top` matches for the same reason: pinned at 0 the sidebar slid under the bar, which sits above it at
   z-index 20, and took its first rows of navigation with it. */
.sidebar {
  position: sticky; top: var(--topbar-h); flex: 0 0 264px;
  height: calc(100vh - var(--topbar-h)); overflow-y: auto; overflow-x: hidden;
  background: linear-gradient(180deg, rgba(19, 19, 21, .85), rgba(12, 12, 14, .55));
  border-right: 1px solid var(--line); padding: 18px 14px;
  transition: flex-basis .22s ease, padding .22s ease, border-width .22s ease, visibility 0s;
}
/* The same column on the other side of the game: its edge faces left. */
.sidebar-right { border-right: 0; border-left: 1px solid var(--line); }
.panel-empty { padding: 0 10px; margin: 0; }
/* The menu's contents keep their open width while the column closes over them, so it slides shut rather
   than squeezing every name onto three lines on its way to nothing. 264px less the 14px padding a side. */
.sidebar > nav, .sidebar > .sidebar-inner { width: 236px; }
/* Folded: gone, and the game takes the width. `visibility` flips only once the slide has finished, and
   is what takes the links out of the tab order — a hidden menu must not still be reachable by Tab. */
.sidebar.folded {
  flex-basis: 0; padding-inline: 0; border-width: 0; visibility: hidden;
  transition: flex-basis .22s ease, padding .22s ease, border-width .22s ease, visibility 0s .22s;
}
@media (prefers-reduced-motion: reduce) { .sidebar, .sidebar.folded { transition: none; } }
.nav-head {
  font-size: 11px; text-transform: uppercase; letter-spacing: .12em; color: var(--muted);
  padding: 0 10px; margin: 4px 0 10px;
}
.nav-games { display: grid; gap: 6px; }
.nav-empty { padding: 0 10px; }

.nav-game {
  position: relative; display: flex; align-items: center; gap: 14px; width: 100%;
  padding: 12px; text-align: left; background: none; color: var(--text); text-decoration: none;
  border: 1px solid transparent; border-radius: 10px;
  transition: background-color .12s, border-color .12s;
}
.nav-game:hover { background: var(--panel-2); }
.nav-game:focus-visible { outline: 2px solid var(--silver); outline-offset: -2px; }
.nav-game.active {
  background: linear-gradient(90deg, color-mix(in srgb, var(--brand) 10%, var(--panel-2)), var(--panel-2) 70%);
  border-color: var(--line);
}
.nav-game.active::before {
  content: ''; position: absolute; left: -14px; top: 12px; bottom: 12px; width: 3px;
  border-radius: 0 3px 3px 0; background: var(--brand);
}

.nav-icon {
  flex: 0 0 46px; height: 46px; display: grid; place-items: center; border-radius: 12px;
  background: var(--bg); border: 1px solid var(--line); color: var(--muted);
  font-size: 18px; font-weight: 700; transition: color .12s, border-color .12s, background-color .12s;
}
.nav-icon svg { width: 24px; height: 24px; }
.nav-game:hover .nav-icon { color: var(--text); }
.nav-game.active .nav-icon {
  color: var(--brand-text); border-color: color-mix(in srgb, var(--brand) 45%, transparent); background: color-mix(in srgb, var(--brand) 12%, transparent);
}

.nav-text { display: grid; min-width: 0; line-height: 1.25; }
.nav-text b { font-size: 16px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nav-text small { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--muted); }
/* A round game is running whether or not you are watching; the dot says so. */
.nav-text .live i {
  width: 6px; height: 6px; border-radius: 50%; background: var(--loss);
  box-shadow: 0 0 8px var(--loss); animation: nav-pulse 1.6s ease-in-out infinite;
}
@keyframes nav-pulse { 50% { opacity: .35; } }
@media (prefers-reduced-motion: reduce) { .nav-text .live i { animation: none; } }


@media (max-width: 900px) {
  .shell { flex-direction: column; align-items: stretch; }
  .sidebar {
    position: static; flex: none; height: auto; padding: 10px 12px;
    border-right: 0; border-bottom: 1px solid var(--line);
  }
  .nav-head { display: none; }
  .nav-games { display: flex; gap: 8px; overflow-x: auto; }
  .nav-game { flex: 0 0 auto; width: auto; gap: 10px; padding: 7px 14px 7px 7px; border-color: var(--line); }
  .nav-game.active { border-color: var(--brand); }
  .nav-game.active::before { display: none; }
  .nav-icon { flex-basis: 36px; height: 36px; border-radius: 9px; }
  .nav-text small { display: none; }
  .sidebar > nav { width: auto; }
  .sidebar.folded { display: none; }
  /* Below this width the game menu becomes a row above the game, and there is no side left for a panel:
     it and its button go, until it has something worth a row of its own. */
  .sidebar-right, .panel-toggle { display: none; }
}

/* --------------------------------------------------------------- top bar -- */
/* Brand on the left; on the right, the wallet and then the account — money beside the player it belongs to. */
header.topbar {
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto; gap: 12px;
  position: sticky; top: 0; z-index: 20; padding-block: 10px;
  /* min-height, not height: the tallest thing in here is the 52px brand mark, which with the padding
     comes to exactly --topbar-h. A taller control later should push the bar down rather than be clipped
     by it — the sidebar would then be one control too long, which is the old bug back at a smaller
     size, and visible rather than silent. Grow the token with the control, not one without the other. */
  min-height: var(--topbar-h);
}
.topbar .account { grid-column: 3; justify-self: end; }
.topbar-start { display: flex; align-items: center; gap: 12px; min-width: 0; }
.nav-toggle {
  flex-shrink: 0; width: 40px; height: 40px; padding: 0; display: grid; place-items: center;
  background: rgba(10, 10, 11, .6); color: var(--muted); border: 1px solid var(--line); border-radius: 10px;
  transition: color .12s, border-color .12s;
}
.nav-toggle:hover { color: var(--text); border-color: var(--muted); }
.nav-toggle:focus-visible { outline: 2px solid var(--silver); outline-offset: 2px; }
.nav-toggle svg { width: 20px; height: 20px; }

.wallet { position: relative; grid-column: 2; justify-self: end; }
/* One slim pill: the balance being played, and the way to top it up — nothing else, no spare room. */
.wallet-box {
  display: flex; align-items: center; height: 40px; padding: 3px;
  background: rgba(10, 10, 11, .6); border: 1px solid var(--line); border-radius: 10px;
}
.wallet-btn {
  display: flex; align-items: center; gap: 6px; height: 100%; padding: 0 8px 0 5px;
  background: none; color: var(--text); border-radius: 7px;
}
.wallet-btn:hover, .wallet-btn[aria-expanded="true"] { background: var(--panel-2); }
.wallet-coin { display: grid; }
/* Amount and symbol share one baseline: they are different fonts and sizes, so centring each box on its
   own leaves the symbol floating above or below the digits. */
.wallet-amount { display: inline-flex; align-items: baseline; gap: 4px; line-height: 1; }
/* Tabular digits, so a balance ticking up and down does not make the pill twitch sideways. */
.wallet-balance { font-size: 14px; font-weight: 600; font-variant-numeric: tabular-nums; transition: color .5s; }
.wallet-balance.up { color: var(--win); transition: none; }
.wallet-balance.down { color: var(--loss); transition: none; }
.wallet-sym { font-size: 11px; font-weight: 600; color: var(--muted); }
.chev { width: 13px; height: 13px; color: var(--muted); transition: transform .15s; }
.wallet-btn[aria-expanded="true"] .chev { transform: rotate(180deg); }
.wallet-deposit {
  display: inline-flex; align-items: center; gap: 5px; height: 100%; padding: 0 12px;
  border-radius: 7px; font-size: 13px; font-weight: 600;
}
.wallet-deposit svg { width: 14px; height: 14px; flex-shrink: 0; }

/* A coin: its official logo, or — for an asset we ship no logo for — a neutral disc with a letter.
   Logos are not cropped: not every official mark is a circle (Tether's is not). */
.coin {
  width: 22px; height: 22px; flex: 0 0 22px; display: grid; place-items: center;
  font-size: 12px; font-weight: 700; line-height: 1;
}
.coin img { display: block; width: 100%; height: 100%; object-fit: contain; }
.coin-letter { border-radius: 50%; background: #4a4a52; color: #fff; }

/* A logo inline with text — in tables and labels. Sized to the text it sits beside. */
.coin-img { display: inline-block; width: 16px; height: 16px; margin-right: 6px; vertical-align: -3px; object-fit: contain; }
.coin-img.coin-letter { display: inline-grid; place-items: center; font-size: 9px; font-weight: 700; line-height: 1; }
/* In a label that already spaces its children, the logo needs no margin of its own. */
.dep-amount-asset .coin-img { margin-right: 0; }

/* Aligned to the pill's right edge: it sits near the edge of the screen, and must not run off it. */
.wallet-menu {
  position: absolute; top: calc(100% + 6px); right: 0;
  width: 260px; max-height: 60vh; overflow-y: auto; padding: 5px; display: grid; gap: 1px;
  background: var(--surface-raised); border: 1px solid var(--line); border-radius: 10px;
  box-shadow: var(--edge), 0 16px 40px rgba(0, 0, 0, .5);
}
.wallet-item {
  display: flex; align-items: center; gap: 10px; width: 100%; padding: 7px 8px; text-align: left;
  background: none; color: var(--text); border-radius: 7px;
}
/* In the list there is room for the coin to be read at a glance. */
.wallet-item .coin { width: 26px; height: 26px; flex-basis: 26px; font-size: 14px; }
.wallet-item:hover { background: var(--panel-2); }
.wallet-item.active { background: var(--panel-2); box-shadow: inset 2px 0 0 var(--brand); }
.wallet-item .name { display: grid; flex: 1; min-width: 0; line-height: 1.25; }
.wallet-item .name b { font-size: 13px; }
.wallet-item .name small { font-size: 12px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wallet-item .amt { font-size: 13px; }
.wallet-item .amt.zero { color: var(--muted); }

@media (max-width: 640px) {
  header.topbar { grid-template-columns: auto minmax(0, 1fr) auto; gap: 8px; padding: 10px 12px; }
  .topbar-start { gap: 8px; }
  .nav-toggle { width: 36px; height: 36px; }
  .topbar .brand em, .wallet-sym, .deposit-label { display: none; }
  .account-menu { width: min(300px, calc(100vw - 24px)); }
  .wallet-deposit { padding: 0 9px; }
  .wallet-menu { width: min(260px, calc(100vw - 24px)); }
}

/* ----------------------------------------------------------------- popup -- */
.modal {
  padding: 0; width: min(640px, calc(100vw - 32px)); max-height: calc(100vh - 48px);
  background: var(--surface-raised); color: var(--text); border: 1px solid var(--line); border-radius: 16px;
  box-shadow: var(--edge), 0 24px 60px rgba(0, 0, 0, .6);
}
.modal::backdrop {
  background: rgba(0, 0, 0, .6);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.modal[open] { animation: modal-in .16s ease-out; }
@keyframes modal-in { from { opacity: 0; transform: translateY(8px) scale(.98); } }
@media (prefers-reduced-motion: reduce) { .modal[open] { animation: none; } }
body:has(.modal[open]) { overflow: hidden; }

/* Everything inside one wrapper, so a click that lands on the dialog itself is a click on the backdrop. */
.modal-inner { display: flex; flex-direction: column; max-height: calc(100vh - 48px); }
.modal-head {
  display: flex; justify-content: space-between; align-items: center;
  padding: 14px 16px 14px 20px; border-bottom: 1px solid var(--line);
}
.modal-head h2 { margin: 0; font-size: 18px; }
.modal-close { background: none; color: var(--muted); font-size: 24px; line-height: 1; padding: 4px 10px; }
.modal-close:hover { background: var(--panel-2); color: var(--text); }
.modal-body { padding: 20px; overflow-y: auto; }
.modal-sub {
  margin: 26px 0 8px; font-size: 12px; font-weight: 500;
  text-transform: uppercase; letter-spacing: .1em; color: var(--muted);
}

/* ------------------------------------------------------------------ home -- */
a.brand { color: inherit; text-decoration: none; }

.home { display: grid; gap: 28px; }
.hero {
  display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); gap: 24px; align-items: center;
  padding: 36px; border-radius: 18px; border: 1px solid var(--line); overflow: hidden;
  position: relative; isolation: isolate;
  background:
    radial-gradient(70% 90% at 0% 100%, rgba(120, 130, 160, .10), transparent 65%),
    linear-gradient(135deg, #1a1a1d, #0c0c0e);
  box-shadow: var(--edge), 0 20px 50px rgba(0, 0, 0, .35);
}
/* The hero's green light, on a layer of its own so it can breathe the way the page's lights drift: same
   rule, transform and opacity only. `isolation` keeps the -1 layer inside the hero, above its background
   and below its content; absolutely placed, it takes no cell in the hero's grid. */
.hero::before {
  content: ''; position: absolute; inset: -30%; z-index: -1; pointer-events: none;
  background: radial-gradient(45% 50% at 80% 25%, color-mix(in srgb, var(--brand) 22%, transparent), transparent 70%);
  will-change: transform, opacity;
  animation: 29s ease-in-out infinite alternate hero-breathe;
}
@keyframes hero-breathe {
  from { transform: translate3d(0, 0, 0) scale(1); opacity: .85; }
  to { transform: translate3d(-6%, 5%, 0) scale(1.1); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) { .hero::before { animation: none; } }
.hero-badge {
  display: inline-block; padding: 4px 10px; border-radius: 999px; font-size: 12px;
  letter-spacing: .08em; text-transform: uppercase; color: var(--brand-text);
  background: color-mix(in srgb, var(--brand) 12%, transparent); border: 1px solid color-mix(in srgb, var(--brand) 40%, transparent);
}
.hero h1 {
  margin: 14px 0 12px; font-size: clamp(30px, 4.2vw, 46px); line-height: 1.05; letter-spacing: .01em;
  text-transform: uppercase; text-wrap: balance;
}
.hero-lead { margin: 0 0 22px; max-width: 46ch; color: var(--muted); font-size: 16px; line-height: 1.6; }
.hero-cta { gap: 12px; }
.big-cta { padding: 12px 22px; font-size: 16px; border-radius: 10px; }
.hero-art { height: 220px; }
/* The SVG draws in currentColor, so the curve follows the palette rather than a copy of it. */
.hero-art { color: var(--brand); }
.hero-art svg { display: block; width: 100%; height: 100%; }
@media (max-width: 760px) {
  .hero { grid-template-columns: 1fr; padding: 24px; }
  .hero-art { height: 120px; order: -1; }
}

.home-head {
  margin: 0 0 -14px; font-size: 13px; font-weight: 500;
  text-transform: uppercase; letter-spacing: .1em; color: var(--muted);
}
.home-games { display: grid; gap: 14px; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); }
.game-card {
  display: grid; gap: 14px; padding: 20px; border-radius: 14px; text-decoration: none; color: var(--text);
  background: var(--surface); border: 1px solid var(--line); box-shadow: var(--edge);
  transition: transform .15s, border-color .15s, box-shadow .15s;
}
.game-card:hover {
  transform: translateY(-2px); border-color: color-mix(in srgb, var(--brand) 55%, transparent);
  box-shadow: var(--edge), 0 12px 32px color-mix(in srgb, var(--brand) 14%, transparent);
}
.game-card:focus-visible { outline: 2px solid var(--silver); outline-offset: 2px; }
.game-card-icon {
  width: 56px; height: 56px; display: grid; place-items: center; border-radius: 14px;
  background: color-mix(in srgb, var(--brand) 12%, transparent); border: 1px solid color-mix(in srgb, var(--brand) 40%, transparent); color: var(--brand-text);
  font-size: 22px; font-weight: 700;
}
.game-card-icon svg { width: 30px; height: 30px; }
.game-card-name { display: grid; gap: 2px; }
.game-card-name b { font-size: 18px; }
.game-card-name small { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--muted); }
.game-card-name .live i {
  width: 6px; height: 6px; border-radius: 50%; background: var(--loss);
  box-shadow: 0 0 8px var(--loss); animation: nav-pulse 1.6s ease-in-out infinite;
}
.game-card-go { font-size: 14px; font-weight: 600; color: var(--brand-text); }
@media (prefers-reduced-motion: reduce) {
  .game-card { transition: none; }
  .game-card:hover { transform: none; }
  .game-card-name .live i { animation: none; }
}

.home-points { display: grid; gap: 14px; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.point {
  display: grid; gap: 6px; padding: 18px; border-radius: 14px;
  background: var(--surface); border: 1px solid var(--line); box-shadow: var(--edge);
}
.point b { font-size: 15px; }
.point span { font-size: 14px; line-height: 1.5; color: var(--muted); }

/* ---------------------------------------------------------- account menu -- */
.topbar .account { position: relative; }
/* The avatar sits in a ring that fills as the player moves through their level, in their level's colour. */
.avatar-btn {
  position: relative; padding: 3px; line-height: 0; border: 0; border-radius: 50%;
  background: conic-gradient(var(--lvl, var(--brand)) calc(var(--progress, 0) * 1turn), var(--line) 0);
}
.avatar-btn:hover, .avatar-btn[aria-expanded="true"] { filter: brightness(1.15); }
.avatar-btn .avatar { box-shadow: 0 0 0 2px var(--panel); }
.avatar-level {
  position: absolute; right: -5px; bottom: -3px; min-width: 18px; height: 18px; padding: 0 4px;
  display: grid; place-items: center; border-radius: 999px; line-height: 1;
  background: var(--lvl, var(--brand)); color: var(--bg); font-size: 10px; font-weight: 800;
  box-shadow: 0 0 0 2px var(--panel);
}
.avatar { display: block; width: 36px; height: 36px; border-radius: 50%; background: var(--bg); }
.avatar-lg { width: 52px; height: 52px; border-radius: 14px; flex-shrink: 0; }

.account-menu {
  position: absolute; top: calc(100% + 10px); right: 0; z-index: 30;
  width: 300px; max-height: calc(100vh - 90px); overflow-y: auto; padding: 8px;
  background: var(--surface-raised); border: 1px solid var(--line); border-radius: 14px;
  box-shadow: var(--edge), 0 16px 40px rgba(0, 0, 0, .5); color: var(--text); font-size: 14px;
}
/* Focusable only so a click on its plain rows keeps focus inside it, rather than closing it. */
.account-menu:focus { outline: none; }
.menu-profile { display: flex; align-items: center; gap: 12px; padding: 6px 6px 12px; }
.menu-who { display: grid; flex: 1; min-width: 0; line-height: 1.35; }
.menu-who b { font-size: 14px; }
.menu-group { padding: 6px 0; border-top: 1px solid var(--line); }
.menu-label {
  padding: 6px 10px 4px; font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: var(--muted);
}
.menu-item {
  display: flex; align-items: center; gap: 12px; width: 100%; padding: 9px 10px;
  background: none; border: 0; border-radius: 8px; color: var(--text);
  font-size: 14px; text-align: left; text-decoration: none;
}
.menu-item svg { width: 18px; height: 18px; flex-shrink: 0; color: var(--muted); }
.menu-item:hover:not(:disabled), .menu-item:focus-visible { background: var(--panel-2); outline: none; }
.menu-item:hover:not(:disabled) svg, .menu-item:focus-visible svg { color: var(--text); }
.menu-item:disabled { opacity: .55; cursor: not-allowed; }
.menu-soon {
  margin-left: auto; padding: 1px 7px; border-radius: 999px; border: 1px solid var(--line);
  font-size: 10px; letter-spacing: .06em; text-transform: uppercase; color: var(--muted);
}
.menu-foot { padding-bottom: 0; }
.menu-signout, .menu-signout svg { color: var(--loss); }
.menu-item.menu-signout:hover:not(:disabled) svg, .menu-item.menu-signout:focus-visible svg { color: var(--loss); }

/* ------------------------------------------------------------ bet history -- */
.bets-page { display: grid; gap: 16px; }
.page-head { display: flex; justify-content: space-between; align-items: flex-end; gap: 16px; flex-wrap: wrap; }
.page-head h1 { margin: 0 0 4px; font-size: 26px; letter-spacing: .01em; text-transform: uppercase; }
.page-head p { margin: 0; max-width: 62ch; }
/* A page of its own, so the table takes the height it needs; narrow screens scroll it sideways. */
.scroll.tall { max-height: none; overflow-x: auto; }

/* ---------------------------------------------------------------- levels -- */
.level-top { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.xp-bar { display: block; height: 6px; border-radius: 999px; background: var(--bg); overflow: hidden; }
.xp-bar i {
  display: block; height: 100%; width: calc(var(--progress, 0) * 100%); border-radius: inherit;
  background: var(--lvl, var(--brand)); transition: width .4s ease;
}
.xp-bar-lg { height: 10px; }
@media (prefers-reduced-motion: reduce) { .xp-bar i { transition: none; } }

/* The level card at the top of the account menu. */
.menu-level {
  display: grid; gap: 6px; margin: 0 2px 8px; padding: 10px 12px; border-radius: 10px;
  background: var(--panel-2); color: var(--text); text-decoration: none;
}
.menu-level:hover, .menu-level:focus-visible { outline: none; box-shadow: inset 0 0 0 1px var(--lvl, var(--line)); }

/* A level badge beside a name, e.g. in the Crash players table. */
.lvl {
  display: inline-grid; place-items: center; min-width: 20px; height: 16px; margin-right: 6px; padding: 0 4px;
  border-radius: 999px; vertical-align: 1px; font: 700 10px/1 var(--font-body);
  color: var(--lvl); background: color-mix(in srgb, var(--lvl) 18%, transparent);
  border: 1px solid color-mix(in srgb, var(--lvl) 45%, transparent);
}

/* A large ring: the rewards page, and the level-up moment. */
.level-ring {
  flex-shrink: 0; width: 96px; height: 96px; display: grid; place-items: center; border-radius: 50%;
  background: conic-gradient(var(--lvl, var(--brand)) calc(var(--progress, 0) * 1turn), var(--line) 0);
}
.level-ring-num {
  width: 80px; height: 80px; display: grid; place-items: center; border-radius: 50%;
  background: var(--panel); color: var(--lvl, var(--brand)); font: 700 30px/1 var(--font-display);
}

.rewards-page { display: grid; gap: 16px; }
.level-card { display: flex; align-items: center; gap: 22px; }
.level-card-body { display: grid; gap: 10px; flex: 1; min-width: 0; }
.level-title { font-size: 22px; }
.rewards-grid { display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.rewards-grid p { margin: 0 0 10px; line-height: 1.55; }
@media (max-width: 560px) { .level-card { flex-direction: column; align-items: stretch; text-align: center; } .level-card .level-ring { margin: 0 auto; } }

.levelup { position: fixed; top: 76px; left: 50%; z-index: 40; transform: translateX(-50%); }
.levelup-card {
  display: grid; justify-items: center; gap: 6px; padding: 18px 28px 16px; cursor: pointer;
  border-radius: 16px;
  background: radial-gradient(100% 80% at 50% 0%, color-mix(in srgb, var(--lvl, var(--brand)) 16%, transparent), transparent 70%), var(--surface-raised);
  border: 1px solid color-mix(in srgb, var(--lvl, var(--brand)) 55%, var(--line));
  box-shadow: 0 18px 50px rgba(0, 0, 0, .5), 0 0 44px color-mix(in srgb, var(--lvl, var(--brand)) 25%, transparent);
  animation: levelup-in .45s cubic-bezier(.2, 1.4, .4, 1);
}
.levelup-ring { width: 72px; height: 72px; }
.levelup-ring .level-ring-num { width: 60px; height: 60px; font-size: 24px; }
.levelup-title { font-size: 18px; }
@keyframes levelup-in { from { opacity: 0; transform: translateY(-12px) scale(.85); } }
@media (prefers-reduced-motion: reduce) { .levelup-card { animation: none; } }

/* ---------------------------------------------------------------- chests -- */
.card-head { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }
.card-head h2 { margin-bottom: 12px; }
.menu-count {
  margin-left: auto; min-width: 20px; padding: 1px 6px; border-radius: 999px; text-align: center;
  background: var(--brand); color: var(--brand-ink); font-size: 11px; font-weight: 800;
}

.chests { display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); }
.chest-card {
  display: grid; justify-items: center; gap: 8px; padding: 16px 14px; text-align: center; border-radius: 14px;
  background: var(--bg); border: 1px solid color-mix(in srgb, var(--lvl, var(--brand)) 40%, var(--line));
}
.chest-card button { width: 100%; }
.chest-icon { display: grid; place-items: center; color: var(--lvl, var(--brand)); }
.chest-icon svg { width: 44px; height: 44px; }

/* The tier colours: the rarer, the warmer. */
.tier { font-weight: 700; }
.tier-common { --tier: #9b9ba4; } .tier-uncommon { --tier: #4ade80; } .tier-rare { --tier: #38bdf8; }
.tier-epic { --tier: #a78bfa; } .tier-legendary { --tier: #e7b847; } .tier-mythic { --tier: #f472b6; }
.tier { color: var(--tier); }

.chest-reveal {
  display: grid; justify-items: center; gap: 4px; margin-bottom: 14px; padding: 20px; border-radius: 14px; text-align: center;
  background: radial-gradient(circle at 50% 0%, color-mix(in srgb, var(--tier) 22%, transparent), transparent 70%), var(--bg);
  border: 1px solid color-mix(in srgb, var(--tier) 55%, var(--line));
  animation: reveal-in .5s cubic-bezier(.2, 1.4, .4, 1);
}
.chest-reveal .chest-icon { color: var(--tier); }
.reveal-tier { font-size: 13px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase; color: var(--tier); }
.reveal-amount { font-size: 28px; font-family: var(--font-mono); color: var(--win); }
@keyframes reveal-in { from { opacity: 0; transform: scale(.9); } }
@media (prefers-reduced-motion: reduce) { .chest-reveal { animation: none; } }

/* ---------------------------------------------------------------- weekly -- */
.weekly-grid { display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
.weekly-card, .jackpot-card { display: grid; gap: 10px; align-content: start; }
.weekly-card p, .jackpot-card p { margin: 0; line-height: 1.5; }
.weekly-big { font: 800 26px/1.15 var(--font-mono); overflow-wrap: anywhere; }
.weekly-big .coin-img, .home-jackpot-pot .coin-img { width: 22px; height: 22px; margin-right: 8px; vertical-align: -3px; }
.weekly-claim {
  display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 14px; border-radius: 12px;
  background: var(--bg); border: 1px solid color-mix(in srgb, var(--win) 45%, var(--line));
}
.weekly-claim div { display: grid; gap: 2px; min-width: 0; }
.jackpot-card { background: radial-gradient(circle at 100% 0%, color-mix(in srgb, var(--gold) 14%, transparent), transparent 60%), var(--panel); }
.jackpot-pot { color: var(--gold); }
.jackpot-last {
  display: flex; align-items: center; gap: 10px; padding: 10px 12px; border-radius: 12px;
  background: var(--bg); border: 1px solid var(--line);
}
.jackpot-last img { width: 36px; height: 36px; border-radius: 10px; flex-shrink: 0; }
.jackpot-last div { display: grid; gap: 2px; min-width: 0; }
.seed-hash { font: 11px/1.4 var(--font-mono); overflow-wrap: anywhere; color: var(--muted); }

.home-jackpot {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap; padding: 16px 20px; border-radius: var(--radius);
  color: var(--text); text-decoration: none;
  background: radial-gradient(circle at 0% 50%, color-mix(in srgb, var(--gold) 18%, transparent), transparent 55%), var(--panel);
  border: 1px solid color-mix(in srgb, var(--gold) 40%, var(--line));
}
.home-jackpot:hover { border-color: var(--gold); }
.home-jackpot-label { font-size: 12px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase; color: var(--gold); }
.home-jackpot-pot { font: 800 24px/1 var(--font-mono); }
.home-jackpot .muted { margin-left: auto; }

/* --------------------------------------------------------------- avatars -- */
.avatar.avatar-xl { width: 96px; height: 96px; border-radius: 22px; }
.avatar-now { display: flex; align-items: center; gap: 18px; margin-bottom: 12px; }
.avatar-now-body { display: grid; gap: 8px; justify-items: start; }
.avatar-style-name { font-size: 18px; }
.token-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.token-chip { padding: 4px 10px; border-radius: 999px; background: var(--panel-2); border: 1px solid var(--line); font-size: 13px; color: var(--muted); }
.token-chip b { color: var(--text); }

.profile-name { display: grid; gap: 8px; margin-bottom: 16px; }
.profile-name p { margin: 0; }
.name-row { display: flex; gap: 8px; flex-wrap: wrap; }
.name-row input { flex: 1 1 180px; min-width: 0; }
.profile-name #username-clear { justify-self: start; }

.style-grid { display: grid; gap: 8px; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); }
.style-tile {
  position: relative; display: grid; justify-items: center; gap: 6px; padding: 10px 6px 8px;
  border-radius: 12px; background: var(--bg); border: 1px solid var(--line); color: var(--text);
}
.style-tile:not(:disabled):hover { border-color: var(--silver); }
.style-tile:disabled { cursor: default; opacity: 1; }
.style-tile.current { border-color: var(--brand); box-shadow: inset 0 0 0 1px var(--brand); }
.style-img { width: 64px; height: 64px; border-radius: 14px; background: var(--panel-2); }
.style-tile.locked .style-img { filter: grayscale(1) brightness(.55); }
.style-tile.locked .style-name { color: var(--muted); }
.style-name { font-size: 12px; line-height: 1.2; text-align: center; }
.style-lock { position: absolute; top: 34px; left: 50%; transform: translateX(-50%); color: #fff; }
.style-lock svg { width: 20px; height: 20px; }
.style-current {
  position: absolute; top: 6px; right: 6px; padding: 1px 6px; border-radius: 999px;
  background: var(--brand); color: var(--brand-ink); font-size: 10px; font-weight: 800;
}
.reveal-style { margin: 6px 0 2px; }
.reveal-prize { font-size: 18px; }
/* ---------------------------------------------------------------- footer -- */
/*
 * Inside main, so it keeps main's measure and never runs under the sidebar. Not a card: a box made it one
 * more block of content to read, when it is the page's end. A rule across the top says that instead —
 * lit green where the page's own light comes from, and fading out to the right, the way the glow does.
 *
 * Left-aligned, like everything above it: centring is what made it read as a separate, decorative thing
 * rather than the last block of the page. It carries what has nowhere else to live — what the site is,
 * and that a lost key is a lost account (CLAUDE.md §9.1 asks for that in the UI, not buried in terms).
 * The navigation is already in the rail and the account menu, so it is not repeated a third time here.
 */
.site-foot {
  position: relative; margin-top: 40px; padding: 24px 0 8px;
  display: grid; gap: 20px; font-size: 13px; color: var(--muted);
}
.site-foot::before {
  content: ''; position: absolute; top: 0; left: 0; right: 0; height: 1px;
  background: linear-gradient(90deg, color-mix(in srgb, var(--brand) 55%, transparent), var(--line) 35%, transparent);
}
.site-foot p { margin: 0; }
/* What the site is, what the account is, and where to go: three columns, each at a readable measure.
   The site is described first and widest; the links need the least room. Stacked on a narrow screen. */
.site-foot-cols { display: grid; grid-template-columns: 1.3fr 1fr .8fr; gap: 20px 40px; }
.site-foot-cols section { display: grid; gap: 8px; align-content: start; min-width: 0; }
.site-foot h3 {
  margin: 0; font-size: 11px; font-weight: 600; letter-spacing: .12em; text-transform: uppercase; color: var(--text);
}
@media (max-width: 760px) { .site-foot-cols { grid-template-columns: 1fr; } }
/* One link a line: in a column they read as a list, and a list is what they are. */
.site-foot-links { display: grid; gap: 6px; justify-items: start; }
/* Where the header's dot used to live. The label is driven off the same `.offline` class ws.js sets on
   the dot, so a grey light can never sit beside the word "Connected". */
.site-foot-conn { display: flex; align-items: center; gap: 8px; }
.conn-offline { display: none; }
.dot.offline ~ .conn-online { display: none; }
.dot.offline ~ .conn-offline { display: inline; }

.credits { display: grid; gap: 14px; margin: 0 0 18px; padding: 0; list-style: none; }
.credit { display: flex; align-items: flex-start; gap: 12px; }
.credit img { flex-shrink: 0; border-radius: 10px; background: var(--panel-2); }
.credit div { display: grid; gap: 2px; min-width: 0; }
.credit pre { white-space: pre-wrap; font-size: 12px; }

/* ----------------------------------------------------------------- 404 -- */
.not-found { max-width: 520px; margin: 48px auto; }
.not-found-lead { font-size: 20px; margin: 0 0 6px; }
.button-link { display: inline-block; padding: 9px 14px; border-radius: 8px; text-decoration: none; }

/* The header dot goes grey while the socket is reconnecting, so a stale page never looks live. */
.dot.offline { background: var(--muted); box-shadow: none; }
