/* The hub — one player-facing app: account, rewards, wallet, invites, and a way
   into the game.

   ⚠ THIS LINE FIRST, AND IT IS NOT DECORATION.

   The browser's own `[hidden] { display: none }` lives in the USER-AGENT
   stylesheet, so ANY author rule setting `display` on the same element beats it
   and the `hidden` attribute silently stops working. This file sets `display`
   in dozens of rules. The wallet shipped without this line and its confirm
   sheet was on screen from first paint, covering the page and swallowing every
   tap — including its own Cancel, because hiding it was the thing that did not
   work. Every suite was green. sim/client-contract.mjs check 14 exists for it. */
[hidden] { display: none !important; }

/* ---------- the palette ----------

   The ohmygames.my brand, since 31 Aug (lucas: "try to match it"): a light
   ground, teal as the working colour, gold for money and calls to action.
   The values below are lifted from the landing page's own :root — change them
   there and here together. The three show states keep their own colours —
   red for live, teal for upcoming, violet for a layer you have not reached. */
:root {
  --bg: #f2f8f9;
  --panel: #ffffff;
  --panel-2: #f2f8f9;
  --panel-3: #ddecee;
  --line: #ddecee;
  --line-2: #c8dde0;

  --text: #13272b;
  --dim: #64818a;
  --faint: #8fa6ad;

  --teal: #02888f;
  --teal-2: #02a4ad;
  --gold: #f0b400;
  --gold-2: #ffd34d;
  --gold-dim: rgba(240, 180, 0, 0.4);
  /* Dark ink for text sitting ON a gold or teal fill — the landing page's
     button text colour, not the body text colour. */
  --ink: #142326;
  --live: #f0503c;
  --soon: #02a4ad;
  --gated: #8a5cf0;
  --good: #02a4ad;
  --bad: #f0503c;

  --r: 18px;
  --r-sm: 12px;
  --font: 'Baloo 2', 'Segoe UI', -apple-system, BlinkMacSystemFont, Roboto, sans-serif;
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 15px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  padding-bottom: calc(74px + env(safe-area-inset-bottom, 0px));
}

/* The icon sprite itself is never drawn — only its symbols are referenced. */
.sprite { display: none; }

/* Every icon on the page.

   ⚠ THE STROKE PROPERTIES MUST LIVE HERE, NOT IN THE SPRITE.

   They were first written as attributes on a <g> wrapping the symbols inside
   <defs>. That does nothing: <use> instances the <symbol> itself, not the
   ancestors it happened to be nested in, so every icon arrived with the SVG
   defaults — fill:black, no stroke — and drew as a solid blob. It shipped, and
   it was the third icon failure in this project.

   fill and stroke are INHERITED properties, so setting them on the <svg> here
   cascades into the instanced content of <use>. That is the mechanism that
   actually works, and it is also what lets `currentColor` follow the text
   colour of whatever the icon sits in. */
.ico {
  width: 20px; height: 20px; display: block; flex: 0 0 auto;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.state { padding: 56px 22px; text-align: center; color: var(--dim); }
.state p { margin: 0 0 16px; }

/* ---------- the account block ---------- */

.acct { padding: 14px 16px 0; }

/* Logo left, language buttons at the far right. */
.brandrow {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  margin-bottom: 12px;
}
.brandlogo { display: block; height: 46px; width: auto; }

/* One slim line: identity left, the points chip right. */
.idrow { display: flex; align-items: center; gap: 9px; margin-bottom: 14px; }
.idname {
  flex: 1; min-width: 0;
  display: flex; align-items: baseline; gap: 6px; overflow: hidden;
}

/* Initials, not a photo. Telegram only sometimes hands a Mini App a photo_url,
   and a broken <img> on the first screen is worse than a letter that is always
   right. */
.avatar {
  width: 34px; height: 34px; flex: 0 0 34px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 13px; font-weight: 800; letter-spacing: 0.04em;
  color: #ffffff;
  background: var(--teal-2);
  border: 2px solid var(--gold);
}
.idrow .nm {
  font-size: 15.5px; font-weight: 800; line-height: 1.15; white-space: nowrap;
}
.idrow .at {
  color: var(--faint); font-size: 12px; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}

/* ---------- the banner ---------- */

.bannerbox { position: relative; margin-bottom: 12px; }
.banner {
  display: block; width: 100%; height: auto;
  border-radius: var(--r);
  border: 1px solid var(--gold-dim);
}
/* The moving version: exactly over the picture, same box and crop, and
   invisible until it is really playing. A phone that will not play it
   (Low Power Mode, a failed load) keeps the picture, never a black box. */
.bannerbox video {
  position: absolute; top: 0; left: 0; width: 100%; height: 100%;
  box-sizing: border-box; object-fit: cover;
  border-radius: var(--r);
  border: 1px solid var(--gold-dim);
  opacity: 0; pointer-events: none;
}
.bannerbox video.playing { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .bannerbox video { display: none; } }

/* ---------- the live stream panel (STREAM.md) ----------

   Right under the banner, and only while the host is live. The frame IS the
   broadcast — the bracket page, or a game page in watch mode — so this panel
   owns nothing but the chrome: the pulsing badge, the caption, the sound tap.
   That chrome is /live-strip.css, shared with the show page so the two read
   as one (27 Sep). Taller for a match than for the table: the boards are
   portrait phone games, the table is landscape. */

#liveWrap { margin-bottom: 12px; }
.liveframewrap {
  height: 300px;
  background: #081820; /* the game pages' own dark ground — no white flash */
}
.liveframewrap.duel { height: 480px; }
.liveframewrap iframe {
  display: block; width: 100%; height: 100%; border: 0;
}

/* ---------- the announcement ticker ----------

   Sits directly under the banner and rolls through the lines set on the
   dashboard. Gold, because it is the accent this app already uses for the
   things a player is meant to look at — a second bright colour here would put
   it in competition with the balance right below it. */

.ticker {
  position: relative;
  display: flex; align-items: center; gap: 10px;
  height: 42px; padding: 0 12px 0 7px; margin-bottom: 11px;
  border-radius: var(--r);
  border: 1px solid var(--gold-dim);
  background:
    linear-gradient(90deg, rgba(240, 180, 0, 0.14), rgba(240, 180, 0, 0.04) 45%, #ffffff);
  overflow: hidden;
}

/* A highlight crossing the bar every few seconds. It is what stops a bar
   holding ONE short line from looking like a dead strip: with a single
   announcement there is barely any travel in the roll itself. */
.ticker::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(105deg, transparent 36%, rgba(255, 255, 255, 0.45) 50%, transparent 64%);
  transform: translateX(-100%);
  animation: sheen 6s ease-in-out infinite;
}
@keyframes sheen {
  0%, 58% { transform: translateX(-100%); }
  100% { transform: translateX(120%); }
}

.tbadge {
  position: relative; z-index: 1;
  width: 28px; height: 28px; flex: 0 0 28px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--gold);
  color: var(--ink);
  box-shadow: 0 0 0 3px rgba(240, 180, 0, 0.18);
}
.tbadge .ico { width: 15px; height: 15px; stroke-width: 2.4; }

/* The window the text rolls through. The mask fades both ends, so a line
   arrives and leaves rather than being chopped off by a hard edge — and the
   right-hand fade is wider because that is the side text emerges from. */
.twin {
  flex: 1; min-width: 0; overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12px, #000 calc(100% - 22px), transparent);
  mask-image: linear-gradient(90deg, transparent, #000 12px, #000 calc(100% - 22px), transparent);
}

/* ⚠ `width: max-content` is what lets the track be wider than its parent. Without
   it the flex row shrinks to the window and every line squashes instead of
   scrolling. The -50% in the roll is the other half of the trick: the track
   holds the lines TWICE, so half its width is exactly one full pass. */
.ttrack {
  display: flex; align-items: center; width: max-content;
  animation: none;
}
.ttrack.running {
  animation: ticker-enter var(--ticker-entry-time, 3s) linear both,
    roll var(--ticker-loop-time, 30s) linear var(--ticker-entry-time, 3s) infinite;
}
@keyframes ticker-enter {
  from { transform: translate3d(var(--ticker-start, 0px), 0, 0); }
  to { transform: translate3d(0, 0, 0); }
}
@keyframes roll {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(-50%, 0, 0); }
}

.tline {
  white-space: nowrap;
  font-size: 13.5px; font-weight: 620; letter-spacing: 0.005em;
  color: var(--text);
}
/* Between two announcements, so they read as separate things rather than one
   run-on sentence. */
.tsep {
  width: 5px; height: 5px; flex: 0 0 5px; border-radius: 50%;
  margin: 0 15px; background: var(--gold); opacity: 0.55;
}

/* A bar that never stops moving is exactly what this setting is asked to turn
   off. It keeps the announcements — the first one simply sits still. */
@media (prefers-reduced-motion: reduce) {
  .ttrack, .ttrack.running { animation: none; transform: none; }
  .ticker::after { display: none; }
}

/* ---------- points ----------

   The MY POINTS card is gone (31 Aug, lucas: "really wasteful, empty") — the
   balance lives in the header's chip now, and the held detail in the wallet's
   lede. What follows is the chip. */

.pointchip {
  display: flex; align-items: center; gap: 5px; flex: 0 0 auto;
  background: var(--gold); color: var(--ink);
  border-radius: 50px; padding: 5px 12px;
  font-size: 14px; font-weight: 800;
}
.pointchip .ico { width: 13px; height: 13px; stroke-width: 2.6; }
.pointchip b { font-weight: 800; letter-spacing: -0.01em; }

/* ---------- the ladder ---------- */

.ladder {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r); padding: 16px 14px 14px; margin-bottom: 11px;
}
.lhead {
  display: flex; align-items: baseline; justify-content: space-between;
  margin-bottom: 13px;
}
.ltitle {
  color: var(--text); font-size: 18px; font-weight: 800;
}
.lpos { color: var(--faint); font-size: 11.5px; font-weight: 700; letter-spacing: 0.05em; }

.tiers { display: flex; flex-direction: column; gap: 9px; }

/* One card per tier. The states are cumulative styling on the same anatomy:
   a dot, a name + subline, and (next only) a progress bar. */
.tier {
  background: var(--panel-2); border: 1px solid var(--line);
  border-radius: 13px; padding: 12px 13px;
}
.tier.here {
  border: 2px solid var(--teal-2);
  box-shadow: 0 4px 14px rgba(2, 164, 173, 0.16);
}
.tier.next { border: 2px dashed var(--gold); }
.tier.far { opacity: 0.62; }
.tier.final.far, .tier.final.next {
  background: linear-gradient(135deg, #fdf3d5, #ffffff 60%);
  border-color: var(--gold); opacity: 1;
}
.tier.final.next { border-style: dashed; border-width: 1.5px; }

.trow { display: flex; align-items: center; gap: 12px; }

.tier i {
  width: 40px; height: 40px; flex: 0 0 40px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background: var(--panel-2); border: 2px solid var(--panel-3);
  color: var(--faint);
}
.tier i .ico { width: 18px; height: 18px; stroke-width: 2.5; }
.tier.done i {
  background: var(--gold); border-color: var(--gold); color: var(--ink);
  box-shadow: none;
}
.tier.here i {
  background: #e6f6f7; border-color: var(--teal-2); color: var(--teal);
  box-shadow: none;
}
.tier.next i { background: #fdf3d5; border: 2px dashed var(--gold); color: #a97e00; }
.tier.final i { background: var(--gold); border-color: var(--gold); color: var(--ink); }

.tbody { flex: 1 1 0; min-width: 0; }
.tname {
  font-size: 13.5px; font-weight: 800; letter-spacing: 0.05em;
  text-transform: uppercase; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tier.far .tname { color: var(--dim); }
.tier.final .tname { color: #a97e00; }
.tsub { font-size: 12px; color: var(--dim); margin-top: 2px; }
.tier.far .tsub { color: var(--faint); }
.tsub.gold { color: #a97e00; font-weight: 700; }

.tpill {
  background: var(--teal-2); color: #ffffff;
  font-size: 10px; font-weight: 800; letter-spacing: 0.07em; text-transform: uppercase;
  border-radius: 999px; padding: 4px 9px; white-space: nowrap;
}
.tcount { color: var(--dim); font-size: 11.5px; font-weight: 700; white-space: nowrap; }

.tbar {
  height: 6px; border-radius: 999px; background: var(--panel-3);
  margin-top: 11px; overflow: hidden;
}
.tfill {
  height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, var(--teal-2), var(--gold));
}

.howup { margin: 13px 0 0; text-align: center; color: var(--dim); font-size: 13px; }

/* ---------- stats ---------- */

.stats {
  display: flex; align-items: stretch;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r); padding: 14px 4px; margin-bottom: 14px;
}
.stat { flex: 1 1 0; text-align: center; min-width: 0; }
.stat + .stat { border-left: 1px solid var(--line); }
.stat .line {
  display: flex; align-items: center; justify-content: center; gap: 8px;
}
.stat .line .ico { width: 22px; height: 22px; color: var(--teal); }
.stat b { font-size: 23px; font-weight: 780; letter-spacing: -0.02em; }
.stat span {
  display: block; margin-top: 3px;
  color: var(--faint); font-size: 11px; font-weight: 600;
  letter-spacing: 0.07em; text-transform: uppercase;
}

/* ---------- screens ---------- */

.screen { display: none; padding: 18px 16px 8px; }
.screen.on { display: block; }

.sechead { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
.sechead h2 {
  flex: 1; margin: 0;
  font-size: 18px; font-weight: 800; letter-spacing: 0;
}
.seeall {
  display: flex; align-items: center; gap: 3px;
  background: none; border: 0; cursor: pointer; padding: 2px;
  color: var(--gold); font-family: inherit; font-size: 13.5px; font-weight: 650;
}
.seeall .ico { width: 16px; height: 16px; }
.seeall { color: var(--teal); }

.screen .lede { color: var(--dim); font-size: 13.5px; margin: 0 0 14px; }

.list { list-style: none; margin: 0; padding: 0; }
.list li {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 0; border-bottom: 1px solid var(--line);
}
.list li:last-child { border-bottom: 0; }
.list .info { flex: 1; min-width: 0; }
.list .nm { display: block; font-weight: 600; font-size: 14.5px; }
.list .sub { display: block; color: var(--dim); font-size: 12.5px; margin-top: 2px; }
.list .cant .nm, .list .cant .sub { opacity: 0.55; }
.empty {
  color: var(--dim); font-size: 13.5px; padding: 22px 16px; text-align: center;
  background: var(--panel); border: 1px dashed var(--line-2); border-radius: var(--r-sm);
}

.tag {
  font-size: 10.5px; font-weight: 750; letter-spacing: 0.05em; text-transform: uppercase;
  padding: 4px 9px; border-radius: 999px; white-space: nowrap;
  color: var(--dim); background: var(--panel-2); border: 1px solid var(--line);
}
.tag.pending, .tag.waiting, .tag.processing { color: #a97e00; background: #fdf3d5; border-color: var(--gold-dim); }
.tag.fulfilled, .tag.earned { color: var(--teal); background: #e6f6f7; border-color: rgba(2,164,173,0.35); }
.tag.rejected { color: var(--bad); background: #fdeae7; border-color: rgba(240,80,60,0.3); }

.btn {
  font-family: inherit; font-size: 14px; font-weight: 800;
  background: var(--gold); color: var(--ink);
  border: 1.5px solid var(--gold); border-radius: 50px;
  padding: 10px 16px; cursor: pointer; white-space: nowrap;
  box-shadow: 0 4px 12px rgba(240, 180, 0, 0.3);
}
.btn.ghost {
  background: var(--panel); color: var(--teal);
  border-color: var(--teal-2); box-shadow: none;
}
.btn:disabled { opacity: 0.4; }
.btn.block { display: block; width: 100%; margin-top: 14px; padding: 13px 16px; font-size: 15px; }

/* ---------- show cards ---------- */
.card {
  padding: 14px; margin-bottom: 14px; overflow: hidden;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--r);
}
.show-summary { display: grid; grid-template-columns: 92px minmax(0, 1fr); gap: 14px; align-items: start; }
.show-summary.no-art { grid-template-columns: minmax(0, 1fr); }
.card .art { width: 92px; height: 118px; object-fit: cover; border-radius: 12px; background: var(--panel-2); }
.card .body { min-width: 0; }
.card .nm { font-weight: 800; font-size: 19px; line-height: 1.28; letter-spacing: -0.015em; white-space: normal; overflow-wrap: anywhere; word-break: break-word; }
.card .prize { color: #a97e00; font-weight: 800; font-size: 15px; margin-top: 7px; overflow-wrap: anywhere; }
.card .meta { display: flex; align-items: flex-start; gap: 6px; margin-top: 6px; color: var(--dim); font-size: 12.5px; line-height: 1.4; }
.card .meta .ico { width: 15px; height: 15px; flex-shrink: 0; margin-top: 1px; }
.spill { display: inline-block; margin-bottom: 7px; font-size: 10px; font-weight: 800; letter-spacing: 0.07em; text-transform: uppercase; padding: 4px 8px; border-radius: 6px; color: #fff; }
.spill.live { background: var(--live); }
.spill.soon { background: var(--soon); }
.spill.gated { background: var(--gated); }
.card .act { display: flex; gap: 10px; margin-top: 14px; }
.card .act > button { flex: 1 1 0; min-width: 0; min-height: 48px; padding: 11px 8px; font-size: 14px; }
.bellbtn { display: flex; align-items: center; justify-content: center; gap: 7px; font-family: inherit; font-weight: 800; border: 2px solid var(--teal); border-radius: 50px; color: #fff; background: var(--teal); cursor: pointer; }
.bellbtn .ico { width: 20px; height: 20px; flex-shrink: 0; }
.bellbtn.on { color: var(--teal); background: #e6f6f7; }
.bellbtn.on .ico { fill: currentColor; }
.bellbtn:disabled { opacity: 0.6; cursor: wait; }
.bellbtn:active { transform: scale(0.98); }
.card button:focus-visible { outline: 3px solid var(--teal-2); outline-offset: 3px; }
.card .gate { display: flex; align-items: center; justify-content: center; gap: 5px; margin-top: 14px; padding: 12px; border-radius: 12px; background: rgba(138,92,240,0.08); color: var(--dim); font-size: 13px; }
.card .gate .ico { width: 16px; height: 16px; color: var(--gated); }
.card .gate b { color: var(--gated); }

.show-countdown { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line); }
.countdown-heading { margin-bottom: 8px; color: var(--teal); font-size: 11px; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; }
.countdown-digits { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; }
.countdown-unit { min-width: 0; text-align: center; }
.countdown-label { display: block; margin-top: 5px; color: var(--dim); font-size: 10px; font-weight: 700; }
.flip-digit { --flip-height: 54px; position: relative; height: var(--flip-height); border-radius: 8px; background: #123c40; color: #fff8dc; font-size: 30px; font-weight: 800; font-variant-numeric: tabular-nums; perspective: 240px; box-shadow: 0 3px 0 #082c30; }
.flip-digit:after { content: ''; position: absolute; z-index: 5; left: 0; right: 0; top: 50%; height: 1px; background: rgba(0,0,0,0.32); pointer-events: none; }
.flip-half { position: absolute; left: 0; right: 0; height: 50%; overflow: hidden; -webkit-backface-visibility: hidden; backface-visibility: hidden; }
.flip-top, .flip-fall { top: 0; border-radius: 8px 8px 0 0; background: #123c40; transform-origin: center bottom; }
.flip-bottom, .flip-rise { bottom: 0; border-radius: 0 0 8px 8px; background: #19494d; transform-origin: center top; }
.flip-number { display: block; height: var(--flip-height); line-height: var(--flip-height); }
.flip-bottom .flip-number, .flip-rise .flip-number { transform: translateY(-50%); }
.flip-fall, .flip-rise { display: none; z-index: 3; }
.flipping .flip-fall { display: block; animation: show-flip-down 0.3s ease-in both; }
.flipping .flip-rise { display: block; animation: show-flip-up 0.3s 0.3s ease-out both; }
@keyframes show-flip-down { from { transform: rotateX(0); } to { transform: rotateX(-90deg); } }
@keyframes show-flip-up { from { transform: rotateX(90deg); } to { transform: rotateX(0); } }
@media (prefers-reduced-motion: reduce) { .flipping .flip-fall, .flipping .flip-rise { animation: none; display: none; } }
@media (max-width: 370px) { .show-summary { grid-template-columns: 76px minmax(0, 1fr); gap: 11px; } .card .art { width: 76px; height: 102px; } .card .nm { font-size: 18px; } .card .act > button { font-size: 13px; } .flip-digit { font-size: 26px; } }

/* ---------- the invite link ---------- */

.linkbox { margin-bottom: 16px; }
.linkbox .btn.block { margin-top: 0; }

/* The link itself. It wraps rather than scrolling sideways or being cut with an
   ellipsis: a player reads it to check it looks right before sending it on, and
   half a URL is not something anybody can check. */
.url {
  margin-top: 12px; padding: 12px 14px;
  background: var(--panel); border: 1px solid var(--gold-dim); border-radius: var(--r-sm);
  color: var(--teal); font-size: 13.5px; font-weight: 700;
  word-break: break-all; line-height: 1.4;
}
.urlacts { display: flex; gap: 10px; margin-top: 10px; }
.urlacts .btn { flex: 1; padding: 11px 14px; }
.urlfor { margin: 10px 0 0; color: var(--faint); font-size: 12.5px; text-align: center; }
.urlnote {
  margin: 12px 0 0; padding: 14px 16px; text-align: center;
  color: var(--dim); font-size: 13px;
  background: var(--panel); border: 1px dashed var(--line-2); border-radius: var(--r-sm);
}

/* Which group the link is into, when they are in more than one. */
.picks { list-style: none; margin: 12px 0 0; padding: 0; }
.picks li {
  display: flex; align-items: center; gap: 10px;
  padding: 13px 14px; margin-bottom: 8px; cursor: pointer;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-sm);
  font-size: 14.5px; font-weight: 600;
}
.picks li .ico { width: 16px; height: 16px; color: var(--teal); margin-left: auto; }

/* ---------- bottom nav ---------- */

.nav {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 20;
  display: flex;
  background: rgba(255, 255, 255, 0.96);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  border-top: 1.5px solid var(--line);
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
.nav button {
  flex: 1; background: transparent; border: 0; cursor: pointer;
  color: var(--faint); font-family: inherit; font-size: 11px; font-weight: 600;
  padding: 10px 2px 11px;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  transition: color 0.15s;
}
.nav button .ico { width: 22px; height: 22px; }
.nav button.on { color: var(--teal); }

/* ---------- confirm sheet ---------- */

.sheet {
  position: fixed; inset: 0; z-index: 40;
  display: flex; align-items: flex-end;
  background: rgba(19, 39, 43, 0.45);
}
.sheet .inner {
  width: 100%; background: var(--panel);
  border-radius: 20px 20px 0 0;
  padding: 22px 20px calc(22px + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--line-2);
  /* A full-height prize picture must never push Close off the screen — that is
     the wallet's swallowed-Cancel bug in a different costume. */
  max-height: 88vh; overflow-y: auto;
}
.sheet h3 { margin: 0 0 8px; font-size: 17.5px; font-weight: 700; }
.sheet p { margin: 0 0 18px; color: var(--dim); font-size: 13.5px; }
.sheet .row { display: flex; gap: 10px; }
.sheet .row .btn { flex: 1; padding: 13px 16px; }

/* ---------- the reward grid ----------

   Two across. A prize is a thing you look at before you want it, and a row
   with a 46px thumbnail gives it about as much presence as a line of text. */
.pgrid {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: 1fr 1fr; gap: 11px;
}
.pcard {
  display: flex; flex-direction: column;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r); padding: 10px; cursor: pointer;
}
.pcard .pimg {
  /* Square: the back office asks for 800 × 800 photos, and 4:3 cut their top and bottom off. */
  display: block; width: 100%; aspect-ratio: 1 / 1; object-fit: cover;
  border-radius: var(--r-sm); background: var(--panel-2);
  border: 1px solid var(--line); margin-bottom: 9px;
}
.pcard .pname {
  font-weight: 650; font-size: 14px; line-height: 1.25;
  /* Two lines, then an ellipsis: the cards are a grid and a third line would
     shove the button below its neighbour's. */
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
  /* ⚠ AND ALWAYS TWO LINES HIGH, whether the name needs them or not.
     `2 lines × 1.25 line-height`, in em so it tracks the font size above rather
     than being a pixel number that has to be remembered when that changes.

     Names are whatever the operator typed. "Grab RM50 Voucher" is one line and
     "Dominos RM50 Voucher" is two, so side by side the price, the availability
     line and the button on the short card all sat a line higher than its
     neighbour's — every card in the row bottoming out somewhere different.
     Reserving the space the clamp already allows is what makes the row line up
     without ever giving up a line the name would have used. */
  min-height: 2.5em;
}
.pcard .pcost { color: #a97e00; font-weight: 800; font-size: 13.5px; margin-top: 4px; }
/* Why it cannot be tapped — "sold out" and "2,000 more needed" are completely
   different messages and only one of them is the player's to do anything
   about. Pushed to the bottom so every button in the row lines up. */
.pcard .pneed { color: var(--faint); font-size: 12px; margin: 2px 0 10px; }
/* ⚠ `margin-top: auto` AND NOTHING AFTER IT THAT SETS margin-top. This rule
   read `margin-top: auto; … ; margin-top: 10px`, and the later declaration in
   the same block simply wins — so the button was never pushed anywhere and the
   auto was decoration. Grid rows stretch every card to the tallest in the row,
   which means auto is what pins the button to the bottom of that shared height
   no matter how much text is above it. The gap above it is the padding-bottom
   of the line before, not a margin here. */
.pcard .btn { margin-top: auto; width: 100%; padding: 9px 10px; }
.pcard.cant .pimg { opacity: 0.45; }
.pcard.cant .pname { color: var(--dim); }

/* A gold button a player cannot press still reads as a button. Disabled ones
   step out of the accent entirely rather than just fading. */
.btn:disabled {
  background: transparent; color: var(--faint);
  border-color: var(--line-2); opacity: 1;
}

/* ---------- the prize sheet ---------- */

.dimg { margin: -4px 0 14px; }
/* ⚠ The WHOLE picture, not a crop of it. This was object-fit:cover under a
   210px cap, which cut the top and bottom off artwork that was designed as one
   piece — the price and the terms are often IN the image. `height:auto` lets it
   be whatever shape it was drawn at; the sheet scrolls if that is tall. */
.dimg img {
  display: block; width: 100%; height: auto;
  border-radius: var(--r-sm); border: 1px solid var(--line-2);
}
.dcost { color: #a97e00; font-weight: 750; font-size: 15px; margin-bottom: 12px; }
.dtext { color: var(--dim); font-size: 14px; margin: 0 0 14px; }
.dfact {
  display: flex; align-items: flex-start; gap: 9px; margin-bottom: 10px;
  color: var(--dim); font-size: 13px; line-height: 1.4;
}
.dfact .ico { width: 16px; height: 16px; color: var(--teal); margin-top: 1px; }

/* A reward row is tappable now, so it needs to look it. */
.list li.tappable { cursor: pointer; }
.thumb {
  width: 46px; height: 46px; flex: 0 0 46px; border-radius: 10px;
  object-fit: cover; background: var(--panel-2); border: 1px solid var(--line);
}

/* ---------- toast ---------- */

.toast {
  position: fixed; left: 50%; bottom: calc(88px + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%); z-index: 50;
  background: var(--panel); border: 1.5px solid var(--line-2);
  color: var(--text); padding: 11px 17px; border-radius: 12px;
  font-size: 13.5px; max-width: 88vw; text-align: center;
  box-shadow: 0 12px 34px rgba(19, 39, 43, 0.18);
}
.toast.err { border-color: var(--bad); }

/* ---------- the earning history (currency step 6) ---------- */

.histhead { margin-top: 24px; }
.hamt { font-weight: 800; font-size: 14.5px; white-space: nowrap; }
.hamt.plus { color: var(--teal); }
.hamt.minus { color: var(--bad); }

/* Three stats across a narrow phone. */
@media (max-width: 370px) {
  .tier i { width: 34px; height: 34px; }
  .stat b { font-size: 20px; }
  .stat .line .ico { width: 18px; height: 18px; }
}

/* ---------- the arcade (ARCADE.md) ---------- */
.arcade { margin-bottom: 14px; }
.arcnote { font-size: 12.5px; color: var(--dim); }
.arcgrid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 11px; }
.arctile {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r); overflow: hidden;
  display: flex; flex-direction: column;
}
.arctile[hidden] { display: none; }
/* The game pages' own dark ground, so the tile reads as a door into them. */
.arcart {
  height: 104px; background: radial-gradient(120% 90% at 50% 0%, #0e2b38, #081820);
  display: flex; align-items: center; justify-content: center;
}
.arcart svg { width: 120px; height: 80px; }
.arcbody { padding: 11px 12px 12px; display: flex; flex-direction: column; gap: 8px; }
.arcbody b { font-weight: 700; font-size: 16px; line-height: 1.2; }
.arcsub { font-size: 12.5px; color: var(--faint); line-height: 1.2; }
.arcbody .btn { min-height: 44px; padding: 9px 16px; }
.arcleft { margin: 10px 0 0; font-size: 12.5px; color: var(--faint); }

/* Free solo challenges are independent of the point-staked Arcade switch.
   Each card uses its own game's art; no active renderer/iframe is loaded. */
.challenges { margin:24px 0 16px; }
.challenges .sechead { margin-bottom:5px; }
.challenge-lede { margin:0 0 12px; color:var(--dim); font-size:13px; }
.challenge-leaderboard { display:flex; align-items:center; gap:14px; min-height:88px; margin:0 0 18px; padding:16px; border:1px solid var(--gold,#ffd059); border-left:4px solid var(--gold,#ffd059); border-radius:18px; background:linear-gradient(115deg,#ffd05918,#153e43 70%); box-shadow:inset 0 1px 0 #fff2bb22,0 5px 18px #001b2233; color:var(--gold,#ffd059); text-decoration:none; }
.challenge-leaderboard-icon { display:grid; place-items:center; flex:0 0 48px; width:48px; height:48px; border-radius:14px; border:1px solid #ffe89b; background:linear-gradient(145deg,#ffe897,#ffd059); color:#173e39; box-shadow:0 3px 0 #9b7b2d; }
.challenge-leaderboard-icon .ico { width:28px; height:28px; }
.challenge-leaderboard-copy { min-width:0; }
.challenge-leaderboard-copy strong { display:block; font-size:21px; font-weight:800; line-height:1.2; overflow-wrap:anywhere; }
.challenge-leaderboard-copy>span { display:block; margin-top:5px; font-size:12px; font-weight:600; letter-spacing:.04em; color:var(--text,#edf6ee); }
.challenge-leaderboard:focus-visible { outline:3px solid var(--teal,#74dcd0); outline-offset:4px; }
@media (hover:hover) { .challenge-leaderboard:hover { background:linear-gradient(115deg,#ffd0592b,#1a494b 70%); border-color:#ffe897; } }
@media (max-width:359px) { .challenge-leaderboard { padding:13px; gap:11px; }.challenge-leaderboard-copy strong { font-size:19px; } }
.challenge-card .arcbody { flex:1; }
.challenge-card .arcsub { min-height:30px; line-height:1.35; }
.challenge-card a.btn { display:flex; align-items:center; justify-content:center; text-decoration:none; margin-top:auto; }
.challenge-card a.btn:focus-visible { outline:3px solid var(--gold); outline-offset:-4px; }
.challenge-art { height:144px; display:grid; place-items:center; overflow:hidden; position:relative; }
.challenge-stack { background:#b9edf0; }
.challenge-stack img,.challenge-stack video { position:absolute; inset:0; width:100%; height:100%; object-fit:contain; }
.challenge-stack video { opacity:0; pointer-events:none; }
@media(prefers-reduced-motion:reduce){.challenge-stack video{display:none}}
.challenge-memory { background:#06484c url('/memory-preview/art/table.webp?v=1') center/cover; }
/* The third challenge spans the row: art beside text, the same art size. */
.challenge-wide { grid-column:1 / -1; flex-direction:row; }
.challenge-wide .challenge-art { flex:0 0 calc(50% - 5.5px); height:auto; min-height:144px; }
.challenge-hop { background:#95d5d4 url('/hop/art/sky-v1.webp') center 70%/cover; }
.challenge-frog { position:absolute; left:calc(50% - 44px); bottom:10px; width:88px; height:88px; background:url('/hop/art/frogs-v1.webp') 33.333% 0/400% 200% no-repeat; }
.challenge-pairs { width:109px; display:grid; grid-template-columns:1fr 1fr; gap:9px; transform:rotate(-8deg); }
.challenge-pairs i { position:relative; aspect-ratio:1; border-radius:11px; perspective:350px; }
.challenge-flip-inner { position:absolute; inset:0; transform-style:preserve-3d; }
.challenge-pairs i:first-child .challenge-flip-inner,.challenge-pairs i:last-child .challenge-flip-inner { transform:rotateY(180deg); }
.challenge-face { position:absolute; inset:0; border-radius:11px; border:2px solid #d9b36b; box-shadow:0 3px 0 #977945,0 6px 7px #001f2677; backface-visibility:hidden; -webkit-backface-visibility:hidden; }
.challenge-pairs .cherry,.challenge-pairs .shell { transform:rotateY(180deg); background:#f7eed9 url('/memory-preview/art/collectibles.webp?v=1') 0 0/300% 300%; }
.challenge-pairs .shell { background-position:100% 0; }
.challenge-flip:after { content:''; position:absolute; inset:-2px; border-radius:12px; border:2px solid #ffe398; box-shadow:0 0 12px #ffd26cbb; opacity:0; pointer-events:none; }
.challenge-pairs .back { display:grid; place-items:center; background:linear-gradient(145deg,#21848b,#06434b); color:#f1d393; font-style:normal; font-size:16px; font-weight:800; text-shadow:0 2px #78592b; }

/* Prize-brand logos retain their original colours and clear space. */
.official-brands { margin:32px 0 12px; padding-top:12px; }
.official-brands h2 {
  display:flex; align-items:center; justify-content:center; gap:14px;
  margin:0 0 18px; color:var(--gold); font-size:20px; font-weight:800;
  line-height:1.35; letter-spacing:1.2px; text-align:center;
}
.official-brands h2::before, .official-brands h2::after {
  content:""; flex:1 1 24px; height:1px;
  background:linear-gradient(90deg,transparent,var(--gold-dim));
}
.official-brands h2::after { transform:rotate(180deg); }
.official-brand-logos { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:9px; }
.official-brand-logos a { display:flex; align-items:center; justify-content:center; min-height:76px; padding:14px 10px; background:transparent; }
.official-brand-logos img { display:block; width:100%; height:46px; object-fit:contain; }
:root .survey-entry{display:flex;align-items:center;gap:14px;padding:18px;margin:22px 0;border:1px solid #eacb82;border-radius:18px;background:#18474b;color:#fff3d1;text-decoration:none}.survey-entry>span:nth-child(2){flex:1;min-width:0}.survey-entry strong{display:block;font-size:18px}.survey-entry small{display:block;margin-top:4px;color:#c0d8cf;font-size:13px}.survey-entry-icon{font-size:28px;color:#f1cc80}.survey-entry:focus-visible{outline:3px solid #f1cc80;outline-offset:3px}
