/* Public arcade hub stylesheet for the vanilla-TS player. A VERBATIM port of
   frontend/src/app/pages/hub/hub.component.scss - every value (px, color, gradient,
   transition, max-height/opacity collapse timing, grid gap, padding) is copied
   unchanged; nothing visual is altered.

   Wrapper strategy (per backend/docs/arcade/SPEC_CSS.md sections 5 and 1B): the Angular
   component was ViewEncapsulated, so its :host block and every .mf-* rule were auto-scoped.
   In vanilla there is no encapsulation, so:
     - the :host { ... } block (the --mf-* token overrides + display/width/height/font-family
       layout) moves onto the page-root wrapper class .arcade-hub, and
     - every hub-component-local selector (all .mf-hub-*, the .mf-board-overlay/.mf-board-sheet/
       .mf-board-mount overlay wrappers, all .mf-set-*, and the hub's own .mf-brand-mire/
       .mf-brand-games lockup spans) is prefixed with .arcade-hub so the rules cannot leak
       globally and win by specificity over the OLDER hub variant carried in shell.css
       (which has a per-card accent border + 12px gap - this live design uses 10px gap, no
       accent edge, a gear, and name-below-banner).
   The SHARED kit classes the mounted leaderboard panel reads (.mf-card, .mf-btn*, .mf-toggle*,
   .mf-list*, .mf-board-row/.mf-board-rank/.mf-board-avatar/.mf-board-name/.mf-board-score/
   .mf-board-level/.mf-board-me, etc.) are NOT in this file: they come globally from shell.css
   (a verbatim slice also in leaderboard-shared.css) and must stay UNWRAPPED so the mounted
   board reads them. Only the board OVERLAY positioning wrappers below (mf-board-overlay/sheet/
   mount), which live in hub.component.scss, are reproduced here - and the overlay uses
   position:fixed; inset:0 so it still covers the viewport even though it is .arcade-hub-scoped.

   The --mf-* tokens are declared on .arcade-hub (the former :host) so they inherit into both
   the hub DOM and the mounted board panel mounted inside it. (shell.css also declares the full
   --mf-* set on :root; re-asserting the subset here matches the source and keeps the hub true
   if it ever loads in isolation.) Loads fourth in the order base -> tokens -> shell -> hub -> play.
   The build-player.mjs step auto-copies styles/*.css into the dist root; the <link> is added
   by the composer, not here. */

/* :host -> .arcade-hub. The --mf-* token overrides + the box/type layout the host carried. */
.arcade-hub {
  --mf-bg: #10131c;
  --mf-bg-2: #1c2230;
  /* the page + header fill. NIGHT (dark navy) is now the DEFAULT; an optional DAY
     (warm parchment) theme is opted into via :root[data-theme="day"] .arcade-hub
     below. The theme is set by a data-theme attribute on <html> (index.ts applies
     and persists the choice); absence/unknown = night. */
  --mf-page-bg: #1c2230;
  --mf-surface: rgba(28, 34, 48, 0.86);
  /* the flatter row fill, the soft accent wash and the faint hairline the mounted
     kit leaderboard card reads; lifted straight from the kit shell :root so the
     card renders true inside the hub the same way it does in a game bundle */
  --mf-surface-flat: rgba(16, 19, 28, 0.4);
  --mf-accent-soft: rgba(184, 168, 216, 0.14);
  --mf-faint: rgba(255, 255, 255, 0.12);
  --mf-ink: #eef1f7;
  --mf-ink-dim: rgba(255, 255, 255, 0.55);
  --mf-accent: #b8a8d8;
  --mf-card-border: rgba(184, 168, 216, 0.18);
  --mf-radius: 14px;

  display: block;
  width: 100%;
  /* a fixed viewport height makes the hub its own scroll container, which is
     what lets the toolbar position:sticky actually stick. --tg-viewport-height
     tracks the Telegram fullscreen height (100vh stayed pinned to the static
     pre-fullscreen box on iOS and letterboxed); 100dvh is the web fallback. */
  height: var(--tg-viewport-height, 100dvh);
  font-family: system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif;
}

/* ***************************************************************
 * DAY theme (optional, opt-in)
 * *************************************************************** */

/* OPTIONAL warm-parchment DAY theme, opted into by data-theme="day" on <html>.
   hub.css re-declares the --mf-* tokens ON .arcade-hub, so those beat any
   :root[data-theme] tokens shell.css sets — the day token overrides MUST therefore
   be re-declared at this .arcade-hub-scoped selector to win inside the hub. NIGHT
   (no attribute / data-theme="night") keeps the dark default block above untouched. */
:root[data-theme="day"] .arcade-hub {
  --mf-page-bg: #faf9f5;
  --mf-bg: #faf9f5;
  --mf-bg-2: #efe9d9;
  --mf-surface: #ffffff;
  --mf-surface-flat: #f1eee7;
  --mf-ink: #2c2a26;
  --mf-ink-dim: #5c5850;
  --mf-faint: #e6e2d9;
  --mf-accent: #880e4f;
  --mf-accent-soft: rgba(136, 14, 79, 0.10);
  --mf-card-border: #e6e2d9;
  /* Paint the parchment fill on the wrapper itself in day mode. The scroller
     (.mf-hub) is made transparent below so the fixed doodle pseudo-element shows
     through between this fill and the cards instead of being hidden by an opaque
     scroller background. */
  background: var(--mf-page-bg);
}

/* DAY-only doodle wallpaper: a faded, repeating Telegram/WhatsApp-style line-art
   tile sat BEHIND every hub element. position:fixed pins it to the viewport so it
   reads as a calm backdrop without scroll jank; pointer-events:none keeps the cards
   and controls fully tappable; z-index:0 (with the scroller lifted to z-index:1
   below) keeps it strictly behind content so it never reduces readability. NIGHT
   never emits this pseudo-element, so the dark theme is unchanged. */
:root[data-theme="day"] .arcade-hub::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: url('/assets/shared/doodle-bg.webp');
  background-repeat: repeat;
  background-size: 460px;
  opacity: 0.2;
}

/* Lift the hub scroller above the day doodle so cards, grid and the sticky header
   all paint over the pattern. Scoped to day so night layering is untouched; the
   sticky header (.mf-hub-tools z-index:5) keeps its own higher stacking inside. */
:root[data-theme="day"] .arcade-hub .mf-hub {
  position: relative;
  z-index: 1;
  /* transparent in day so the wrapper parchment fill + the fixed doodle behind
     show through; the opaque navy fill is kept for night via the base rule */
  background: transparent;
}

.arcade-hub .mf-hub {
  position: relative;
  width: 100%;
  height: 100%;
  box-sizing: border-box;
  overflow-y: auto;
  /* Hide the scrollbar entirely (still scrollable by wheel / touch) so it never
     takes layout width. That keeps the tool row's left and right edge gaps equal
     (the scrollbar would otherwise eat the right side), and toggling Favorites
     never widens the content box / zooms the cards. */
  scrollbar-width: none;
  /* Ride the brand lockup at the very top: only the device safe-area inset plus a
     small 8px breathing gap (no extra static clearance). On web that inset is 0 so
     the lockup pins right to the top; a notch / status bar is still respected. */
  padding: calc(env(safe-area-inset-top) + 8px) 16px max(24px, env(safe-area-inset-bottom));
  background: var(--mf-page-bg);
  color: var(--mf-ink);
}

/* The settings gear, sitting at the right end of the tool row just past the
   favorites chip — a 42×42 icon button matching the chip / search height. */
.arcade-hub .mf-hub-gear {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  padding: 0;
  color: var(--mf-ink);
  background: var(--mf-surface);
  border: 1px solid var(--mf-card-border);
  border-radius: 12px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.arcade-hub .mf-hub-gear:active {
  background: var(--mf-bg-2);
}

/* The brand lockup, shown in the sticky header top row */
.arcade-hub .mf-hub-lockup {
  display: flex;
  align-items: center;
  gap: 9px;
}

.arcade-hub .mf-hub-mark {
  display: block;
  height: 30px;
  width: 30px;
  /* the square brand monogram, the dark-background variant for the night theme */
  background: url('/assets/brand/trademire-icon-dark.svg') center / contain no-repeat;
}

/* day theme: swap the faded dark-background icon for the exact-brand-color day icon
   (#841B3C bordeaux circles + #746A82 grey figure) so the mark matches the day
   wordmark colours, never the washed-out dark variant on the light wallpaper */
:root[data-theme="day"] .arcade-hub .mf-hub-mark {
  /* ONE logo regardless of theme: day uses the SAME pinkish dark-variant icon as
     night (owner: apply the night look to day, single logo both modes) */
  background-image: url('/assets/brand/trademire-icon-dark.svg');
}

.arcade-hub .mf-hub-word {
  display: flex;
  align-items: baseline;
  gap: 5px;
  font-size: 20px;
  font-weight: 800;
  letter-spacing: 0.3px;
}

.arcade-hub .mf-brand-mire {
  color: #d96f8a;
}

.arcade-hub .mf-brand-games {
  color: #b8b0c2;
}

/* the stats row under the arcade title: the crown tally and the coins pill side by
   side, so the two totals read together as one compact stat bar */
.arcade-hub .mf-hub-stats {
  display: inline-flex;
  align-items: center;
  gap: 14px;
}

/* The arcade-wide crown tally, shown on the right of the sticky header top row */
.arcade-hub .mf-hub-total-crowns {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-weight: 800;
  color: var(--mf-gold);
}

/* the total-coins pill, stacked right under the crown tally (the subrow is a centered
   column): the gold jeton mark + the player's shared-economy balance, in the branded
   jeton gold so it reads as the account wallet shared across every game */
.arcade-hub .mf-hub-total-coins {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-weight: 800;
  color: #f7c948;
}

/* the referral tally pill, the third stat beside crowns and coins: the gold gift mark
   + the player's qualified-invite count. Hidden (mf-hidden) until the relay profile
   resolves a non-zero count, the same non-zero-only convention as the other pills. */
.arcade-hub .mf-hub-total-referrals {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-weight: 800;
  color: var(--mf-gold);
}

/* The invite banner — the growth CTA that rides the scroll content directly under the
   sticky header. A full-width tappable card: the gift mark, the headline + live
   progress subline, and a gold CTA chip. Gold-bordered so it reads as the reward /
   invite surface without shouting over the catalog. Hidden outside Telegram. */
.arcade-hub .mf-hub-invite {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  box-sizing: border-box;
  margin: 0 0 14px;
  padding: 12px 14px;
  font-family: inherit;
  text-align: left;
  background: var(--mf-surface);
  border: 1px solid var(--mf-gold);
  border-radius: 14px;
  cursor: pointer;
}

.arcade-hub .mf-hub-invite-icon {
  flex: 0 0 auto;
  font-size: 24px;
  line-height: 1;
}

.arcade-hub .mf-hub-invite-text {
  flex: 1 1 auto;
  min-width: 0;
}

.arcade-hub .mf-hub-invite-title {
  font-size: 14px;
  font-weight: 800;
  color: var(--mf-ink);
}

.arcade-hub .mf-hub-invite-sub {
  margin-top: 2px;
  font-size: 12px;
  color: var(--mf-ink-dim);
}

.arcade-hub .mf-hub-invite-cta {
  flex: 0 0 auto;
  padding: 8px 14px;
  font-size: 13px;
  font-weight: 800;
  /* brand bordeaux on the gold chip — the same readable pairing the coin mark uses */
  color: #841b3c;
  background: var(--mf-gold);
  border-radius: 10px;
  white-space: nowrap;
}

/* The community footer — a quiet bottom strip of social-channel links, separated from
   the grid by a hairline. Secondary by design (the invite banner is the primary growth
   lever), so it is low-emphasis and centered. */
.arcade-hub .mf-hub-community {
  max-width: 720px;
  margin: 8px auto 20px;
  padding: 16px 12px 0;
  text-align: center;
  border-top: 1px solid var(--mf-card-border);
}

.arcade-hub .mf-hub-community-caption {
  margin-bottom: 10px;
  font-size: 12px;
  color: var(--mf-ink-dim);
}

.arcade-hub .mf-hub-community-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
}

/* the footer channel buttons are round icon-buttons (the brand glyph only); the icon
   is currentColor so it tints with the theme and the active state */
.arcade-hub .mf-hub-community-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  color: var(--mf-ink-dim);
  background: var(--mf-surface);
  border: 1px solid var(--mf-card-border);
  border-radius: 50%;
  cursor: pointer;
}

.arcade-hub .mf-hub-community-link:active {
  color: var(--mf-ink);
  border-color: var(--mf-gold);
}

/* the Community channel buttons in the settings sheet share the language-pill shape
   (.mf-set-lang) but center a brand icon instead of text. The compound selector keeps
   the icon centering + tint winning over the base pill rule regardless of source
   order, since the button carries both classes. */
.arcade-hub .mf-set-lang.mf-set-social {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 52px;
  padding: 0 14px;
  color: var(--mf-ink-dim);
}

.arcade-hub .mf-set-lang.mf-set-social:active {
  color: var(--mf-ink);
}

/* The branded header + search toolbar, pinned to the top. Its fill is the page's
   own base background colour (the same --mf-bg the .mf-hub gradient starts from)
   and it carries NO drop shadow, so the header reads as part of the page rather
   than a separate bar — there is no seam line under it. It stays opaque so the
   grid never bleeds through the pinned header while the long list scrolls under it.
   Flush at the bottom (no bottom padding); the tool row bleeds to the page edges. */
.arcade-hub .mf-hub-tools {
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex;
  flex-direction: column;
  /* explicit stretch: the kit shell.css `.mf-hub-tools` sets align-items:center,
     which (since we only override flex-direction) would otherwise leak in and
     center+shrink each row to its content width — that is what stopped the search
     from filling the row and the tool row from bleeding to the edges. Stretch makes
     every row span the full header width so the search grows and the bleed works. */
  align-items: stretch;
  /* flexible full width: no fixed cap, so the header band spans the whole content
     column edge to edge on any device (was capped at 720px which left big doodle
     margins beside it on wide screens). */
  max-width: none;
  /* bleed the parchment band fully to the screen edges: the -16px side margins
     cancel the .mf-hub 16px side padding so the background touches both edges with
     no gap, and the matching 16px side padding re-insets the content so the brand,
     subtitle and tool row stay exactly where they were (the toolrow -13px bleed
     still resolves to the same 3px edge gap). */
  margin: 0 -16px 12px;
  padding: 12px 16px 2px;
  background: var(--mf-page-bg);
  /* explicitly none: the kit shell.css ships a `.mf-hub-tools` rule with a drop
     shadow, and without this override that shadow leaks in and draws a seam line
     under the header. The header must read as part of the page, so: no shadow. */
  box-shadow: none;
}

/* Extend the opaque bar up over the Telegram-clearance zone, so once the header
   pins there is never a transparent gap above it where the scrolling grid shows
   through. Sits behind the brand row and below the gear (which is z-index 6). */
.arcade-hub .mf-hub-tools::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 100%;
  height: calc(max(24px, env(safe-area-inset-top)) + 64px);
  background: var(--mf-page-bg);
}

/* brand row: the Mire Games mark, centered and always pinned at the top */
.arcade-hub .mf-hub-brandrow {
  display: flex;
  justify-content: center;
}

/* subtitle row: the arcade label over the crown tally, centered under the brand.
   Collapses smoothly when the list is scrolled, leaving just the brand and the
   search pinned. A premium ease, not a hard cut.

   THE PREMIUM SCROLL FIX (the cause of the web.telegram search-bar / screen shake):
   the OLD collapse was a bare `max-height: 64px -> 0` transition. That reflowed every
   animation frame AND shrank the sticky header's flow height mid-scroll, which shrank
   the total scroll content; the browser then re-seated scrollTop, the re-seat fired
   another scroll event, the collapse flipped again => it oscillated and the whole
   screen jittered. The 18px-on / 6px-off band sat right where Telegram's momentum /
   rubber-band scroll lives, so the oscillation was constant.

   Two changes kill it: (1) the visible fold is now carried by a GPU-composited
   `transform: scaleY()` + `opacity` (run on the compositor, zero reflow), so the motion
   the eye follows never touches layout; the max-height/margin still release the box so
   the search rides up with no gap and no clip, but they only SETTLE the box, they no
   longer ARE the animation. (2) the index.ts side flips `.scrolled` at most once per
   animation frame (rAF-throttled) with a WIDE 64px-on / 24px-off dead-band kept far
   from the very top, so a momentum-scroll burst near 0 can never straddle a threshold
   and oscillate the box-release. transform-origin: top folds it up into the brand row;
   will-change keeps the transform/opacity on their own layer so a phone GPU composites
   the fold cheaply. */
.arcade-hub .mf-hub-subrow {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  overflow: hidden;
  /* max-height caps (does not stretch) the natural content, so expanded there is
     never a gap and never a clip. Sized for THREE stacked lines now — the arcade
     title, the crown tally AND the total-coins pill under it (~72px content) — so the
     coins line is no longer clipped by the cap. The box still releases its space on
     collapse (so the search rides up cleanly), but the index.ts side flips it AT MOST
     once per animation frame (rAF) with a WIDE dead-band kept far from the very top,
     so the box-release transition settles once per crossing instead of thrashing
     against momentum scroll near 0. */
  max-height: 96px;
  margin-top: 7px;
  opacity: 1;
  transform-origin: top center;
  /* the transform + opacity are the GPU-composited motion the eye follows (no reflow);
     max-height + margin-top settle the box once underneath them. Premium ease. */
  transition:
    transform 0.3s cubic-bezier(0.22, 0.61, 0.36, 1),
    opacity 0.22s ease,
    max-height 0.34s cubic-bezier(0.22, 0.61, 0.36, 1),
    margin-top 0.34s cubic-bezier(0.22, 0.61, 0.36, 1);
  will-change: transform, opacity;
}

.arcade-hub .mf-hub-tools.scrolled .mf-hub-subrow {
  max-height: 0;
  margin-top: 0;
  opacity: 0;
  transform: scaleY(0) translateY(-10px);
}

/* the Oyun Salonu arcade label inside the subtitle row */
.arcade-hub .mf-hub-arcade {
  margin: 0;
  font-size: 18px;
  font-weight: 700;
  color: var(--mf-ink);
  text-align: center;
}

/* search row: the search input, the favorites toggle and the settings gear. It
   bleeds out past the .mf-hub 16px side padding (negative side margins) so the
   search sticks flush to the left edge and the gear flush to the right edge. */
.arcade-hub .mf-hub-toolrow {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 12px;
  /* 3px gap each side: .mf-hub pads 16px, so -13px leaves a 3px edge gap */
  margin-left: -13px;
  margin-right: -13px;
}

.arcade-hub .mf-hub-search {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 42px;
  box-sizing: border-box;
  padding: 10px 14px;
  font-family: inherit;
  font-size: 15px;
  color: var(--mf-ink);
  background: var(--mf-surface);
  border: 1px solid var(--mf-card-border);
  border-radius: 12px;
  outline: none;
}

.arcade-hub .mf-hub-search::placeholder {
  color: var(--mf-ink-dim);
}

.arcade-hub .mf-hub-search:focus {
  border-color: var(--mf-accent);
}

.arcade-hub .mf-hub-favchip {
  flex: 0 0 auto;
  min-height: 42px;
  padding: 0 14px;
  font-family: inherit;
  font-size: 14px;
  font-weight: 700;
  color: var(--mf-ink-dim);
  background: var(--mf-surface);
  border: 1px solid var(--mf-card-border);
  border-radius: 12px;
  cursor: pointer;
}

.arcade-hub .mf-hub-favchip.on {
  color: var(--mf-gold);
  border-color: var(--mf-gold);
}

/* Loading, error and empty state lines */
.arcade-hub .mf-hub-state,
.arcade-hub .mf-hub-empty {
  max-width: 720px;
  margin: 24px auto;
  text-align: center;
  color: var(--mf-ink-dim);
  font-size: 14px;
}

.arcade-hub .mf-hub-empty {
  grid-column: 1 / -1;
}

.arcade-hub .mf-hub-retry {
  margin-left: 10px;
  padding: 8px 16px;
  font-family: inherit;
  font-weight: 700;
  color: var(--mf-ink);
  background: var(--mf-surface);
  border: 1px solid var(--mf-card-border);
  border-radius: 10px;
  cursor: pointer;
}

/* The two-column game grid: minmax keeps two cards per row on a phone */
.arcade-hub .mf-hub-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 10px;
  max-width: 720px;
  margin: 0 auto;
}

.arcade-hub .mf-hub-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 16px;
  text-decoration: none;
  background: var(--mf-surface);
  /* one uniform, calm border on every card. No per-game accent edge, so the
     grid reads clean and the colorful hero art is the only color, not a chaos
     of clashing card outlines. */
  border: 1px solid var(--mf-card-border);
  border-radius: var(--mf-radius);
  transition: transform 0.1s ease, background 0.15s ease, box-shadow 0.2s ease;
}

/* A filtered-out card must actually leave the layout. The card sets display:flex,
   which is an author rule that would otherwise beat the plain [hidden] attribute,
   so the favorites and search filters would visually do nothing. This author rule
   at attribute specificity restores the hide. */
.arcade-hub .mf-hub-card[hidden] {
  display: none;
}

.arcade-hub .mf-hub-card:hover {
  background: rgba(28, 34, 48, 0.96);
  transform: translateY(-2px);
}

.arcade-hub .mf-hub-card strong {
  font-size: 15px;
  font-weight: 700;
  color: var(--mf-ink);
}

.arcade-hub .mf-hub-card span {
  font-size: 12px;
  line-height: 1.4;
  color: var(--mf-ink-dim);
}

/* Art cards carry the hero banner edge to edge above the text block */
.arcade-hub .mf-hub-card-art {
  padding: 0;
  gap: 0;
  overflow: hidden;
}

/* the banner wrapper holds the hero art and the floated favorite star */
.arcade-hub .mf-hub-card-banner {
  position: relative;
}

.arcade-hub .mf-hub-card-banner img {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-bottom: 1px solid var(--mf-card-border);
}

/* the game name on its own line below the banner, for every card (Miro Flight
   keeps its baked-in art name too, by design) */
.arcade-hub .mf-hub-card-name {
  margin: 9px 12px 0;
  font-size: 15px;
  font-weight: 700;
  line-height: 1.2;
  color: var(--mf-ink);
}

/* the tagline under the name. A small bottom margin keeps a minimum gap before
   the footer, which is then pushed to the card's bottom edge. */
.arcade-hub .mf-hub-card-desc {
  margin: 3px 12px 8px;
  font-size: 12px;
  line-height: 1.4;
  color: var(--mf-ink-dim);
}

/* Favorite: a round frosted-glass star floated on the banner top-right, going
   gold when the card is favorited - the premium little control from the mockup. */
.arcade-hub .mf-hub-fav {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  color: #fff;
  background: rgba(8, 11, 18, 0.42);
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: 999px;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: color 0.14s ease, background 0.14s ease, transform 0.12s ease;
}

.arcade-hub .mf-hub-fav.on {
  color: var(--mf-gold);
  background: rgba(8, 11, 18, 0.55);
  border-color: rgba(255, 215, 94, 0.7);
}

@media (hover: hover) {
  .arcade-hub .mf-hub-fav:hover {
    background: rgba(8, 11, 18, 0.62);
    transform: scale(1.06);
  }

  .arcade-hub .mf-hub-fav.on:hover {
    color: var(--mf-gold);
  }
}

/* The footer meta row: the crown tally on the left, the leaderboard trophy on
   the right, pushed apart so each holds its own corner. */
.arcade-hub .mf-hub-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  min-height: 26px;
  /* margin-top:auto pins the footer to the card's bottom edge, so the trophy
     stays bottom-left and the crown bottom-right on every card regardless of
     how many lines the tagline took (grid stretches cards to equal height). */
  margin: auto 12px 9px;
}

/* legacy spacer, no longer emitted now the trophy is the first (left) child */
.arcade-hub .mf-hub-meta-spacer {
  flex: 1 1 auto;
}

/* The earned/total crowns badge: a gold pill anchored on the bottom-left */
.arcade-hub .mf-hub-crowns {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 9px;
  font-size: 11px;
  font-weight: 800;
  color: var(--mf-gold);
  background: rgba(255, 215, 94, 0.1);
  border: 1px solid rgba(255, 215, 94, 0.4);
  border-radius: 999px;
}

/* keep the count text gold over the generic dim card-span color */
.arcade-hub .mf-hub-crowns span {
  margin: 0;
  font-size: 11px;
  color: var(--mf-gold);
}

/* the zero-earned crowns pill reads muted/dim until the first crown is won, so a
   game's crown progress is always visible (0/8) without shouting like a complete one */
.arcade-hub .mf-hub-crowns-empty {
  color: rgba(255, 255, 255, 0.42);
  background: rgba(255, 255, 255, 0.05);
  border-color: rgba(255, 255, 255, 0.16);
}

.arcade-hub .mf-hub-crowns-empty span {
  color: rgba(255, 255, 255, 0.42);
}

/* Leaderboard: the same trophy icon as the in-game board link, a small button on
   the bottom-right that opens the shared, relay-fed board for this game */
.arcade-hub .mf-hub-board {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  color: var(--mf-ink-dim);
  background: var(--mf-bg-2);
  border: 1px solid var(--mf-card-border);
  border-radius: 10px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: color 0.14s ease, background 0.14s ease, border-color 0.14s ease;
}

@media (hover: hover) {
  .arcade-hub .mf-hub-board:hover {
    color: var(--mf-gold);
    border-color: rgba(255, 215, 94, 0.5);
  }
}

/* The flagship card leads the grid; a calm brighter border marks it without a
   colored glow that would clash with the hero art. */
.arcade-hub .mf-hub-card-pinned {
  border-color: rgba(255, 255, 255, 0.28);
}

/* A fully-crowned card glows gold so a completed game stands out in the grid.
   overflow:hidden clips the premium gold sheen sweep to the card's rounded edge. */
.arcade-hub .mf-hub-card-crowned {
  border-color: var(--mf-gold);
  box-shadow: 0 0 18px rgba(255, 215, 94, 0.45);
  overflow: hidden;
}

/* a slow, subtle gold sheen sweeps diagonally across a fully-crowned card so it
   reads premium/alive without being busy. pointer-events:none keeps the card
   tappable; it sweeps in ~2.6s then rests ~2.4s before repeating. */
.arcade-hub .mf-hub-card-crowned::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background: linear-gradient(
    115deg,
    transparent 40%,
    rgba(255, 235, 170, 0.0) 46%,
    rgba(255, 240, 190, 0.4) 50%,
    rgba(255, 235, 170, 0.0) 54%,
    transparent 60%
  );
  transform: translateX(-130%);
  animation: mf-hub-crown-sheen 5s ease-in-out infinite;
}

@keyframes mf-hub-crown-sheen {
  0% {
    transform: translateX(-130%);
  }
  52% {
    transform: translateX(130%);
  }
  100% {
    transform: translateX(130%);
  }
}

/* respect reduced-motion (and keep phones cool): a completed card keeps its gold
   glow + border but drops the moving sheen entirely */
@media (prefers-reduced-motion: reduce) {
  .arcade-hub .mf-hub-card-crowned::after {
    animation: none;
    opacity: 0;
  }
}

/* ***************************************************************
 * Leaderboard overlay
 * *************************************************************** */

/* Full-screen dim backdrop; a tap outside the sheet closes the board. The inner
   sheet only positions and bounds the mounted kit card. The card itself (its
   surface, border, title, tabs, rows and Back button) is the SAME kit leaderboard
   panel the games render in their menu, styled by the global leaderboard-shared
   stylesheet, so the popup reads identically here and in game. Only the kit board
   classes are styled globally; the few extra tokens that panel reads, beyond the
   ones the host block above declares, are added there so the card renders true.
   These overlay wrappers are .arcade-hub-scoped (hub-component-local in the source),
   but position:fixed; inset:0 still makes the backdrop cover the full viewport. */
.arcade-hub .mf-board-overlay {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: max(24px, env(safe-area-inset-top)) 12px max(16px, env(safe-area-inset-bottom));
  background: rgba(4, 6, 11, 0.66);
  backdrop-filter: blur(2px);
}

/* The sheet is a transparent centered bound for the kit card. It carries no
   surface of its own, since the kit card paints its own frame, glass and shadow;
   the sheet only caps the width and height so a long board scrolls inside the
   card rather than off the screen. */
.arcade-hub .mf-board-sheet {
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 440px;
  max-height: 100%;
  min-height: 0;
}

/* The mount container the kit panel root is appended into. It fills the sheet so
   the card can use its own auto margins to center and its own overflow to scroll. */
.arcade-hub .mf-board-mount {
  display: flex;
  flex-direction: column;
  width: 100%;
  max-height: 100%;
  min-height: 0;
}

/* The board title's inline trophy. These three rules live in the kit's
   leaderboard-shared stylesheet (so the in-game board reads them), but the player
   does not link that sheet, so without them the kit's stroke="currentColor" trophy
   falls back to the panel's white ink and sits unaligned at the top-left. Restated
   here, .arcade-hub-scoped like the overlay wrappers above, so the header shows a
   gold trophy inline right before the centered game-name title. */
.arcade-hub .mf-board-title {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}

.arcade-hub .mf-board-title-icon {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  color: var(--mf-gold);
}

.arcade-hub .mf-board-title-icon svg {
  display: block;
  width: 22px;
  height: 22px;
}

/* ***************************************************************
 * Settings overlay
 * *************************************************************** */

/* The full-bleed backdrop behind the settings sheet, dimming the catalog. A tap
   on the backdrop closes the sheet; the sheet itself stops the click. */
.arcade-hub .mf-set-overlay {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: rgba(6, 8, 14, 0.62);
  /* keep the sheet clear of the device chrome on a notched phone */
  padding: 0 0 env(safe-area-inset-bottom);
}

/* The settings sheet: a mobile-portrait bottom sheet a thumb can reach. It caps
   its height and scrolls inside so a long body never pushes off-screen. */
.arcade-hub .mf-set-sheet {
  box-sizing: border-box;
  width: 100%;
  max-width: 520px;
  max-height: 86vh;
  overflow-y: auto;
  padding: 18px 18px max(20px, env(safe-area-inset-bottom));
  background: linear-gradient(160deg, var(--mf-bg-2) 0%, var(--mf-bg) 100%);
  border: 1px solid var(--mf-card-border);
  border-radius: 18px 18px 0 0;
  box-shadow: 0 -10px 30px -12px rgba(0, 0, 0, 0.8);
}

/* The sheet header carries the title and the close control */
.arcade-hub .mf-set-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 6px;
}

.arcade-hub .mf-set-head h2 {
  margin: 0;
  font-size: 17px;
  font-weight: 800;
  color: var(--mf-ink);
}

.arcade-hub .mf-set-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  padding: 0;
  color: var(--mf-ink);
  background: var(--mf-surface);
  border: 1px solid var(--mf-card-border);
  border-radius: 11px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.arcade-hub .mf-set-close:active {
  background: var(--mf-bg-2);
}

/* Each labeled settings group, separated by a hairline so the sections read apart */
.arcade-hub .mf-set-section {
  padding: 14px 0;
  border-top: 1px solid var(--mf-card-border);
}

.arcade-hub .mf-set-section:first-of-type {
  border-top: none;
}

.arcade-hub .mf-set-label {
  margin-bottom: 10px;
  font-size: 13px;
  font-weight: 700;
  color: var(--mf-ink-dim);
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.arcade-hub .mf-set-hint {
  margin-bottom: 10px;
  font-size: 13px;
  line-height: 1.45;
  color: var(--mf-ink-dim);
}

/* The language picker: a wrap of pill buttons, each in its own script. The active
   language pill lights with the accent so the current choice reads at a glance. */
.arcade-hub .mf-set-langs {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.arcade-hub .mf-set-lang {
  flex: 0 0 auto;
  min-height: 40px;
  padding: 0 16px;
  font-family: inherit;
  font-size: 15px;
  font-weight: 700;
  color: var(--mf-ink);
  background: var(--mf-surface);
  border: 1px solid var(--mf-card-border);
  border-radius: 11px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.arcade-hub .mf-set-lang.on {
  color: #fff;
  background: rgba(184, 168, 216, 0.22);
  border-color: var(--mf-accent);
}

/* Language: a collapsed row (label + current native name + chevron) that opens a
   search box over the pill grid, so the 30-language wall no longer fills the sheet. */
.arcade-hub .mf-set-langcur {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 14px;
  font-weight: 700;
  color: var(--mf-ink-dim);
}

.arcade-hub .mf-set-chevron {
  font-size: 11px;
  line-height: 1;
  transition: transform 0.18s ease;
}

.arcade-hub .mf-set-langrow.open .mf-set-chevron {
  transform: rotate(180deg);
}

.arcade-hub .mf-set-langpicker {
  margin-top: 10px;
}

.arcade-hub .mf-set-langsearch {
  width: 100%;
  box-sizing: border-box;
  margin-bottom: 10px;
}

/* Theme: a sun / moon icon segment (language-independent) instead of localized text.
   The track uses the surface + border tokens so it reads on both day and night. */
.arcade-hub .mf-set-themeseg {
  display: inline-flex;
  gap: 4px;
  padding: 3px;
  background: var(--mf-surface);
  border: 1px solid var(--mf-card-border);
  border-radius: 999px;
}

.arcade-hub .mf-set-themebtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 30px;
  padding: 0;
  border: none;
  border-radius: 999px;
  background: transparent;
  color: var(--mf-ink-dim);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.arcade-hub .mf-set-themebtn.on {
  background: var(--mf-accent);
  color: #fff;
}

/* The sound row: a full-width tappable row with a label and a slide switch */
.arcade-hub .mf-set-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 4px 0;
  font-family: inherit;
  background: transparent;
  border: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.arcade-hub .mf-set-row-label {
  font-size: 15px;
  font-weight: 600;
  color: var(--mf-ink);
}

/* The slide switch: an off track that turns accent when sound is on */
.arcade-hub .mf-set-switch {
  position: relative;
  flex: 0 0 auto;
  width: 46px;
  height: 28px;
  background: rgba(255, 255, 255, 0.14);
  border-radius: 999px;
  transition: background 0.15s ease;
}

.arcade-hub .mf-set-switch.on {
  background: var(--mf-accent);
}

.arcade-hub .mf-set-knob {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 22px;
  height: 22px;
  background: #fff;
  border-radius: 50%;
  transition: transform 0.15s ease;
}

.arcade-hub .mf-set-switch.on .mf-set-knob {
  transform: translateX(18px);
}

/* The music volume slider row: a label on the left, the range filling the rest */
.arcade-hub .mf-set-sliderrow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  width: 100%;
  padding: 2px 0 4px;
}

.arcade-hub .mf-set-sliderrow .mf-set-row-label {
  flex: 0 0 auto;
}

/* A flat range input themed to the accent track + white knob like the switch */
.arcade-hub .mf-set-slider {
  flex: 1 1 auto;
  min-width: 0;
  height: 28px;
  -webkit-appearance: none;
  appearance: none;
  background: transparent;
  cursor: pointer;
}

.arcade-hub .mf-set-slider::-webkit-slider-runnable-track {
  height: 6px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.14);
}

.arcade-hub .mf-set-slider::-moz-range-track {
  height: 6px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.14);
}

.arcade-hub .mf-set-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  margin-top: -8px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--mf-accent);
  border: 3px solid #fff;
  box-sizing: border-box;
}

.arcade-hub .mf-set-slider::-moz-range-thumb {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--mf-accent);
  border: 3px solid #fff;
  box-sizing: border-box;
}

/* A dimmed, non-interactive look for the music controls while sound (or music) is
   off, so the group reads as subordinate to the sound toggle */
.arcade-hub .mf-set-dim {
  opacity: 0.4;
}

.arcade-hub .mf-set-slider:disabled {
  cursor: default;
}

/* The invite and promo rows: an input filling the row with a button beside it */
.arcade-hub .mf-set-inviterow,
.arcade-hub .mf-set-promorow {
  display: flex;
  gap: 8px;
  align-items: stretch;
}

.arcade-hub .mf-set-input {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 44px;
  box-sizing: border-box;
  padding: 10px 12px;
  font-family: inherit;
  font-size: 14px;
  color: var(--mf-ink);
  background: var(--mf-surface);
  border: 1px solid var(--mf-card-border);
  border-radius: 11px;
  outline: none;
}

.arcade-hub .mf-set-input:focus {
  border-color: var(--mf-accent);
}

.arcade-hub .mf-set-input::placeholder {
  color: var(--mf-ink-dim);
}

.arcade-hub .mf-set-btn {
  flex: 0 0 auto;
  min-height: 44px;
  padding: 0 16px;
  font-family: inherit;
  font-size: 14px;
  font-weight: 800;
  color: #fff;
  background: rgba(184, 168, 216, 0.22);
  border: 1px solid var(--mf-accent);
  border-radius: 11px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.arcade-hub .mf-set-btn:active {
  background: rgba(184, 168, 216, 0.34);
}

.arcade-hub .mf-set-btn:disabled {
  opacity: 0.55;
  cursor: default;
}

/* The promo result line under the apply row */
.arcade-hub .mf-set-status {
  margin-top: 10px;
  font-size: 13px;
  line-height: 1.4;
  color: var(--mf-ink);
}

/* feedback section: a full-width multiline textarea, a ghost attach button + photo
   name, and a send button spaced under the attach row */
.arcade-hub .mf-set-textarea {
  width: 100%;
  display: block;
  margin-top: 8px;
  resize: vertical;
  min-height: 76px;
  line-height: 1.45;
}

.arcade-hub .mf-set-btn-ghost {
  color: var(--mf-ink);
  background: transparent;
  border-color: var(--mf-card-border);
  font-weight: 700;
}

.arcade-hub .mf-set-photoname {
  align-self: center;
  font-size: 13px;
  color: var(--mf-ink-dim);
}

/* the feedback send button is the only direct-child button of a section (the promo
   apply button lives inside a .mf-set-promorow), so this spaces only the send button */
.arcade-hub .mf-set-section > button.mf-set-btn {
  margin-top: 10px;
}

/* ***************************************************************
 * Legal section (privacy / terms links + delete-my-data)
 * *************************************************************** */

/* The little open-affordance chevron on the right of each legal link row (Privacy /
   Terms). The row itself is a .mf-set-row (label left, this glyph right); dim so it
   reads as a quiet forward affordance, not a control. */
.arcade-hub .mf-set-legal-arrow {
  flex: 0 0 auto;
  font-size: 18px;
  line-height: 1;
  color: var(--mf-ink-dim);
}

/* The delete-my-data wrapper, separated from the Terms row above it. Holds the danger
   button, its inline confirm line and the result status, which swap in place. */
.arcade-hub .mf-set-legal-delete {
  margin-top: 12px;
}

/* The inline confirm actions row: the Delete + Cancel buttons side by side, each
   filling half the row so neither dominates. */
.arcade-hub .mf-set-legal-actions {
  display: flex;
  gap: 8px;
  margin-top: 10px;
}

.arcade-hub .mf-set-legal-actions .mf-set-btn {
  flex: 1 1 0;
}

/* The DANGER button variant, layered over .mf-set-btn for the destructive delete
   controls (the "Delete my data" button and the confirm "Delete"). A red-tinted
   outline rather than a loud solid fill, so it reads as destructive without shouting
   over the sheet. Declared AFTER the base .mf-set-btn rules so its colors win on the
   button that carries both classes. */
.arcade-hub .mf-set-btn-danger {
  color: #ff6b6b;
  background: rgba(224, 74, 74, 0.12);
  border-color: rgba(224, 74, 74, 0.5);
}

.arcade-hub .mf-set-btn-danger:active {
  background: rgba(224, 74, 74, 0.22);
}

/* ***************************************************************
 * Legal document viewer overlay
 * *************************************************************** */

/* The full-screen legal viewer, opened from the settings LEGAL section OVER the
   settings sheet, so its z-index (60) sits above the settings overlay (50). It shows a
   bundled privacy/terms page in an iframe. Unlike the settings/board overlays a tap on
   the backdrop does NOT close it (there is no backdrop click handler); only the header
   X dismisses it, since a legal read is deliberate. Top padding clears the device /
   Telegram top inset so the header never hides under the notch or the client chrome. */
.arcade-hub .mf-legal-overlay {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding-top: max(24px, env(safe-area-inset-top));
  background: rgba(6, 8, 14, 0.86);
}

/* The panel framing the document: a centered full-height column (phone = full width,
   desktop = a 520px reading column matching the settings sheet cap) carrying the
   header bar over the frame. Its own opaque page fill covers the backdrop behind it. */
.arcade-hub .mf-legal-panel {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  max-width: 520px;
  background: var(--mf-page-bg);
}

/* The header bar: the document title on the left and the X close on the right, split
   apart over a hairline like the sheet section dividers. */
.arcade-hub .mf-legal-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--mf-card-border);
}

.arcade-hub .mf-legal-title {
  margin: 0;
  font-size: 17px;
  font-weight: 800;
  color: var(--mf-ink);
}

/* The X close, the exact shape + tokens as the settings sheet's .mf-set-close so the
   two headers read identically. */
.arcade-hub .mf-legal-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  padding: 0;
  color: var(--mf-ink);
  background: var(--mf-surface);
  border: 1px solid var(--mf-card-border);
  border-radius: 11px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.arcade-hub .mf-legal-close:active {
  background: var(--mf-bg-2);
}

/* The document frame fills the rest of the panel edge to edge, no border. */
.arcade-hub .mf-legal-frame {
  flex: 1 1 auto;
  width: 100%;
  min-height: 0;
  border: 0;
}

/* ***************************************************************
 * Parental gate (native Android only — Families-policy link check)
 * *************************************************************** */

/* The full-bleed backdrop behind the parental gate, dimming the catalog / settings
   sheet beneath it. A tap on the backdrop aborts (the link does NOT open); the card
   stops the click. Its z-index (70) sits above the settings sheet (50), the first-launch
   notice (55) and the legal viewer (60) so the gate is always the topmost surface when
   an external link is tapped. Native-only: nothing builds this on Telegram / web. */
.arcade-hub .mf-gate-overlay {
  position: fixed;
  inset: 0;
  z-index: 70;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(6, 8, 14, 0.72);
}

/* The centered gate card: a compact modal a thumb can reach, capped so a small phone
   never overflows. Matches the settings sheet fill + border so the two read as one UI. */
.arcade-hub .mf-gate-card {
  box-sizing: border-box;
  width: 100%;
  max-width: 360px;
  padding: 20px;
  background: linear-gradient(160deg, var(--mf-bg-2) 0%, var(--mf-bg) 100%);
  border: 1px solid var(--mf-card-border);
  border-radius: 16px;
  box-shadow: 0 18px 40px -16px rgba(0, 0, 0, 0.85);
  text-align: center;
}

/* The gate title, matching the settings header weight/size */
.arcade-hub .mf-gate-title {
  margin: 0 0 6px;
  font-size: 17px;
  font-weight: 800;
  color: var(--mf-ink);
}

/* The gate instruction line, the dimmer supporting copy like a settings hint */
.arcade-hub .mf-gate-body {
  margin: 0 0 12px;
  font-size: 13px;
  line-height: 1.45;
  color: var(--mf-ink-dim);
}

/* The question line ("A x B = ?"), the loud focal prompt the grown-up answers */
.arcade-hub .mf-gate-question {
  margin: 0 0 12px;
  font-size: 26px;
  font-weight: 800;
  letter-spacing: 1px;
  color: var(--mf-ink);
}

/* The numeric answer field, centered under the question. Reuses the settings input look
   (surface + hairline + accent focus) at a larger centered type for the digits. */
.arcade-hub .mf-gate-input {
  width: 100%;
  box-sizing: border-box;
  min-height: 48px;
  margin: 0 0 14px;
  padding: 10px 12px;
  font-family: inherit;
  font-size: 20px;
  font-weight: 700;
  text-align: center;
  color: var(--mf-ink);
  background: var(--mf-surface);
  border: 1px solid var(--mf-card-border);
  border-radius: 11px;
  outline: none;
}

.arcade-hub .mf-gate-input:focus {
  border-color: var(--mf-accent);
}

/* The actions row: OK + Cancel side by side, each filling half the row */
.arcade-hub .mf-gate-actions {
  display: flex;
  gap: 8px;
}

.arcade-hub .mf-gate-actions .mf-set-btn {
  flex: 1 1 0;
}

/* The Cancel button's neutral variant: a transparent, hairline-outlined button so the
   abort action reads quieter than the primary OK. Its own class (not the shared
   `.mf-set-btn-ghost`) because the day `.mf-set-btn` override would otherwise flatten a
   ghost button to the same accent fill as OK. Declared AFTER the base `.mf-set-btn` so
   it wins at equal specificity in the night theme; the day override is re-asserted in
   the DAY theme block below. */
.arcade-hub .mf-gate-cancel {
  color: var(--mf-ink);
  background: transparent;
  border-color: var(--mf-card-border);
  font-weight: 700;
}

/* The wrong-answer shake: a short horizontal wobble applied to the card on a miss. The
   builder removes then re-adds the class (forcing a reflow between) so a repeat miss
   restarts the animation. */
@keyframes mfGateShake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-7px); }
  40% { transform: translateX(6px); }
  60% { transform: translateX(-4px); }
  80% { transform: translateX(3px); }
}

.arcade-hub .mf-gate-card.mf-gate-shake {
  animation: mfGateShake 0.32s ease;
}

/* ***************************************************************
 * First-launch notice (native Android only — one-time device-id disclosure)
 * *************************************************************** */

/* The backdrop behind the one-time first-launch notice, dimming the catalog on the very
   first native boot. It carries NO click-to-close (acknowledged via OK). Its z-index
   (55) sits above the settings sheet (50) and below the legal viewer (60) so the Privacy
   link opens the viewer OVER it. Native-only: nothing builds this on Telegram / web. */
.arcade-hub .mf-notice-overlay {
  position: fixed;
  inset: 0;
  z-index: 55;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: rgba(6, 8, 14, 0.62);
  /* keep the card clear of the device chrome on a notched phone */
  padding: 0 0 env(safe-area-inset-bottom);
}

/* The notice card: a bottom sheet matching the settings sheet fill / radius / border so
   the one-time disclosure reads as part of the same UI. */
.arcade-hub .mf-notice-card {
  box-sizing: border-box;
  width: 100%;
  max-width: 520px;
  padding: 20px 18px max(20px, env(safe-area-inset-bottom));
  background: linear-gradient(160deg, var(--mf-bg-2) 0%, var(--mf-bg) 100%);
  border: 1px solid var(--mf-card-border);
  border-radius: 18px 18px 0 0;
  box-shadow: 0 -10px 30px -12px rgba(0, 0, 0, 0.8);
}

/* The welcome title */
.arcade-hub .mf-notice-title {
  margin: 0 0 8px;
  font-size: 18px;
  font-weight: 800;
  color: var(--mf-ink);
}

/* The disclosure body copy */
.arcade-hub .mf-notice-body {
  margin: 0 0 12px;
  font-size: 14px;
  line-height: 1.5;
  color: var(--mf-ink-dim);
}

/* The Privacy Policy text-link: an inline accent link (not a filled button) so it reads
   as a secondary read-more beside the primary OK button below it. */
.arcade-hub .mf-notice-link {
  display: inline-block;
  margin: 0 0 16px;
  padding: 0;
  font-family: inherit;
  font-size: 14px;
  font-weight: 700;
  color: var(--mf-accent);
  background: transparent;
  border: none;
  text-decoration: underline;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* The primary OK button fills the sheet width so the acknowledge action is unmissable.
   Layout only here; the fill/ink come from the shared `.mf-set-btn` (and its day override). */
.arcade-hub .mf-notice-ok {
  display: block;
  width: 100%;
}

/* The daily game-tip soft-ask reuses the notice shell but offers TWO choices, so its
   actions sit in a split row like the parental gate: Yes (primary accent) beside No (quiet
   outline), each filling half the row. Native-only surface; no web effect. */
.arcade-hub .mf-notice-actions {
  display: flex;
  gap: 8px;
}

.arcade-hub .mf-notice-actions .mf-set-btn {
  flex: 1 1 0;
}

/* The "No thanks" decline: a transparent, hairline-outlined button so it reads quieter than
   the accent Yes. Its own class (not the shared `.mf-set-btn-ghost`) because the day
   `.mf-set-btn` override would otherwise flatten a ghost button to the same accent fill as
   Yes. Declared AFTER the base `.mf-set-btn` so it wins at equal specificity in the night
   theme; the day override is re-asserted in the DAY theme block below. */
.arcade-hub .mf-notice-no {
  color: var(--mf-ink);
  background: transparent;
  border-color: var(--mf-card-border);
  font-weight: 700;
}

/* ***************************************************************
 * DAY theme — hardcoded-value overrides
 * *************************************************************** */

/* Every rule below is additive and day-scoped (selector begins with
   :root[data-theme="day"]); it repoints the few hardcoded colors that would break
   on the warm parchment to the day palette. Gold (#ffd75e) is left alone — crown /
   trophy semantics stay gold in both themes. Night visuals are untouched. */

/* Brand lockup: the night pink/grey marks become the bordeaux + grey day marks. */
:root[data-theme="day"] .arcade-hub .mf-brand-mire {
  color: #d96f8a;
}

:root[data-theme="day"] .arcade-hub .mf-brand-games {
  color: #b8b0c2;
}

/* Make the card body transparent in day so the fixed doodle wallpaper shows
   THROUGH the text footer beneath each hero banner (the banner img stays opaque
   up top). On phones the cards fill the screen, so this is where the doodle
   actually reads. The light border still frames each card. */
:root[data-theme="day"] .arcade-hub .mf-hub-card {
  /* a light 0.3 parchment veil (not fully transparent) so the fixed doodle reads
     softly behind the card text footer while keeping the title/tagline crisp */
  background: rgba(255, 255, 255, 0.3);
}

/* Card hover fill (desktop only): a cleaner, more opaque card on hover. */
:root[data-theme="day"] .arcade-hub .mf-hub-card:hover {
  background: rgba(255, 255, 255, 0.6);
}

/* Favorite star: the dark frosted chip becomes a light warm chip so the star
   reads on a light banner/card. */
:root[data-theme="day"] .arcade-hub .mf-hub-fav {
  color: #2c2a26;
  background: rgba(255, 255, 255, 0.7);
  border-color: rgba(0, 0, 0, 0.12);
}

:root[data-theme="day"] .arcade-hub .mf-hub-fav.on {
  color: var(--mf-gold);
  background: rgba(255, 255, 255, 0.85);
  border-color: rgba(255, 215, 94, 0.7);
}

@media (hover: hover) {
  :root[data-theme="day"] .arcade-hub .mf-hub-fav:hover {
    background: rgba(255, 255, 255, 0.92);
  }
}

/* Board + settings backdrops: the heavy near-black scrims become a lighter warm
   scrim so the dimmed catalog still reads light behind the sheet. */
:root[data-theme="day"] .arcade-hub .mf-board-overlay {
  background: rgba(44, 42, 38, 0.34);
}

:root[data-theme="day"] .arcade-hub .mf-set-overlay {
  background: rgba(44, 42, 38, 0.34);
}

/* Active language pill + primary settings button: the night white-on-wash look
   would wash out on parchment, so use day ink/accent so the active/primary state
   reads. */
:root[data-theme="day"] .arcade-hub .mf-set-lang.on {
  color: #ffffff;
  background: var(--mf-accent);
}

:root[data-theme="day"] .arcade-hub .mf-set-btn {
  color: #ffffff;
  background: var(--mf-accent);
}

:root[data-theme="day"] .arcade-hub .mf-set-btn:active {
  background: #6e0b3f;
}

/* Danger button on parchment: the day .mf-set-btn override above repaints EVERY
   .mf-set-btn solid accent, so the destructive variant must be re-asserted here (same
   specificity, declared later) with a darker red that reads on the light surface. */
:root[data-theme="day"] .arcade-hub .mf-set-btn-danger {
  color: #c0392b;
  background: rgba(192, 57, 43, 0.08);
  border-color: rgba(192, 57, 43, 0.42);
}

:root[data-theme="day"] .arcade-hub .mf-set-btn-danger:active {
  background: rgba(192, 57, 43, 0.16);
}

/* Legal viewer scrim: lighten the near-black backdrop to the warm day scrim like the
   board + settings overlays, so the parchment reads light on the panel's side gutters. */
:root[data-theme="day"] .arcade-hub .mf-legal-overlay {
  background: rgba(44, 42, 38, 0.5);
}

/* Switch + slider tracks/knobs: the white-on-dark translucent tracks vanish on a
   light surface, so day uses a dark-on-light track and a tinted knob. */
:root[data-theme="day"] .arcade-hub .mf-set-switch {
  background: rgba(0, 0, 0, 0.14);
}

:root[data-theme="day"] .arcade-hub .mf-set-slider::-webkit-slider-runnable-track {
  background: rgba(0, 0, 0, 0.14);
}

:root[data-theme="day"] .arcade-hub .mf-set-slider::-moz-range-track {
  background: rgba(0, 0, 0, 0.14);
}

/* Empty-crowns pill: the white-on-dark muted pill becomes a dark-on-light muted
   pill so a 0/N crown count stays legible on parchment. */
:root[data-theme="day"] .arcade-hub .mf-hub-crowns-empty {
  color: rgba(44, 42, 38, 0.5);
  background: rgba(0, 0, 0, 0.04);
  border-color: rgba(0, 0, 0, 0.12);
}

:root[data-theme="day"] .arcade-hub .mf-hub-crowns-empty span {
  color: rgba(44, 42, 38, 0.5);
}

/* Pinned-card edge: the bright white border that marked the flagship on dark would
   disappear on parchment, so day uses the accent at low alpha to keep the lead
   card subtly distinguished. */
:root[data-theme="day"] .arcade-hub .mf-hub-card-pinned {
  border-color: rgba(136, 14, 79, 0.35);
}

/* Native parental gate + first-launch notice scrims: lighten the near-black backdrops
   to the warm day scrim like the board / settings / legal overlays, so the parchment
   reads light on the gutters behind the card. (Native-only surfaces; no web effect.) */
:root[data-theme="day"] .arcade-hub .mf-gate-overlay {
  background: rgba(44, 42, 38, 0.5);
}

:root[data-theme="day"] .arcade-hub .mf-notice-overlay {
  background: rgba(44, 42, 38, 0.34);
}

/* Gate Cancel on parchment: the day `.mf-set-btn` override repaints EVERY `.mf-set-btn`
   solid accent, so the neutral Cancel must be re-asserted here (same specificity as that
   override, declared later) to stay a quiet outlined button distinct from the accent OK. */
:root[data-theme="day"] .arcade-hub .mf-gate-cancel {
  color: var(--mf-ink);
  background: transparent;
  border-color: var(--mf-card-border);
}

/* Daily-tip decline on parchment: same reasoning as the gate Cancel above - the day
   `.mf-set-btn` override repaints EVERY `.mf-set-btn` solid accent, so the neutral No must be
   re-asserted here (same specificity, declared later) to stay a quiet outlined button
   distinct from the accent Yes. */
:root[data-theme="day"] .arcade-hub .mf-notice-no {
  color: var(--mf-ink);
  background: transparent;
  border-color: var(--mf-card-border);
}
