/*
 * Antigame design system.
 *
 * Every colour and gradient here is lifted from the Xamarin app so the web build reads as the
 * same product: the palette is Antigame/App.xaml's ResourceDictionary, and the layered-gradient
 * card treatment reproduces the trick the XAML used everywhere — an outer StackLayout with a
 * LinearGradientBrush and 1-3px of padding wrapping an inner gradient StackLayout, which Xamarin
 * needed because it has no border-image. On the web that is one element with a padded
 * background-image, so the markup stays flat.
 */

/* ---------------------------------------------------------------- fonts */

@font-face {
    font-family: "Poppins";
    src: url("../assets/fonts/Poppins-Thin.ttf") format("truetype");
    font-weight: 100;
    font-display: swap;
}
@font-face {
    font-family: "Poppins";
    src: url("../assets/fonts/Poppins-ExtraLight.ttf") format("truetype");
    font-weight: 200;
    font-display: swap;
}
@font-face {
    font-family: "Poppins";
    src: url("../assets/fonts/Poppins-Light.ttf") format("truetype");
    font-weight: 300;
    font-display: swap;
}
@font-face {
    font-family: "Poppins";
    src: url("../assets/fonts/Poppins-Regular.ttf") format("truetype");
    font-weight: 400;
    font-display: swap;
}
@font-face {
    font-family: "Poppins";
    src: url("../assets/fonts/Poppins-Bold.ttf") format("truetype");
    font-weight: 700;
    font-display: swap;
}
@font-face {
    font-family: "Poppins";
    src: url("../assets/fonts/Poppins-Black.ttf") format("truetype");
    font-weight: 900;
    font-display: swap;
}

/* ---------------------------------------------------------------- palette */

:root {
    /*
     * Straight from App.xaml — with one translation that MUST be preserved: XAML writes 8-digit
     * hex as AARRGGBB, CSS reads RRGGBBAA. Copy a XAML colour verbatim and its alpha byte
     * becomes its red channel ("25% pink" #40ce75d3 renders as opaque mint green). Every
     * translucent token below has therefore been re-ordered; do the same for any new ones.
     */
    --primary: #3c1461;
    --primary-t1: #3c14618f;
    --primary-t2: #3c146140;
    --primary-t3: #3c146120;

    --primary-dark: #1f0331;
    --primary-dark-t1: #1f0331a0;
    --primary-dark-t2: #1f033140;
    --primary-dark-t3: #1f033120;

    --primary-light: #ce75c3;
    --primary-light-t1: #ce75c380;
    --primary-light-t2: #ce75d3b0;
    --primary-light-t3: #ce75d340;

    --black-t1: #00000080;
    --black-t2: #00000040;
    --black-t3: #00000020;

    --white-t1: #ffffffb0;
    --white-t2: #ffffff40;
    --white-t3: #ffffff20;

    --secondary: #ea5d6b;
    --secondary-dark: #d3404e;
    --secondary-light: #ffa1aa;

    --light: #ffffff;
    --dark: #000000;

    --gold-1: #caa660;
    --gold-2: #f9f5c4;
    --gold-3: #4f3511;

    /* The countdown ring's border sweep. GamePage.gradLevels, indexed by seconds remaining:
       it runs hot (red) when time is nearly up and cools to pink with time to spare. */
    --cd-20: #fec5d3;
    --cd-15: #fec5d3;
    --cd-10: #de85d3;
    --cd-7:  #ce75c3;
    --cd-5:  #fa7d6b;
    --cd-3:  #ea5d6b;
    --cd-1:  #ff303e;

    --gold-bar: linear-gradient(180deg, var(--gold-1) 0%, var(--gold-2) 50%, var(--gold-3) 100%);
    --gold-button: linear-gradient(180deg, var(--gold-1) 0%, var(--gold-3) 50%, var(--gold-2) 100%);

    /* Layout rails. The mobile pages pinned the header to 9-10% of the page and the tab bar to
       11%, with content inset below/above; these are the web equivalents. */
    --header-h: 118px;
    --nav-h: 86px;
    --gutter: 16px;

    /*
     * Motion.
     *
     * Xamarin animations were written with Easing.CubicIn and a 1000ms Commit, which on the web
     * reads as slow-starting and a little dead. These are the standard decelerating curves: a
     * long tail so things settle rather than stop, and one overshoot curve for elements that
     * appear. Everything that moves uses one of them, so the UI feels like a single system.
     */
    --ease-out: cubic-bezier(.16, 1, .3, 1);
    --ease-in-out: cubic-bezier(.65, 0, .35, 1);
    --ease-pop: cubic-bezier(.34, 1.56, .64, 1);

    --dur-fast: 180ms;
    --dur: 320ms;
    --dur-slow: 560ms;
}

/* ---------------------------------------------------------------- reset */

*,
*::before,
*::after { box-sizing: border-box; }

html, body {
    margin: 0;
    padding: 0;
    height: 100%;
}

body {
    font-family: "Poppins", system-ui, -apple-system, "Segoe UI", sans-serif;
    font-weight: 300;
    color: var(--light);
    background: var(--primary-dark);
    -webkit-font-smoothing: antialiased;
    overflow: hidden;
}

h1, h2, h3, h4 {
    font-weight: 700;
    margin: 0;
}

button {
    font-family: inherit;
    color: inherit;
    cursor: pointer;
    border: 0;
    background: none;
}

button:disabled { cursor: default; }

a { color: var(--primary-light); }

/*
 * Images never take part in selection or native drag.
 *
 * A browser makes every <img> draggable, which fights the click-and-drag panning on the spaces
 * carousel: the gesture starts a ghost-image drag instead of moving the strip, and leaves the
 * blue selection highlight behind.
 */
img {
    -webkit-user-drag: none;
    -webkit-user-select: none;
    user-select: none;
}

/*
 * Icons keep their own aspect ratio. The art is a mix of square and non-square sources, and
 * setting both width and height squashed the ones that are not square — the notification bell
 * most visibly.
 */
.ag-header__logo,
.ag-balance img,
.ag-nav__item img,
.ag-stat__icon,
.ag-room__seats img,
.ag-room__fee img,
.ag-room__launch,
.ag-space__players img,
.ag-iconbtn__face img {
    object-fit: contain;
}

/* Scrollbars are hidden throughout: every mobile ScrollView set
   HorizontalScrollBarVisibility/VerticalScrollBarVisibility to Never. */
.noscroll { scrollbar-width: none; -ms-overflow-style: none; }
.noscroll::-webkit-scrollbar { width: 0; height: 0; }

/* ---------------------------------------------------------------- app shell */

#app, .ag-app {
    position: fixed;
    inset: 0;
    overflow: hidden;
}

/* ContentPage's implicit style in App.xaml: a vertical Primary -> PrimaryDark gradient. */
.ag-page {
    position: absolute;
    inset: 0;
    /*
     * A pure positioning shell. It paints nothing: the colour wash is the layout's persistent
     * .ag-tint (so hue changes can glide between pages) and the starfield sits above that.
     * Deliberately NO z-index and NO animation here — either would make this a stacking
     * context, flattening the children's z-indexes below the fixed starfield, which put the
     * "background in the foreground" once already.
     */
    overflow: hidden;
}

/* The shared wash. Base colour comes from .ag-app behind it. */
.ag-tint {
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background:
        radial-gradient(120% 100% at 50% 104%,
            var(--primary-light-t2) 0%,
            var(--primary-t1) 50%,
            var(--primary-dark-t1) 100%),
        linear-gradient(180deg, var(--primary) 50%, var(--primary-dark) 100%);
    filter: hue-rotate(var(--page-hue, 0deg)) saturate(var(--page-sat, 1));
    /* The glide between screens: hue interpolates, gradients never need to. */
    transition: filter 900ms var(--ease-in-out);
    animation: ag-tint-breathe 26s var(--ease-in-out) infinite;
}

@keyframes ag-tint-breathe {
    0%, 100% { opacity: 1; }
    50%      { opacity: .86; }
}

/* Softens the tint swap between screens now that the starfield itself never resets. */
@keyframes ag-page-in {
    from { opacity: .55; }
    to   { opacity: 1; }
}

.ag-content {
    position: absolute;
    inset: 0;
    z-index: 2; /* above the shared starfield */
    overflow-y: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
    animation: ag-page-in 240ms var(--ease-out);
}

.ag-content--inset {
    padding-top: var(--header-h);
    padding-bottom: calc(var(--nav-h) + 12px);
}

/* ---------------------------------------------------------------- parallax starfield */

/*
 * Mobile stacked three ScrollViews holding background_space_transparent / background_stars and
 * scrolled each at a divided rate from the page's Scrolled handler (Antigame.AnimateBackground
 * and the per-page DoAnimations). Here the layers are fixed backgrounds driven by a CSS variable
 * the page updates on scroll, so the parallax costs no layout work.
 */
.ag-parallax {
    position: fixed;
    inset: 0;
    /*
     * NO overflow clipping. The layers overdraw this box by 30% on every side precisely so the
     * wandering zoom can scale below 1 — but overflow:hidden clipped them to the container,
     * and the clip box shrinks WITH the scale, so minus zoom levels exposed a band of bare
     * tint along the bottom edge.
     */
    pointer-events: none;
    /* Above each page's opaque colour wash, below all content (.ag-content is 2, chrome 20+). */
    z-index: 1;
}

.ag-parallax__layer {
    position: absolute;
    inset: -30%;
    background-repeat: repeat;
    background-position: center;
    will-change: transform;
}

/*
 * Each layer combines two sources of motion:
 *   --px/--py  scroll offset, the direct port of the mobile behaviour
 *   --mx/--my  pointer position, added for desktop where a screen often does not scroll at all
 * and divides them by its own depth, so nearer layers travel further.
 */
.ag-parallax__layer--1 {
    background-image: url("../assets/img/background_space_transparent.png");
    background-size: 150% auto;
    opacity: 1;
    transform:
        translate3d(
            calc(var(--px, 0px) / 3.5 + var(--mx, 0px) * 1),
            calc(var(--py, 0px) / 3.5 + var(--my, 0px) * 1), 0)
        scale(1.3);
}

.ag-parallax__layer--2 {
    background-image: url("../assets/img/background_space_transparent.png");
    background-size: 110% auto;
    opacity: .8;
    transform:
        translate3d(
            calc(var(--px, 0px) / 4.9 + var(--mx, 0px) * 0.55),
            calc(var(--py, 0px) / 4.9 + var(--my, 0px) * 0.55), 0)
        scale(1.7);
}

.ag-parallax__layer--3 {
    background-image: url("../assets/img/background_stars.png");
    background-size: 90% auto;
    opacity: .85;
    transform:
        translate3d(
            calc(var(--px, 0px) / 6.3 + var(--mx, 0px) * 0.25),
            calc(var(--py, 0px) / 6.3 + var(--my, 0px) * 0.25), 0);
}

/*
 * The wandering zoom: JS sets --pz to a new random level (clamped to ±2 levels, 2% each) and
 * this slow transition carries the container there. On the CONTAINER so the layers' own drift
 * keyframes are untouched — a second animation on the layers would override the drift and
 * snap their background-position to frame zero.
 */
.ag-parallax {
    transform: scale(var(--pz, 1));
    transition: transform 3.4s var(--ease-in-out);
}

/* The slow idle drift Antigame.AnimateBackground produced with a 200ms timer. */
.ag-parallax--drift .ag-parallax__layer--1 { animation: ag-drift 48s ease-in-out infinite alternate; }
.ag-parallax--drift .ag-parallax__layer--2 { animation: ag-drift 36s ease-in-out infinite alternate-reverse; }
.ag-parallax--drift .ag-parallax__layer--3 { animation: ag-drift 72s linear infinite alternate; }

@keyframes ag-drift {
    from { background-position: 40% 50%; }
    to   { background-position: 60% 50%; }
}

/* ---------------------------------------------------------------- gradient-bordered card */

/*
 * The app's signature surface. SpaceItemView, RoomItemView and the room info cards all used an
 * outer gradient stack with a few px of padding around an inner gradient stack.
 */
.ag-card {
    position: relative;
    padding: 3px;
    border-radius: 20px;
    background: linear-gradient(160deg,
        var(--primary-light-t3) 20%,
        var(--primary-dark-t2) 50%,
        var(--primary-t2) 100%);
}

.ag-card__inner {
    border-radius: 18px;
    background: linear-gradient(140deg,
        var(--primary-dark) 30%,
        var(--primary-t1) 50%,
        var(--primary-light-t2) 100%);
    overflow: hidden;
    height: 100%;
}

.ag-card--tight { border-radius: 10px; padding: 3px; }
.ag-card--tight .ag-card__inner { border-radius: 8px; }

/* Flat translucent panel, as used for the room stat rows. */
.ag-panel {
    background: var(--primary-dark-t2);
    border-radius: 10px;
}

.ag-panel--dark { background: var(--primary-dark); }

/* ---------------------------------------------------------------- typography */

.ag-title     { font-weight: 700; font-size: 22px; color: var(--primary-light); }
.ag-h2        { font-weight: 700; font-size: 24px; color: var(--secondary); }
.ag-body      { font-weight: 300; font-size: 14px; }
.ag-caption   { font-weight: 300; font-size: 11px; opacity: .85; }
.ag-strong    { font-weight: 700; }
.ag-num       { font-weight: 700; font-variant-numeric: tabular-nums; }
.ag-upper     { text-transform: uppercase; }

/* ---------------------------------------------------------------- buttons */

.ag-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 44px;
    padding: 10px 26px;
    border-radius: 999px; /* pill, like the chips and the knockout ribbon */
    border: 1px solid var(--white-t3);
    font-weight: 700;
    font-size: 13px;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--light);
    background: linear-gradient(180deg, var(--primary) 40%, var(--primary-dark) 100%);
    /* inset highlight along the top edge sells the press depth */
    box-shadow: inset 0 1px 0 var(--white-t2), 0 6px 16px -8px rgba(0, 0, 0, .7);
    transition: transform var(--dur-fast) var(--ease-out),
                filter var(--dur-fast) var(--ease-out),
                box-shadow var(--dur-fast) var(--ease-out);
}

.ag-btn:hover:not(:disabled) {
    filter: brightness(1.14);
    transform: translateY(-1px);
    box-shadow: inset 0 1px 0 var(--white-t2), 0 10px 22px -8px rgba(0, 0, 0, .75);
}
.ag-btn:active:not(:disabled) { transform: scale(.955); }
.ag-btn:disabled { opacity: .4; }

/* App.xaml's ButtonRegister style: the green GO accent, tuned to sit in this palette. */
.ag-btn--register {
    background: linear-gradient(180deg, #1d9b4e 0%, #0f7a3a 100%);
    border-color: rgba(120, 230, 160, .45);
    box-shadow: inset 0 1px 0 rgba(190, 255, 210, .35), 0 0 22px -6px rgba(50, 205, 100, .55);
}

.ag-btn--register:hover:not(:disabled) {
    box-shadow: inset 0 1px 0 rgba(190, 255, 210, .35), 0 0 30px -6px rgba(50, 205, 100, .7);
}

/* App.xaml's ButtonGame style: gold, dark text. */
.ag-btn--gold {
    background: var(--gold-bar);
    color: var(--dark);
    border-radius: 10px;
}

.ag-btn--ghost {
    background: var(--black-t2);
    border-color: var(--primary-light-t1);
    color: var(--primary-light);
    box-shadow: none;
}

.ag-btn--ghost:hover:not(:disabled) {
    background: var(--primary-t2);
    box-shadow: 0 0 18px -6px var(--primary-light-t1);
}

.ag-btn--block { width: 100%; }

/*
 * ButtonView: a round gold-framed icon with a caption, used for Cashout / Protection /
 * Insurance on the game screen.
 */
.ag-iconbtn {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    margin: 5px;
    transition: transform var(--dur-fast) var(--ease-out), opacity var(--dur) var(--ease-out);
}

.ag-iconbtn:active:not(:disabled) { transform: scale(.92); }
.ag-iconbtn:disabled { opacity: .2; }

.ag-iconbtn__ring {
    padding: 4px;
    border-radius: 50%;
    background: var(--gold-bar);
}

.ag-iconbtn__face {
    display: grid;
    place-items: center;
    width: 54px;
    height: 54px;
    border-radius: 50%;
    background: var(--gold-button);
}

.ag-iconbtn__face img { width: 26px; height: 26px; opacity: .9; }

.ag-iconbtn__label {
    font-weight: 700;
    font-size: 11px;
    letter-spacing: .1em;
    text-transform: uppercase;
    opacity: .9;
}

/* ---------------------------------------------------------------- header */

/*
 * The header sits over scrolling content, so it has to be opaque. The Xamarin HeaderView faded
 * to transparent at its lower edge, which works on a page that does not scroll under it — here
 * the room hero slid straight through the fade and collided with the title.
 */
.ag-header {
    position: absolute;
    top: 0; left: 0; right: 0;
    z-index: 20;
    background: linear-gradient(180deg, #2a0d45 0%, #230839 100%);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
    box-shadow: 0 8px 28px rgba(0, 0, 0, .45);
}

.ag-header__top {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 6px var(--gutter) 0;
}

.ag-header__logo { width: 44px; height: 44px; object-fit: contain; }

.ag-header__title {
    flex: 1;
    font-weight: 700;
    font-size: 20px;
    color: var(--primary-light);
    text-transform: uppercase;
}

.ag-header__bell {
    position: relative;
    display: grid;
    place-items: center;
    padding: 5px;
    border-radius: 50%;
    opacity: .9;
    transition: transform var(--dur-fast) var(--ease-out), opacity var(--dur) var(--ease-out);
}

.ag-header__bell img { height: 26px; width: auto; object-fit: contain; }

.ag-header__bell:hover { transform: scale(1.12); opacity: 1; }
.ag-header__bell:active { transform: scale(.9); }

.ag-header__bell.is-muted { opacity: .45; }

/* The slash that says "off" without needing a second icon asset. */
.ag-header__bell.is-muted::after {
    content: "";
    position: absolute;
    left: 5px;
    right: 5px;
    top: 50%;
    height: 2.5px;
    border-radius: 2px;
    background: var(--secondary);
    box-shadow: 0 0 6px rgba(234, 93, 107, .8);
    transform: rotate(-45deg);
}

.ag-header__wallet {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px var(--gutter);
    background: linear-gradient(180deg, #1f0331 0%, #190228 100%);
    border-top: 1px solid var(--white-t3);
}

.ag-avatar {
    padding: 1px;
    border-radius: 50%;
    background: var(--primary-light);
    flex: 0 0 auto;
}

.ag-avatar img {
    display: block;
    width: 38px;
    height: 38px;
    border-radius: 50%;
    object-fit: cover;
}

.ag-header__name {
    font-size: 13px;
    max-width: 120px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ag-header__balances {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-left: auto;
}

.ag-balance {
    display: flex;
    align-items: center;
    gap: 5px;
    font-weight: 700;
    font-size: 14px;
    font-variant-numeric: tabular-nums;
}

.ag-balance img { width: 22px; height: 22px; }

/* ---------------------------------------------------------------- tab bar */

.ag-nav {
    position: absolute;
    bottom: 0; left: 0; right: 0;
    z-index: 20;
    padding: 0 10px;
    background: linear-gradient(180deg, rgba(42, 13, 69, .55) 0%, #230839 55%, #1f0331 100%);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
}

/* Centred, so the row does not hug the left edge once the items stop stretching. */
.ag-nav__inner {
    display: flex;
    justify-content: center;
    width: 100%;
}

.ag-nav__item {
    position: relative;
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    margin: 4px;
    padding: 8px 4px 10px;
    border-radius: 10px;
    opacity: .7;
    transition: opacity var(--dur) var(--ease-out),
                background-color var(--dur) var(--ease-out),
                transform var(--dur) var(--ease-out);
}

.ag-nav__item img { width: 30px; height: 30px; }

.ag-nav__iconwrap { position: relative; display: grid; place-items: center; }
.ag-nav__item span { font-size: 11px; }

.ag-nav__item:hover { opacity: .9; }

.ag-nav__item.is-active {
    opacity: 1;
    background: var(--primary-dark-t1);
}

/* The DataTrigger-driven badge TapNavigationItem.Render built in C#. */
.ag-nav__badge {
    position: absolute;
    top: -7px;
    right: -11px;
    min-width: 18px;
    padding: 1px 5px;
    border-radius: 9px;
    background: orangered;
    font-size: 11px;
    font-weight: 700;
    text-align: center;
}

/* ---------------------------------------------------------------- info fader */

/*
 * InfoFaderPanel cross-faded and scaled a stack of labels on a 5s timer. Only one line is in the
 * DOM at a time here; the animation is keyed on the text so a change restarts it.
 */
.ag-infofader {
    display: grid;
    place-items: center;
    min-height: 54px;
    padding: 8px 20px;
    text-align: center;
    background: linear-gradient(180deg,
        transparent 0%,
        var(--primary-dark-t1) 50%,
        transparent 100%);
}

.ag-infofader__line {
    font-size: 18px;
    font-weight: 300;
    color: var(--primary-light);
    animation: ag-fade-scale var(--dur-slow) var(--ease-out) both;
}

.ag-infofader__line--accent { color: var(--light); }

@keyframes ag-fade-scale {
    from { opacity: 0; transform: scale(1); }
    to   { opacity: 1; transform: scale(1.08); }
}

/* ---------------------------------------------------------------- spaces carousel */

/*
 * SpacesView was a horizontal ScrollView of SpaceItemViews, where DoAnimations scaled the card
 * nearest the viewport centre to 1.0 and pushed the rest to 0.85 / 0.7 opacity. Scroll snapping
 * plus a scroll handler that tags the centred card reproduces it.
 */
.ag-spaces {
    display: flex;
    gap: 0;
    height: 100%;
    padding: 0 calc(50vw - 118px);
    overflow-x: auto;
    overflow-y: hidden;
    align-items: center;
    scroll-snap-type: x mandatory;
}

.ag-space {
    flex: 0 0 auto;
    width: 216px;
    margin: 0 10px;
    scroll-snap-align: center;
    opacity: .7;
    transform: scale(.85);
    transition: opacity var(--dur-slow) var(--ease-out),
                transform var(--dur-slow) var(--ease-out);
    text-align: left;
}

.ag-space.is-active { opacity: 1; transform: scale(1); }

.ag-space__body { padding: 18px; }

/* "You are registered here" — same voice as the tab badge, pinned to the card's corner. */
.ag-space__badge {
    position: absolute;
    top: -7px;
    right: 2px;
    z-index: 3;
    min-width: 24px;
    padding: 3px 8px;
    border-radius: 12px;
    background: orangered;
    font-size: 12px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    text-align: center;
    color: var(--light);
    box-shadow: 0 2px 10px rgba(0, 0, 0, .45), 0 0 16px -2px rgba(255, 69, 0, .6);
    animation: ag-pop 420ms var(--ease-pop) both;
}

.ag-space__thumb {
    width: 100%;
    aspect-ratio: 1;
    object-fit: contain;
    border-radius: 16px;
    -webkit-user-drag: none;
    -webkit-user-select: none;
    user-select: none;
    pointer-events: none;
}

.ag-space__title {
    margin: 10px 0 2px;
    font-weight: 700;
    font-size: 19px;
    color: var(--secondary);
}

.ag-space__desc {
    font-size: 13px;
    font-weight: 300;
    min-height: 56px;
    opacity: .95;
}

.ag-space__players {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: 10px;
    font-size: 13px;
}

.ag-space__players img { width: 17px; height: 17px; }

/* ---------------------------------------------------------------- room rows */

.ag-room {
    display: block;
    width: 100%;
    max-width: 540px;
    margin: 0 auto 10px;
    text-align: left;
}

.ag-room__inner {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    background: linear-gradient(180deg,
        var(--primary-light-t1) 0%,
        var(--primary-dark-t2) 40%,
        var(--black-t3) 100%);
    -webkit-backdrop-filter: blur(12px) saturate(1.25);
    backdrop-filter: blur(12px) saturate(1.25);
}

.ag-room__name {
    flex: 0 0 110px;
    font-weight: 700;
    font-size: 14px;
}

.ag-room__seats {
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 7px 9px;
    border-radius: 5px;
    background: var(--primary-dark-t1);
    font-weight: 100;
    font-size: 13px;
    font-variant-numeric: tabular-nums;
}

.ag-room__seats img { width: 15px; height: 15px; }

.ag-room__fee {
    display: flex;
    align-items: center;
    gap: 4px;
    margin-left: auto;
    padding: 4px 8px;
    border-radius: 6px;
    background: var(--primary-dark-t3);
    font-weight: 700;
    font-size: 13px;
}

.ag-room__fee img { width: 15px; height: 15px; }
.ag-room__launch { width: 19px; height: 19px; opacity: .8; }

.ag-room__mine {
    flex: 0 0 auto;
    padding: 3px 9px;
    border-radius: 999px;
    border: 1px solid var(--primary-light-t1);
    background: var(--primary-t1);
    color: var(--primary-light);
    font-size: 9px;
    font-weight: 700;
    letter-spacing: .14em;
    text-transform: uppercase;
}

.ag-room__live {
    padding: 2px 7px;
    border-radius: 9px;
    background: var(--secondary-dark);
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
}

/* ---------------------------------------------------------------- hero thumbnail */

.ag-hero {
    margin: 10px var(--gutter);
    padding: 5px;
    border-radius: 40px;
    background: var(--primary-dark-t1);
}

.ag-hero img {
    display: block;
    width: 100%;
    /* Viewport-aware on phones: a fixed 210px panel pushed the join page's Register button
       below the fold. Desktop re-enlarges this in its media block. */
    height: clamp(96px, 17.6vh, 168px);
    /* contain, not cover: the art mixes photographs with logo cards (QUICK GAME lettering,
       brand marks), and cropping a logo beheads it. The panel behind supplies the frame. */
    object-fit: contain;
    border-radius: 36px;
    background: var(--primary-dark-t2);
}

/* Photographic covers (jpg) have no transparency to protect — they fill the panel edge to
   edge instead of letterboxing on the dark ground. Logo art (png) stays contained above. */
.ag-hero--photo img { object-fit: cover; }

/* SpaceLobbyPage rotated and scaled the hero as the page scrolled. */
.ag-hero--tilt img {
    transform: rotateX(calc(var(--tilt, 0) * 1deg)) scale(calc(1 - var(--tilt, 0) / 90));
    transition: transform .14s var(--ease-out);
}

/* ---------------------------------------------------------------- game screen */

.ag-gamebar {
    padding: 5px;
    background: var(--gold-bar);
}

.ag-gamebar__inner {
    display: flex;
    justify-content: center;
    gap: 6px;
    width: 100%;
}

.ag-stat {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 5px 16px;
    border-radius: 10px;
    background: var(--primary-dark);
}

.ag-stat__icon { width: 26px; height: 26px; }
.ag-stat__label {
    font-size: 9px;
    font-weight: 700;
    letter-spacing: .16em;
    text-transform: uppercase;
    opacity: .75;
}
.ag-stat__value { font-weight: 700; font-size: 15px; font-variant-numeric: tabular-nums; }

/*
 * Game screen bands: stat bar on top, stage in the middle taking whatever height is left, action
 * row at the bottom. Without this the three simply stacked from the top and left a dead gap
 * below, which is wrong for a full-screen game view.
 */
.ag-game {
    display: flex;
    flex-direction: column;
    min-height: 100%;
}

.ag-game__stage {
    flex: 1 1 auto;
    /* Never shorter than its contents. With min-height: 0 a short window squeezed the stage and
       the turn result (options + versus meter + verdict) spilled down over the action row; the
       verdict's z-index then painted its chips on top of the Lobby button. Now the action row is
       pushed below and .ag-content scrolls instead. */
    min-height: auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    position: relative; /* the turn splash pins itself to this box */
    /* Anchored to the top, not centred: centring made every element's position depend on the
       total height of whatever the current phase rendered, so the counter and the state text
       bounced between states. The HUD slots below give them fixed homes. */
    justify-content: flex-start;
    gap: 6px;
    width: 100%;
    padding-block: 1.5vh 6px;
}

.ag-hud {
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 100%;
    margin-top: 6px;
}

/*
 * Viewport-fit sizing at EVERY width, not just desktop. The clamp-based heights originally
 * lived only in the >=768px block, so a phone-sized window kept the fixed 220px cards and
 * 128px ring and the stage overflowed into a scrollbar, cutting the action row. The desktop
 * media block still overrides these with its own (larger) clamps later in the file.
 */
.ag-game .ag-option { width: clamp(140px, 42vw, 172px); padding: 4px; }
.ag-game .ag-option__img { height: clamp(136px, 27vh, 220px); }
.ag-game .ag-countdown { width: clamp(84px, 13vh, 128px); height: clamp(84px, 13vh, 128px); }
.ag-game .ag-countdown__num { font-size: clamp(24px, 4.5vh, 38px); }
.ag-game .ag-hero img { height: clamp(88px, 16vh, 160px); }
.ag-game .ag-iconbtn__face { width: clamp(42px, 6.5vh, 54px); height: clamp(42px, 6.5vh, 54px); }
.ag-game .ag-infofader { min-height: 34px; padding-block: 2px; }

/* The fallback scroll stays functional but invisible, like every other strip in the app. */
.ag-game { scrollbar-width: none; -ms-overflow-style: none; overscroll-behavior: contain; }
.ag-game::-webkit-scrollbar { width: 0; height: 0; }

/* The counter's reserved slot: same height whether or not a ring is showing. */
.ag-hud__cd {
    display: grid;
    place-items: center;
    height: clamp(92px, 14vh, 140px);
}

.ag-game__stage > * { width: 100%; }

.ag-game__actions {
    flex: 0 0 auto;
    width: 100%;
    padding-bottom: 14px;
}

/* -- countdown ring -- */

/*
 * GamePage's countdown: a radial-gradient ring whose border colour steps through gradLevels by
 * seconds remaining, with the whole block scaling 0.75 -> 1.0 on each tick and the number
 * fading in. The tick animation is re-keyed per second so it restarts.
 */
.ag-countdown {
    display: grid;
    place-items: center;
    width: 128px;
    height: 128px;
    margin: 0 auto;
    border-radius: 50%;
    background:
        radial-gradient(circle at 50% 50%,
            var(--primary-dark-t1) 38%,
            var(--ring, var(--primary-light-t3)) 62%,
            transparent 72%);
    animation: ag-cd-tick 1s var(--ease-out);
}

.ag-countdown__num {
    font-weight: 700;
    font-size: 38px;
    font-variant-numeric: tabular-nums;
    animation: ag-cd-num 820ms var(--ease-out);
}

@keyframes ag-cd-tick {
    from { transform: scale(.75); }
    to   { transform: scale(1); }
}

@keyframes ag-cd-num {
    from { opacity: .15; }
    to   { opacity: 1; }
}

/* -- option cards -- */

.ag-options {
    position: relative; /* the voter rails pin to this box */
    z-index: 1;
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 16px;
    padding: 10px var(--gutter);
    perspective: 900px;
}

.ag-option {
    position: relative;
    flex: 0 0 auto;
    width: 172px;
    padding: 5px;
    border-radius: 20px;
    background: linear-gradient(180deg, var(--gold-3) 0%, var(--gold-2) 50%, var(--gold-3) 100%);
    opacity: .85;
    transform-style: preserve-3d;
    transition: transform var(--dur-slow) var(--ease-out),
                opacity var(--dur-slow) var(--ease-out),
                margin var(--dur-slow) var(--ease-out);
}

.ag-option__img {
    display: block;
    width: 100%;
    height: 220px;
    object-fit: cover;
    border-radius: 16px;
}

.ag-option__name {
    position: absolute;
    left: 0; right: 0; bottom: 10px;
    text-align: center;
    font-weight: 700;
    font-size: 17px;
    text-shadow: 0 2px 6px #000;
}

/*
 * The logo stamp OptionView revealed on the card you picked.
 *
 * Sized explicitly rather than with `inset`. An inset-sized absolute element takes its box from
 * the nearest positioned ancestor, and .ag-options sets `perspective`, which makes IT a
 * containing block — so the stamp escaped its card and rendered as a huge triangle across the
 * whole options row.
 */
.ag-option__stamp {
    position: absolute;
    left: 50%;
    top: 50%;
    width: 44%;
    max-width: 120px;
    height: auto;
    transform: translate(-50%, -50%);
    object-fit: contain;
    pointer-events: none;
    animation: ag-stamp 900ms var(--ease-out) both;
}

@keyframes ag-stamp {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* The idle "breathing" tilt GamePage ran while the Choose phase was open. */
.ag-options.is-choosing .ag-option--a { animation: ag-breathe-a 2.6s var(--ease-in-out) infinite; }
.ag-options.is-choosing .ag-option--b { animation: ag-breathe-b 2.6s var(--ease-in-out) infinite; }

@keyframes ag-breathe-a {
    0%, 100% { transform: scale(.95) rotateX(1deg); }
    50%      { transform: scale(1) rotateX(-1deg); }
}

@keyframes ag-breathe-b {
    0%, 100% { transform: scale(1) rotateX(-1deg); }
    50%      { transform: scale(.95) rotateX(1deg); }
}

/*
 * ChooseAnimation / WinAnimation.
 *
 * Mobile scaled the chosen card to 1.15 and the winner to 2x and slid them around. A transform
 * does not affect layout, so on the web those values pushed the cards straight over the result
 * rows and the status message underneath. Emphasis is kept, but inside the card's own slot.
 */
.ag-option.is-picked  { opacity: 1; transform: scale(1.05); z-index: 2; }
.ag-option.is-dropped { opacity: .22; transform: scale(.92); }

.ag-option.is-winner { opacity: 1; transform: scale(1.06); z-index: 3; }
.ag-option.is-loser  { opacity: .12; transform: scale(.9); }

/* -- versus meter (vote reveal) -- */

/*
 * The live tally during the reveal.
 *
 * This replaces a flat progress bar with two plain captions. In Antigame the SMALLER side
 * survives, so the counts are the most consequential thing on screen and each side carries its
 * own live verdict — a player watching the numbers move should be able to see, at a glance,
 * whether they are currently safe. GamePage drove the same moment with two scaling cards and a
 * width-animated label.
 */
.ag-vs {
    position: relative;
    z-index: 4;
    width: min(540px, calc(100% - var(--gutter) * 2));
    margin: 12px auto 0;
}

.ag-vs__teams {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 8px;
}

.ag-vs__team {
    flex: 1 1 0;
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
    padding: 7px 10px;
    border-radius: 14px;
    background: var(--primary-dark-t1);
    border: 1px solid transparent;
    transition: border-color var(--dur) var(--ease-out),
                background-color var(--dur) var(--ease-out),
                box-shadow var(--dur) var(--ease-out);
}

.ag-vs__team--right { flex-direction: row; justify-content: flex-end; text-align: right; }

/* Currently the minority, so currently alive. */
.ag-vs__team.is-safe {
    border-color: var(--primary-light);
    background: linear-gradient(180deg, var(--primary-t1), var(--primary-dark-t1));
    box-shadow: 0 0 18px -4px var(--primary-light);
}

.ag-vs__team.is-doomed { opacity: .72; }

/* Too close to call: neither glowing safe nor dimmed out — gold tension instead. */
.ag-vs__team.is-edge {
    border-color: var(--gold, #d8b24a);
    background: linear-gradient(180deg, var(--primary-t1), var(--primary-dark-t1));
}

.ag-vs__team.is-edge .ag-vs__status {
    color: var(--gold, #d8b24a);
    opacity: 1;
    animation: ag-vs-pulse 0.9s var(--ease-in-out) infinite;
}

.ag-vs__face {
    flex: 0 0 auto;
    width: 42px;
    height: 42px;
    border-radius: 10px;
    object-fit: cover;
}

.ag-vs__meta { min-width: 0; flex: 1 1 auto; }

.ag-vs__name {
    font-weight: 700;
    font-size: 15px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.ag-vs__status {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .14em;
    opacity: .75;
}

.ag-vs__team.is-safe .ag-vs__status {
    color: var(--primary-light);
    opacity: 1;
    animation: ag-vs-pulse 1.4s var(--ease-in-out) infinite;
}

.ag-vs__team.is-doomed .ag-vs__status { color: var(--secondary); }

/* Re-keyed per value, so each new count counts in rather than snapping. */
.ag-vs__count {
    flex: 0 0 auto;
    font-weight: 900;
    font-size: 30px;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    animation: ag-vs-tick 420ms var(--ease-pop) both;
}

.ag-vs__sep {
    flex: 0 0 auto;
    font-weight: 900;
    font-size: 13px;
    letter-spacing: .1em;
    opacity: .5;
}

.ag-vs__bar {
    display: flex;
    height: 20px;
    border-radius: 10px;
    overflow: hidden;
    background: var(--primary-dark);
    box-shadow: inset 0 2px 6px rgba(0, 0, 0, .5);
}

.ag-vs__fill {
    position: relative;
    /* A floor, so the side with zero votes is still visibly a side of the meter. */
    flex-basis: 7%;
    transition: flex-grow .85s var(--ease-out);
    overflow: hidden;
}

.ag-vs__fill--a { background: linear-gradient(180deg, #6c2fa0, #3c1461); }
.ag-vs__fill--b { background: linear-gradient(180deg, #e08ad4, #ce75c3); }

/* A travelling sheen on whichever side is currently surviving. */
.ag-vs__fill.is-safe::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(100deg, transparent 20%, var(--white-t2) 50%, transparent 80%);
    animation: ag-vs-sheen 1.8s var(--ease-in-out) infinite;
}

.ag-vs__hint {
    margin-top: 6px;
    text-align: center;
    font-size: 11px;
    letter-spacing: .08em;
    text-transform: uppercase;
    opacity: .55;
}

@keyframes ag-vs-tick {
    from { transform: scale(1.35); opacity: .35; }
    to   { transform: scale(1); opacity: 1; }
}

@keyframes ag-vs-pulse {
    0%, 100% { opacity: 1; }
    50%      { opacity: .45; }
}

@keyframes ag-vs-sheen {
    from { transform: translateX(-120%); }
    to   { transform: translateX(120%); }
}

/* -- game over -- */

.ag-over {
    position: absolute;
    inset: 0;
    z-index: 30;
    display: grid;
    place-items: center;
    background: var(--black-t1);
    backdrop-filter: blur(2px);
}

.ag-over__card {
    width: min(320px, calc(100vw - 32px));
    padding: 5px;
    border-radius: 20px;
    background: var(--primary-dark-t1);
    text-align: center;
    animation: ag-pop 420ms var(--ease-pop) both;
}

.ag-over__inner {
    padding: 18px;
    border-radius: 16px;
    background: var(--primary-dark-t1);
}

.ag-over__logo { width: 96px; height: 96px; object-fit: contain; }

.ag-over__title {
    margin: 6px 0;
    font-weight: 700;
    font-size: 23px;
    color: var(--primary-light);
}

.ag-over__msg { margin-bottom: 16px; font-size: 17px; }

@keyframes ag-pop {
    from { opacity: 0; transform: scale(.85); }
    to   { opacity: 1; transform: scale(1); }
}

/* ---------------------------------------------------------------- lobby / login bits */

.ag-stack { display: flex; flex-direction: column; }
.ag-row   { display: flex; align-items: center; }
.ag-center { position: relative; z-index: 2; display: grid; place-items: center; }
.ag-spacer { flex: 1; }

.ag-section-title {
    margin: 4px 0;
    padding: 8px 0;
    text-align: center;
    font-weight: 700;
    font-size: 17px;
    background: linear-gradient(180deg,
        transparent 0%,
        var(--primary-dark-t2) 60%,
        transparent 100%);
}

.ag-login {
    position: relative;
    z-index: 1;
    display: grid;
    place-items: center;
    min-height: 100%;
    padding: 24px var(--gutter);
}

.ag-login__box { width: min(330px, 100%); text-align: center; }

.ag-login__logo {
    width: 100%;
    max-height: 170px;
    object-fit: contain;
    animation: ag-logo-in 1.1s var(--ease-out) both;
}

@keyframes ag-logo-in {
    from { opacity: 0; transform: scale(.92); }
    to   { opacity: 1; transform: scale(1); }
}

/* The staged word-by-word reveal of ". . . and the minority wins!" in LoginPage.OnAppearing. */
.ag-slogan {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 5px;
    margin: 6px 0 34px;
    font-size: 23px;
    font-weight: 300;
}

.ag-slogan > * { opacity: 0; animation: ag-word 520ms var(--ease-out) forwards; }
.ag-slogan > :nth-child(1) { animation-delay: .60s; }
.ag-slogan > :nth-child(2) { animation-delay: .80s; }
.ag-slogan > :nth-child(3) { animation-delay: 1.00s; }
.ag-slogan > :nth-child(4) { animation-delay: 1.20s; }
.ag-slogan > :nth-child(5) { animation-delay: 1.60s; }
.ag-slogan > :nth-child(6) { animation-delay: 2.00s; font-weight: 700; }
.ag-slogan > :nth-child(7) { animation-delay: 2.75s; font-weight: 700; }

@keyframes ag-word { to { opacity: 1; } }

/*
 * The form language. Replaced the ported flat white rows: fields are frosted dark capsules in
 * the app's own palette, with a small floating caption and an accent glow on focus. One block
 * styles EVERY form in the app — login, register, onboarding, profile, wallet, KYC.
 */
.ag-field {
    display: grid;
    gap: 5px;
    margin-bottom: 14px;
    text-align: left;
}

.ag-field__label {
    padding-left: 14px;
    font-size: 10.5px;
    font-weight: 800;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: var(--primary-light);
    opacity: .9;
}

.ag-field input,
.ag-field select {
    width: 100%;
    min-width: 0;
    padding: 13px 16px;
    border: 1.5px solid var(--white-t1);
    border-radius: 16px;
    font-family: inherit;
    font-size: 15px;
    color: var(--light);
    background: var(--primary-dark-t2);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    transition: border-color .2s var(--ease-out), box-shadow .2s var(--ease-out);
}

.ag-field input::placeholder { color: var(--light); opacity: .35; }

.ag-field input:focus,
.ag-field select:focus {
    outline: none;
    border-color: var(--primary-light);
    box-shadow: 0 0 0 3px var(--primary-light-t2), 0 0 22px -6px var(--primary-light);
}

.ag-field select option { background: var(--primary-dark); color: var(--light); }

/* Native date/number widgets pick up the dark scheme instead of flashing white. */
.ag-field input[type="date"] { color-scheme: dark; }

.ag-login__footer {
    position: absolute;
    bottom: 10px;
    left: 0; right: 0;
    text-align: center;
    font-size: 12px;
}

.ag-login__url {
    display: inline-block;
    margin-bottom: 4px;
    padding: 4px 14px;
    border-radius: 10px;
    background: var(--black-t3);
}

.ag-login__copy { font-weight: 100; opacity: .9; }

/* ---------------------------------------------------------------- game feel */

/* In-game captions speak HUD, not sentence case. */
.ag-game .ag-infofader__line {
    text-transform: uppercase;
    letter-spacing: .16em;
    font-weight: 700;
    font-size: 15px;
}

/* -- verdict banner: what the turn did to YOU -- */

.ag-verdict {
    /*
     * An overlay stamp over the scene, not flow content. In the flow its ~150px pushed the
     * TurnResult state past short viewports and the game scrolled mid-round; layered over the
     * dimmed loser / glowing winner it reads MORE like a verdict, not less. ag-pop could not
     * be reused: its keyframes write `transform` and would stomp the centring translate.
     */
    position: absolute;
    left: 50%;
    top: 54%;
    transform: translate(-50%, -50%);
    z-index: 5;
    width: min(440px, calc(100% - var(--gutter) * 2));
    padding: 14px 18px 16px;
    border-radius: 18px;
    background: var(--primary-dark-t1);
    -webkit-backdrop-filter: blur(10px) saturate(1.2);
    backdrop-filter: blur(10px) saturate(1.2);
    border: 1px solid var(--white-t3);
    text-align: center;
    pointer-events: none;
    animation: ag-verdict-in 460ms var(--ease-pop) both;
}

@keyframes ag-verdict-in {
    from { opacity: 0; transform: translate(-50%, -50%) scale(.82); }
    to   { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}

.ag-verdict__title {
    font-weight: 900;
    font-size: clamp(30px, 6vh, 44px);
    line-height: 1.05;
    text-transform: uppercase;
    letter-spacing: .07em;
}

.ag-verdict--safe .ag-verdict__title {
    color: var(--primary-light);
    text-shadow: 0 0 26px var(--primary-light-t1);
}

.ag-verdict--out .ag-verdict__title {
    color: var(--secondary);
    text-shadow: 0 0 26px rgba(255, 48, 62, .5);
}

.ag-verdict--tie .ag-verdict__title {
    color: var(--gold-2);
    text-shadow: 0 0 22px rgba(249, 245, 196, .45);
}

.ag-verdict--info .ag-verdict__title { color: var(--light); }

.ag-verdict__sub {
    margin-top: 3px;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .18em;
    text-transform: uppercase;
    opacity: .8;
}

.ag-verdict__chips {
    display: flex;
    justify-content: center;
    gap: 10px;
    margin-top: 10px;
}

.ag-chip {
    padding: 5px 14px;
    border-radius: 999px;
    background: var(--primary-dark-t1);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .14em;
    text-transform: uppercase;
}

.ag-chip b {
    margin-right: 4px;
    font-size: 14px;
    font-variant-numeric: tabular-nums;
}

.ag-chip--out { border: 1px solid rgba(234, 93, 107, .5); color: var(--secondary-light); }
.ag-chip--in  { border: 1px solid var(--primary-light-t1); color: var(--primary-light); }

/* -- transport-down banner -- */

.ag-reconnect {
    position: relative;
    z-index: 6;
    width: fit-content;
    margin: 6px auto 0;
    padding: 6px 18px;
    border-radius: 999px;
    border: 1px solid var(--gold-1);
    background: var(--primary-dark-t1);
    color: var(--gold-2);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .16em;
    text-transform: uppercase;
    animation: ag-vs-pulse 1.2s var(--ease-in-out) infinite;
}

/* -- spectator ribbon: a knockout tag, not a form-validation error -- */

.ag-ko {
    position: relative;
    z-index: 4;
    width: fit-content;
    margin: 8px auto;
    padding: 7px 18px;
    border-radius: 999px;
    border: 1px solid rgba(255, 161, 170, .4);
    background: linear-gradient(180deg, rgba(211, 64, 78, .85), rgba(140, 28, 40, .85));
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .12em;
    text-transform: uppercase;
}

/* -- seat meter: the lobby as a filling gauge -- */

.ag-seatmeter {
    width: min(380px, calc(100% - var(--gutter) * 2));
    margin: 2px auto 0;
    text-align: center;
}

.ag-seatmeter__row {
    display: flex;
    align-items: baseline;
    justify-content: center;
    gap: 7px;
}

.ag-seatmeter__row img { width: 18px; height: 18px; align-self: center; object-fit: contain; }

.ag-seatmeter__count {
    font-size: 32px;
    font-weight: 900;
    font-variant-numeric: tabular-nums;
}

.ag-seatmeter__req {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .14em;
    text-transform: uppercase;
    opacity: .7;
}

.ag-seatmeter__bar {
    height: 12px;
    margin-top: 8px;
    border-radius: 6px;
    overflow: hidden;
    background: var(--primary-dark);
    box-shadow: inset 0 2px 5px rgba(0, 0, 0, .5);
}

.ag-seatmeter__fill {
    height: 100%;
    border-radius: 6px;
    background: linear-gradient(90deg, var(--primary-light), var(--secondary));
    transition: width .7s var(--ease-out);
}

.ag-seatmeter__hint {
    margin-top: 7px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .12em;
    text-transform: uppercase;
    opacity: .7;
}

/* -- turn splash -- */

.ag-turnsplash {
    /*
     * Pinned to the stage's centre as an overlay. A splash is not flow content — leaving it in
     * the flex flow let it end up stranded at the viewport edge — and ag-pop could not be
     * reused: its keyframes write `transform`, which would stomp the centring translate, so
     * the entrance below carries the translate inside its own keyframes.
     */
    position: absolute;
    left: 50%;
    top: 38%;
    transform: translate(-50%, -50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    line-height: 1;
    pointer-events: none;
    animation: ag-splash-in 520ms var(--ease-pop) both;
}

@keyframes ag-splash-in {
    from { opacity: 0; transform: translate(-50%, -50%) scale(.78); }
    to   { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}

.ag-turnsplash__label {
    /* letter-spacing adds a phantom space after the LAST letter as well, so the box is wider
       on the right than the glyphs; trimming it is what actually centres the word. */
    margin-right: -.5em;
    font-size: 13px;
    font-weight: 700;
    letter-spacing: .5em;
    text-transform: uppercase;
    opacity: .75;
}

.ag-turnsplash__num {
    font-size: clamp(64px, 16vh, 118px);
    font-weight: 900;
    color: var(--light);
    text-shadow: 0 0 38px var(--primary-light-t1), 0 4px 0 var(--primary-dark);
}

/* -- countdown alarm: the last seconds should feel like last seconds -- */

.ag-countdown.is-critical {
    animation: ag-cd-tick 1s var(--ease-out), ag-cd-alarm .55s var(--ease-in-out) infinite alternate;
}

@keyframes ag-cd-alarm {
    from { box-shadow: 0 0 8px -4px rgba(255, 48, 62, .25); }
    to   { box-shadow: 0 0 38px 4px rgba(255, 48, 62, .55); }
}

/* -- leave row -- */

.ag-leave {
    display: grid;
    place-items: center;
    padding: 4px var(--gutter) 2px;
}

/* Twin equal-width actions side by side. */
.ag-leave--pair {
    display: flex;
    justify-content: center;
    gap: 10px;
}

.ag-btn--even { width: 170px; }

.ag-btn__ico {
    width: 18px;
    height: 18px;
    object-fit: contain;
}

.ag-leave__hint {
    position: relative;
    z-index: 2;
    margin-top: 6px;
    text-align: center;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .16em;
    text-transform: uppercase;
    opacity: .55;
}

/* -- room stat tiles (join screen) -- */

.ag-tiles {
    display: grid;
    grid-template-columns: repeat(2, minmax(140px, 180px));
    gap: 10px;
    justify-content: center;
    padding: 4px var(--gutter);
}

.ag-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 3px;
    padding: clamp(9px, 1.6vh, 14px) 10px clamp(8px, 1.4vh, 11px);
    border-radius: 14px;
    border: 1px solid var(--white-t3);
    background: var(--primary-dark-t2);
    animation: ag-tile-pulse 8s var(--ease-in-out) var(--delay, 0s) infinite;
}

.ag-tile img { width: 30px; height: 30px; object-fit: contain; }

.ag-tile__value {
    font-size: 24px;
    font-weight: 900;
    font-variant-numeric: tabular-nums;
}

.ag-tile__dim { font-size: 15px; font-weight: 700; opacity: .6; }

.ag-tile__label {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .16em;
    text-transform: uppercase;
    opacity: .7;
    text-align: center;
}

@keyframes ag-tile-pulse {
    0%, 18%, 100% { transform: scale(1); }
    8%            { transform: scale(1.05); }
}

/* -- small room thumb (My Games) -- */

.ag-thumb-sm {
    flex: 0 0 auto;
    width: 52px;
    height: 52px;
    padding: 4px;
    border-radius: 10px;
    object-fit: contain; /* logo cards again — never crop them */
    background: var(--primary-dark);
}

/* -- end card outcomes -- */

.ag-over__title { text-transform: uppercase; letter-spacing: .06em; }

.ag-over__card--win {
    background: linear-gradient(180deg, rgba(202, 166, 96, .45), var(--primary-dark-t1));
    box-shadow: 0 0 48px -6px rgba(249, 245, 196, .45);
}

.ag-over__card--win .ag-over__title {
    background: var(--gold-bar);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}

.ag-over__card--cash .ag-over__title { color: var(--gold-2); }
.ag-over__card--out .ag-over__title { color: var(--secondary); }

.ag-over__payout {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    margin: 2px 0 12px;
    font-size: 32px;
    font-weight: 900;
    font-variant-numeric: tabular-nums;
    animation: ag-pop 520ms var(--ease-pop) both;
}

.ag-over__payout img { width: 28px; height: 28px; object-fit: contain; }

.ag-over__list { display: grid; gap: 4px; margin-bottom: 14px; }

.ag-over__row {
    display: flex;
    justify-content: space-between;
    gap: 10px;
    padding: 6px 12px;
    border-radius: 8px;
    background: var(--primary-dark-t2);
    font-size: 14px;
}

.ag-over__row-payout {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.ag-over__row-payout img { width: 16px; height: 16px; object-fit: contain; }

/* ---------------------------------------------------------------- misc */

.ag-empty {
    padding: 50px var(--gutter);
    text-align: center;
    opacity: .75;
}

.ag-error {
    position: relative;
    z-index: 4;
    margin: 10px auto;
    padding: 10px 14px;
    max-width: 420px;
    border-radius: 10px;
    background: var(--secondary-dark);
    font-size: 13px;
    text-align: center;
}

.ag-toast {
    position: absolute;
    left: 50%;
    bottom: calc(var(--nav-h) + 20px);
    z-index: 40;
    transform: translateX(-50%);
    padding: 9px 18px;
    border-radius: 20px;
    background: var(--black-t1);
    font-size: 13px;
    animation: ag-toast-in var(--dur) var(--ease-pop) both;
}

@keyframes ag-toast-in {
    from { opacity: 0; transform: translate(-50%, 10px); }
    to   { opacity: 1; transform: translate(-50%, 0); }
}

.ag-spinner {
    width: 34px;
    height: 34px;
    border: 3px solid var(--white-t3);
    border-top-color: var(--primary-light);
    border-radius: 50%;
    animation: ag-spin 900ms linear infinite;
}

@keyframes ag-spin { to { transform: rotate(360deg); } }

/* ---------------------------------------------------------------- panning */

/*
 * A horizontal strip panned with a finger on mobile. A desktop mouse can do neither of the things
 * that made that work: dragging selects the card text instead of moving the strip, and a vertical
 * wheel does nothing to a horizontal container. The behaviour is added in antigame.js; this is
 * the part that has to be CSS.
 */
.ag-spaces {
    cursor: grab;
    -webkit-user-select: none;
    user-select: none;
    touch-action: pan-x pan-y;
    overscroll-behavior-x: contain;
}

.ag-spaces.is-dragging {
    cursor: grabbing;
    scroll-behavior: auto;
}

/*
 * Nothing in a game is text to copy: a stray blue selection mid-round reads as a glitch.
 * App-wide, with the two places typing happens opted back in.
 */
.ag-app {
    -webkit-user-select: none;
    user-select: none;
    background: var(--primary-dark); /* floor under the breathing tint */
}

.ag-app input,
.ag-app textarea {
    -webkit-user-select: text;
    user-select: text;
}

/* Desktop paging arrows for the carousel. Hidden where a finger can just push the strip. */
.ag-carousel { position: relative; flex: 1; min-height: 0; }

.ag-carousel__arrow {
    position: absolute;
    top: 50%;
    z-index: 5;
    display: none;
    place-items: center;
    width: 48px;
    height: 48px;
    margin-top: -24px;
    border-radius: 50%;
    background: var(--primary-dark-t1);
    border: 1px solid var(--white-t3);
    backdrop-filter: blur(4px);
    color: var(--light);
    font-size: 22px;
    line-height: 1;
    transition: background-color var(--dur) var(--ease-out),
                transform var(--dur) var(--ease-out),
                border-color var(--dur) var(--ease-out);
}

.ag-carousel__arrow:hover { background: var(--primary); transform: scale(1.08); }
.ag-carousel__arrow--prev { left: 18px; }
.ag-carousel__arrow--next { right: 18px; }

/* ---------------------------------------------------------------- responsive */

/*
 * The Xamarin layout is a phone layout, and stretching it across a 1900px browser window leaves
 * a full-bleed hero image, a stat bar marooned in the middle of an empty gold band, and content
 * hugging nothing. Everything below re-centres the design into a column and scales the pieces
 * that were sized in raw pixels for a handset.
 */

@media (min-width: 768px) {
    :root {
        --header-h: 132px;
        --nav-h: 96px;
        --gutter: 24px;
        --app-max: 1180px;
        --read-max: 720px;
    }

    /*
     * Chrome keeps a full-bleed background while its contents sit in the centred column.
     * Done with padding rather than max-width + auto margins, so the bar itself still spans the
     * window — constraining the element shrinks its background too, which left the wallet strip
     * and the tab bar as floating islands.
     */
    .ag-header__top,
    .ag-header__wallet,
    .ag-nav,
    .ag-gamebar {
        padding-inline: max(var(--gutter), calc(50% - var(--app-max) / 2));
    }

    .ag-header__title { font-size: 23px; }
    .ag-header__logo { width: 50px; height: 50px; }
    .ag-avatar img { width: 44px; height: 44px; }
    .ag-header__name { max-width: 220px; font-size: 14px; }

    .ag-nav__item { flex: 1 1 0; max-width: 170px; }

    /* The hero was HeightRequest="220" on a ~400px wide phone. Full width it is a letterbox. */
    .ag-hero {
        max-width: var(--read-max);
        margin-inline: auto;
    }

    .ag-hero img { height: 240px; }

    /* The gold band stays edge to edge; the stats sit in the column. */
    .ag-gamebar { padding-block: 8px; }
    .ag-stat { padding: 7px 22px; }
    .ag-stat__value { font-size: 17px; }

    .ag-option { width: 240px; }
    .ag-option__img { height: 300px; }
    .ag-option__name { font-size: 19px; }
    .ag-options { gap: 20px; }

    .ag-countdown { width: 152px; height: 152px; }
    .ag-countdown__num { font-size: 46px; }

    .ag-infofader__line { font-size: 21px; }


    .ag-room { max-width: var(--read-max); }

    .ag-carousel__arrow { display: grid; }

    /*
     * Cards align to the start of the centred column rather than centring one card in the
     * viewport. Centring needs half-a-viewport of padding, which on a wide screen is the huge
     * empty gutter that made the strip look broken.
     */
    .ag-spaces {
        padding-inline: max(var(--gutter), calc(50% - var(--app-max) / 2));
        scroll-snap-type: x proximity;
        scroll-padding-left: max(var(--gutter), calc(50% - var(--app-max) / 2));
    }

    .ag-space {
        width: 248px;
        scroll-snap-align: start;
    }

    /* On desktop every card is legible, so the de-emphasis is much gentler. */
    .ag-space { opacity: .88; transform: scale(.95); }
    .ag-space.is-active { opacity: 1; transform: scale(1); }
    .ag-space:hover { opacity: 1; transform: scale(.98) translateY(-4px); }
    .ag-space.is-active:hover { transform: scale(1.02) translateY(-4px); }

    .ag-space__desc { min-height: 64px; }

    .ag-login__box { width: 380px; }
    .ag-over__card { width: 380px; }
}

    /*
     * The game is a view, not a document: on a desktop window everything from the stat bar to the
     * action buttons has to be visible at once. Left to scroll, the countdown and the Cashout row
     * sat below the fold and the player had to hunt for them mid-turn.
     */
    /*
     * Not `hidden`. The phases differ in height, and clipping meant a taller one simply lost its
     * lower half — the action buttons or the result panel would vanish with no way to reach them,
     * which reads as the game having frozen.
     */
    .ag-game { overflow-y: auto; }

    /*
     * Sized against viewport height, not fixed pixels: the cards are the one element big enough
     * to push the Cashout row off a short window, and a laptop screen is routinely under 800px.
     */
    .ag-game .ag-options { margin-top: 0; padding-block: 4px; }
    .ag-game .ag-option__img { height: clamp(150px, 30vh, 260px); }
    .ag-game .ag-option { padding: 4px; }
    .ag-game .ag-countdown { width: clamp(92px, 13vh, 120px); height: clamp(92px, 13vh, 120px); }
    .ag-game .ag-countdown__num { font-size: clamp(26px, 4.2vh, 36px); }
    .ag-game .ag-infofader { min-height: 38px; padding-block: 2px; }
    .ag-game .ag-hero img { height: clamp(112px, 21vh, 168px); }
    .ag-game .ag-gamebar { padding-block: 5px; }
    .ag-game .ag-iconbtn__face { width: 46px; height: 46px; }
    .ag-game .ag-iconbtn { margin: 2px 5px; }

}

@media (min-width: 1400px) {
    :root { --app-max: 1320px; }
    .ag-space { width: 268px; }
    .ag-hero img { height: 272px; }
}

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .01ms !important;
    }
}


/* ---------------------------------------------------------------- accounts, shop, kyc */

/* Mode links under the login button. */
.ag-login__switch {
    margin-top: 14px;
    display: flex;
    justify-content: center;
    gap: 18px;
}

.ag-login__switch button {
    background: none;
    border: 0;
    color: var(--primary-light);
    font: inherit;
    font-size: 13px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    cursor: pointer;
    opacity: .85;
}

.ag-login__switch button:hover { opacity: 1; text-decoration: underline; }

.ag-consent {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin: 10px 2px 0;
    font-size: 12.5px;
    line-height: 1.45;
    color: var(--light);
    opacity: .9;
    cursor: pointer;
    -webkit-user-select: none;
    user-select: none;
}

.ag-consent input { margin-top: 2px; accent-color: var(--secondary); }

/* ---- onboarding ---- */

.ag-onboard__title {
    font-size: 26px;
    font-weight: 900;
    color: var(--primary-light);
    text-align: center;
    margin-top: 10px;
}

.ag-onboard__body {
    margin-top: 10px;
    text-align: center;
    font-size: 15px;
    line-height: 1.6;
    opacity: .92;
}

.ag-onboard__body b { color: var(--secondary); }

.ag-onboard__dots {
    display: flex;
    justify-content: center;
    gap: 8px;
    margin: 18px 0 14px;
}

.ag-onboard__dots span {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--white-t2);
    transition: background .3s var(--ease-out), transform .3s var(--ease-out);
}

.ag-onboard__dots span.is-on { background: var(--secondary); transform: scale(1.25); }

.ag-avatarpick {
    display: grid;
    justify-items: center;
    gap: 12px;
    margin: 14px 0 6px;
}

.ag-avatarpick input[type="range"] {
    width: min(240px, 80%);
    accent-color: var(--secondary);
}

/* ---- initials avatar: no uploads, a hue is the identity ---- */

.ag-avatar--initials {
    width: 72px;
    height: 72px;
    display: grid;
    place-items: center;
    border-radius: 50%;
    font-weight: 900;
    font-size: 26px;
    color: #fff;
    background: linear-gradient(145deg,
        hsl(var(--hue, 275), 70%, 55%),
        hsl(calc(var(--hue, 275) + 40), 72%, 38%));
    border: 3px solid var(--white-t2);
    text-shadow: 0 2px 4px rgba(0, 0, 0, .35);
}

.ag-avatar--big { width: 96px; height: 96px; font-size: 34px; }

/* ---- kyc status chip ---- */

.ag-kyc {
    padding: 2px 10px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 800;
    letter-spacing: .1em;
    text-transform: uppercase;
}

.ag-kyc--approved { background: var(--primary-light-t1); color: var(--primary-light); }
.ag-kyc--pending { background: var(--gold-t1, rgba(216, 178, 74, .18)); color: var(--gold1, #d8b24a); }
.ag-kyc--rejected { background: rgba(211, 64, 78, .18); color: var(--secondary); }
.ag-kyc--none { background: var(--white-t1); color: var(--light); opacity: .8; }

/* ---- wallet / shop ---- */

/* (the old .ag-wallet__balances strip was replaced by the hero tiles below) */

.ag-packs {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 10px;
    width: min(440px, 100%);
}

.ag-pack {
    flex: 1 1 120px;
    max-width: 136px;
    display: grid;
    justify-items: center;
    gap: 4px;
    padding: 14px 10px;
    border: 1px solid var(--white-t1);
    border-radius: 18px;
    background: linear-gradient(180deg, var(--primary-t1), var(--primary-dark-t2));
    color: var(--light);
    font: inherit;
    cursor: pointer;
    transition: transform .18s var(--ease-out), border-color .18s var(--ease-out);
}

.ag-pack:hover:not(:disabled) { transform: translateY(-2px); border-color: var(--primary-light); }
.ag-pack:disabled { opacity: .55; cursor: default; }
.ag-pack img { width: 34px; height: 34px; }
.ag-pack__amount { font-size: 19px; font-weight: 900; }
.ag-pack__name { font-size: 11px; opacity: .75; }

.ag-pack__price {
    margin-top: 4px;
    padding: 3px 12px;
    border-radius: 999px;
    background: var(--secondary);
    font-size: 12.5px;
    font-weight: 800;
}

/* ---- transaction history rows ---- */

.ag-tx {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 0;
    border-bottom: 1px solid var(--white-t1);
    font-size: 13.5px;
}

.ag-tx:last-child { border-bottom: 0; }

.ag-tx__icon { width: 22px; height: 22px; flex: 0 0 auto; }

.ag-tx__main { flex: 1; min-width: 0; display: grid; line-height: 1.25; }
.ag-tx__type { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ag-tx__time { font-size: 10.5px; opacity: .55; letter-spacing: .04em; }

.ag-tx__status {
    font-size: 10px;
    font-weight: 800;
    letter-spacing: .08em;
    text-transform: uppercase;
    opacity: .7;
}

.ag-tx__status--pending { color: var(--gold1, #d8b24a); opacity: 1; }
.ag-tx__status--rejected { color: var(--secondary); opacity: 1; }
.ag-tx__status--completed, .ag-tx__status--approved { display: none; } /* the normal case is silent */

.ag-tx__delta { font-weight: 800; font-variant-numeric: tabular-nums; }
.ag-tx__delta.is-credit { color: var(--primary-light); }
.ag-tx__delta.is-debit { opacity: .85; }

/* ---- file inputs on the KYC form: a drop-zone capsule, not a bare browse row ---- */

.ag-field input[type="file"] {
    width: 100%;
    padding: 18px 16px;
    border: 1.5px dashed var(--primary-light-t1);
    border-radius: 16px;
    background: var(--primary-dark-t2);
    color: var(--light);
    font-size: 13px;
    cursor: pointer;
    transition: border-color .2s var(--ease-out), background .2s var(--ease-out);
}

.ag-field input[type="file"]:hover {
    border-color: var(--primary-light);
    background: var(--primary-t1);
}

.ag-field input[type="file"]::file-selector-button {
    margin-right: 12px;
    padding: 8px 16px;
    border: 0;
    border-radius: 999px;
    background: var(--primary-light);
    color: var(--primary-dark);
    font: inherit;
    font-size: 12px;
    font-weight: 800;
    letter-spacing: .06em;
    text-transform: uppercase;
    cursor: pointer;
}


/* ---- onboarding demo graphics: the rule shown, not described ---- */

.ag-ob-demo {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 14px;
    margin: 20px 0 8px;
}

.ag-ob-side {
    display: grid;
    justify-items: center;
    gap: 4px;
    padding: 10px 12px 12px;
    border-radius: 18px;
    border: 2px solid var(--white-t1);
    background: var(--primary-dark-t2);
    transition: transform .4s var(--ease-out);
}

.ag-ob-side img {
    width: 84px;
    height: 104px;
    object-fit: cover;
    border-radius: 12px;
}

.ag-ob-side.is-safe {
    border-color: var(--primary-light);
    box-shadow: 0 0 26px -6px var(--primary-light);
    transform: scale(1.06);
}

.ag-ob-side.is-out { opacity: .55; }

.ag-ob-count { font-size: 26px; font-weight: 900; line-height: 1; }

.ag-ob-tag {
    font-size: 10px;
    font-weight: 800;
    letter-spacing: .18em;
}

.ag-ob-side.is-safe .ag-ob-tag { color: var(--primary-light); animation: ag-vs-pulse 1.4s var(--ease-in-out) infinite; }
.ag-ob-side.is-out .ag-ob-tag { color: var(--secondary); }

.ag-ob-vs {
    font-size: 13px;
    font-weight: 800;
    letter-spacing: .1em;
    opacity: .6;
    text-transform: uppercase;
}

.ag-ob-pot {
    display: grid;
    justify-items: center;
    gap: 10px;
    margin: 22px 0 10px;
}

.ag-ob-pot__chest { width: 86px; height: 86px; object-fit: contain; }

.ag-ob-pot__coins { display: flex; gap: 6px; }
.ag-ob-pot__coins img { width: 30px; height: 30px; animation: ag-ob-bob 1.8s var(--ease-in-out) infinite; }
.ag-ob-pot__coins img:nth-child(2) { animation-delay: .25s; }
.ag-ob-pot__coins img:nth-child(3) { animation-delay: .5s; }

@keyframes ag-ob-bob {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(-7px); }
}

.ag-ob-pot__pill {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 16px;
    border-radius: 999px;
    background: var(--gold2, #b78a28);
    color: #2b1d04;
    font-size: 12px;
    font-weight: 800;
    letter-spacing: .12em;
}

.ag-ob-pot__pill img { width: 20px; height: 20px; }

/* Bigger, calmer copy under the graphics. */
.ag-onboard__body {
    font-size: 17px;
    line-height: 1.5;
    max-width: 300px;
    margin-inline: auto;
}


/* ---------------------------------------------------------------- unified hover language */

/*
 * ONE hover behaviour for every interactive surface: lift 2px, brighten slightly, same
 * duration and easing everywhere. Individual components keep their own glows/borders; the
 * MOTION is what must feel identical across the app.
 */
.ag-btn,
.ag-pack,
.ag-iconbtn__face,
.ag-space,
.ag-room__inner,
.ag-nav__iconwrap,
.ag-balance,
.ag-option.is-selectable,
.ag-header__title.is-back,
.ag-carousel__arrow {
    transition:
        transform .18s var(--ease-out),
        filter .18s var(--ease-out),
        border-color .18s var(--ease-out),
        box-shadow .18s var(--ease-out);
}

.ag-btn:hover:not(:disabled),
.ag-pack:hover:not(:disabled),
.ag-iconbtn:hover:not(:disabled) .ag-iconbtn__face,
.ag-space:hover,
.ag-room:hover .ag-room__inner,
.ag-nav__item:hover .ag-nav__iconwrap,
.ag-balance:hover,
.ag-carousel__arrow:hover {
    transform: translateY(-2px);
    filter: brightness(1.07);
}

.ag-option.is-selectable:hover { filter: brightness(1.07); }

.ag-btn:active:not(:disabled),
.ag-pack:active:not(:disabled) {
    transform: translateY(0);
    filter: brightness(.97);
}

/* The back-title affordance: subtle, discoverable on hover. */
.ag-header__title.is-back { cursor: pointer; }
.ag-header__title.is-back:hover { filter: brightness(1.15); transform: translateX(-2px); }
.ag-header__title.is-back::before {
    content: "‹ ";
    opacity: .55;
}


/* ---------------------------------------------------------------- palette-mapped layers */

/* The wrapper only carries the three --page-hue* variables; it paints nothing itself. */
.ag-hueroot { display: contents; }

/*
 * Each background layer glides to its palette slot: the space cover's MOST USED hue drives
 * the foreground stars, the second the mid layer, the third the deep layer and the tint.
 * Same duration and easing as the tint's own glide, so the whole stack moves as one.
 */
.ag-parallax__layer--1 {
    filter: hue-rotate(var(--page-hue, 0deg)) saturate(var(--page-sat, 1));
    transition: filter 900ms var(--ease-in-out);
}

.ag-parallax__layer--2 {
    filter: hue-rotate(var(--page-hue-mid, 0deg)) saturate(var(--page-sat, 1));
    transition: filter 900ms var(--ease-in-out);
}

.ag-parallax__layer--3 {
    filter: hue-rotate(var(--page-hue-front, 0deg)) saturate(var(--page-sat, 1));
    transition: filter 900ms var(--ease-in-out);
}


/* ---------------------------------------------------------------- reveal voter rails */

/*
 * The reveal's roll call: a FEED per side in the empty flank beside each card. Names stack
 * in vote order, newest at the bottom; each entry grows in from its card's side, and when
 * the column fills, the elders glide up and dissolve through the top mask — the list
 * scrolls itself, no scrollbar. Left rail reads toward its card (right-aligned), right rail
 * away from its (left-aligned). The feed stays up through the turn result.
 */
.ag-voters {
    /* Anchored to the CARD PAIR's geometry, not the row edges: the pair is centred, each
       card is var(--optw) wide with a 16px gap, so every offset below is exact. */
    --optw: clamp(140px, 42vw, 172px);
    position: absolute;
    top: 6px;
    bottom: 6px;
    width: clamp(110px, 16vw, 190px);
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    gap: 3px;
    overflow: hidden;
    pointer-events: none;
    z-index: 3;
    /* elders dissolve as they are pushed out the top */
    -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 22%);
    mask-image: linear-gradient(180deg, transparent 0, #000 22%);
}

/* Desktop: flush BESIDE each card — the rail's inner edge hugs the card's outer edge. */
.ag-voters--l { right: calc(50% + var(--optw) + 18px); left: auto; align-items: flex-end; text-align: right; }
.ag-voters--r { left: calc(50% + var(--optw) + 18px); right: auto; align-items: flex-start; text-align: left; }

.ag-voter {
    /* NEVER shrink: a full column must push elders out through the top mask (the scroll),
       not compress every label into unreadable slivers — flex items shrink by default. */
    flex: 0 0 auto;
    max-width: 100%;
    max-height: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--vsize, 12px);
    font-weight: 700;
    letter-spacing: .04em;
    line-height: 1.35;
    color: var(--light);
    text-shadow: 0 1px 8px rgba(0, 0, 0, .65);
    opacity: 0;
    will-change: transform, opacity, max-height;
    /* Growing max-height is what makes the whole column GLIDE up for each arrival,
       instead of the stack snapping a row higher. */
    animation: ag-voter-in-l .55s cubic-bezier(.22, .68, .32, 1) var(--vdelay, 0ms) forwards;
}

.ag-voters--l .ag-voter { padding-right: 6px; animation-name: ag-voter-in-l; }
.ag-voters--r .ag-voter { padding-left: 6px; animation-name: ag-voter-in-r; }

@keyframes ag-voter-in-l {
    0%   { opacity: 0; max-height: 0; transform: translateX(12px); }
    45%  { max-height: 1.5em; }
    100% { opacity: 1; max-height: 1.5em; transform: translateX(0); }
}

@keyframes ag-voter-in-r {
    0%   { opacity: 0; max-height: 0; transform: translateX(-12px); }
    45%  { max-height: 1.5em; }
    100% { opacity: 1; max-height: 1.5em; transform: translateX(0); }
}

/* Size moods — an intimate table lists large; a crowd lists dense. */
.ag-voters.is-cozy  { --vsize: 13.5px; gap: 4px; }
.ag-voters.is-crowd { --vsize: 12px; }
.ag-voters.is-mega  { --vsize: 10.5px; gap: 2px; }

@media (max-width: 560px) {
    /* Phones have no flanks: the feed lives INSIDE its card, over the art, each column
       hugging its card's outer edge and stopping above the name strip. */
    .ag-voters {
        top: 18px;
        bottom: 22%;
        width: calc(var(--optw) - 20px);
    }

    .ag-voters--l {
        right: calc(50% + 8px + 10px);
        align-items: flex-start;
        text-align: left;
    }

    .ag-voters--r {
        left: calc(50% + 8px + 10px);
        align-items: flex-end;
        text-align: right;
    }

    .ag-voter { text-shadow: 0 1px 4px rgba(0, 0, 0, .95), 0 0 12px rgba(0, 0, 0, .8); }

    .ag-voters.is-cozy  { --vsize: 11.5px; }
    .ag-voters.is-crowd { --vsize: 10.5px; }
    .ag-voters.is-mega  { --vsize: 10px; }
}


/* ---------------------------------------------------------------- wallet console */

.ag-wallet {
    padding: 10px var(--gutter) 90px;
    display: grid;
    gap: 14px;
    justify-items: center;
}

.ag-wallet__panel, .ag-wallet__herocard { width: min(440px, 100%); }
.ag-wallet__panel .ag-card__inner { padding: 16px; display: grid; gap: 12px; }

/* Hero: the two currencies as tiles, gold featured. */
.ag-wallet__herocard .ag-card__inner { padding: 16px; display: grid; gap: 12px; }

.ag-wallet__hero {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
}

.ag-wallet__tile {
    display: grid;
    justify-items: center;
    gap: 2px;
    padding: 14px 10px 12px;
    border-radius: 18px;
    border: 1px solid var(--white-t1);
    background: linear-gradient(180deg, var(--primary-t1), var(--primary-dark-t2));
}

.ag-wallet__tile img { width: 36px; height: 36px; margin-bottom: 4px; }

.ag-wallet__tile--gold {
    border-color: var(--gold2, #b78a28);
    box-shadow: 0 0 22px -8px var(--gold1, #d8b24a);
}

.ag-wallet__amount {
    font-size: 24px;
    font-weight: 900;
    font-variant-numeric: tabular-nums;
    line-height: 1;
}

.ag-wallet__cur {
    font-size: 9.5px;
    font-weight: 800;
    letter-spacing: .22em;
    opacity: .6;
}

/* Winnings strip: what can actually leave, with its KYC state beside it. */
.ag-wallet__win {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    border-radius: 14px;
    background: var(--primary-dark-t2);
    border: 1px dashed var(--gold2, #b78a28);
}

.ag-wallet__win img { width: 26px; height: 26px; }

.ag-wallet__winmeta { flex: 1; display: grid; line-height: 1.3; }

.ag-wallet__winlabel {
    font-size: 9.5px;
    font-weight: 800;
    letter-spacing: .18em;
    opacity: .6;
}

.ag-wallet__winvalue {
    font-size: 16px;
    font-weight: 900;
    color: var(--gold1, #d8b24a);
}

/* Panel headers share one voice. */
.ag-wallet__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-size: 11px;
    font-weight: 800;
    letter-spacing: .18em;
    opacity: .8;
}

.ag-wallet__rail { color: var(--gold1, #d8b24a); opacity: .9; letter-spacing: .1em; }

.ag-wallet__loading { display: grid; place-items: center; padding: 16px 0; }

/* Net breakdown: the money math, stated before the button is pressed. */
.ag-wallet__net {
    display: grid;
    gap: 4px;
    padding: 10px 14px;
    border-radius: 14px;
    background: var(--primary-dark-t2);
    border: 1px solid var(--white-t1);
    font-size: 13px;
}

.ag-wallet__net > div { display: flex; justify-content: space-between; gap: 12px; }
.ag-wallet__net span { opacity: .75; }
.ag-wallet__net b { font-variant-numeric: tabular-nums; }
.ag-wallet__net .is-net {
    padding-top: 4px;
    border-top: 1px dashed var(--white-t1);
}
.ag-wallet__net .is-net b { color: var(--gold1, #d8b24a); }

/* The money action is gold — sibling of --register (green) in the button family. */
.ag-btn--gold {
    background: linear-gradient(180deg, var(--gold1, #d8b24a), var(--gold2, #b78a28));
    color: #2b1d04;
}

.ag-btn--gold:disabled { filter: saturate(.4) brightness(.8); }


/* ---------------------------------------------------------------- rewarded ad */

/* The free-gold pack: same family as the paid packs, gold-dashed to read as "earned". */
.ag-pack--ad {
    max-width: 200px;
    border-style: dashed;
    border-color: var(--gold2, #b78a28);
}

.ag-pack__play {
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    background: var(--gold1, #d8b24a);
    color: #2b1d04;
    font-size: 14px;
    padding-left: 2px;
}

.ag-pack__price--free {
    background: transparent;
    border: 1px solid var(--gold2, #b78a28);
    color: var(--gold1, #d8b24a);
}

/* The spot: a FULLSCREEN takeover, like a real rewarded ad. The video covers the whole
   viewport; the AD tag, countdown and claim float over it. */
.ag-adplayer {
    position: fixed;
    inset: 0;
    z-index: 40;
    background: #000;
    animation: ag-page-in 240ms var(--ease-out);
}

.ag-adplayer__video {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.ag-adplayer__fallback {
    position: absolute;
    inset: 0;
    display: grid;
    place-content: center;
    justify-items: center;
    gap: 14px;
    text-align: center;
}

.ag-adplayer__fallback img { width: 180px; object-fit: contain; }

.ag-adplayer__tag {
    position: absolute;
    top: max(14px, env(safe-area-inset-top));
    left: 16px;
    padding: 6px 14px;
    border-radius: 999px;
    background: rgba(0, 0, 0, .55);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    font-size: 10px;
    font-weight: 800;
    letter-spacing: .2em;
    color: #fff;
    opacity: .9;
}

.ag-adplayer__pitch { font-size: 15px; opacity: .85; }

.ag-adplayer__cta {
    position: absolute;
    left: 0;
    right: 0;
    bottom: max(26px, env(safe-area-inset-bottom));
    display: grid;
    place-items: center;
}

.ag-adplayer__count {
    display: grid;
    place-items: center;
    width: 54px;
    height: 54px;
    border-radius: 50%;
    border: 3px solid var(--gold-1);
    background: rgba(0, 0, 0, .5);
    font-size: 22px;
    font-weight: 900;
    font-variant-numeric: tabular-nums;
    color: #fff;
}


/* ---------------------------------------------------------------- wallet flow chart */

/*
 * Chart colours are VALIDATED against the card surface (#2b0a47), not eyeballed:
 * in #0ea2c6 / out #ea5d6b / net #b78e2e pass the lightness band, chroma floor,
 * CVD separation (worst adjacent ΔE 15.6) and 3:1 contrast. Change them only through
 * the validator.
 */
.ag-flow {
    --flow-in: #0ea2c6;
    --flow-out: #ea5d6b;
    --flow-net: #b78e2e;
    display: grid;
    gap: 8px;
}

.ag-flow__legend {
    display: flex;
    gap: 16px;
    font-size: 10px;
    font-weight: 800;
    letter-spacing: .14em;
    opacity: .85;
}

.ag-flow__legend span { display: inline-flex; align-items: center; gap: 6px; }
.ag-flow__legend i { width: 10px; height: 10px; border-radius: 3px; }
.ag-flow__legend i.is-line { height: 3px; border-radius: 2px; width: 14px; }

.ag-flow__plot { position: relative; }

.ag-flow__plot svg {
    display: block;
    width: 100%;
    height: clamp(110px, 18vh, 150px);
}

/* Recessive chrome: the grid whispers, the marks speak. */
.ag-flow__axis { stroke: var(--white-t2); stroke-width: 1; }
.ag-flow__grid { stroke: var(--white-t3); stroke-width: 1; stroke-dasharray: 3 4; }

.ag-flow__tip {
    position: absolute;
    top: -4px;
    transform: translateX(-50%);
    display: flex;
    gap: 8px;
    padding: 5px 10px;
    border-radius: 10px;
    background: var(--primary-dark);
    border: 1px solid var(--white-t2);
    font-size: 11.5px;
    white-space: nowrap;
    pointer-events: none;
    z-index: 2;
    font-variant-numeric: tabular-nums;
}

.ag-flow__x {
    display: flex;
    justify-content: space-between;
    font-size: 10px;
    letter-spacing: .08em;
    opacity: .55;
}


/* Stacked actions on the game-over card breathe. */
.ag-over__inner > .ag-btn + .ag-btn { margin-top: 10px; }


/* ---------------------------------------------------------------- room list view modes */

.ag-roomlist__bar {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
}

.ag-viewtoggle {
    display: inline-flex;
    border: 1px solid var(--white-t2);
    border-radius: 999px;
    overflow: hidden;
}

.ag-viewtoggle button {
    padding: 3px 12px;
    border: 0;
    background: transparent;
    color: var(--light);
    font-size: 13px;
    line-height: 1;
    opacity: .55;
    cursor: pointer;
    transition: background .18s var(--ease-out), opacity .18s var(--ease-out);
}

.ag-viewtoggle button.is-on {
    background: var(--primary-light-t1);
    opacity: 1;
}

/* Grid mode: tile cards, same information as a row, scannable two-up (three on desktop). */
.ag-roomgrid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 10px;
    padding: 0 var(--gutter);
    max-width: 640px;
    margin-inline: auto;
}

.ag-roomcard {
    position: relative;
    display: grid;
    justify-items: center;
    gap: 6px;
    padding: 16px 10px 12px;
    border: 1px solid var(--white-t1);
    border-radius: 18px;
    background: linear-gradient(180deg,
        var(--primary-light-t1) 0%,
        var(--primary-dark-t2) 45%,
        var(--black-t3) 100%);
    -webkit-backdrop-filter: blur(12px) saturate(1.25);
    backdrop-filter: blur(12px) saturate(1.25);
    color: var(--light);
    font: inherit;
    cursor: pointer;
    transition: transform .18s var(--ease-out), filter .18s var(--ease-out),
                border-color .18s var(--ease-out);
}

.ag-roomcard:hover { transform: translateY(-2px); filter: brightness(1.07); }

.ag-roomcard.is-mine { border-color: var(--primary-light); }

.ag-roomcard__mine {
    position: absolute;
    top: -7px;
    padding: 2px 10px;
    border-radius: 999px;
    background: var(--primary-light);
    color: var(--primary-dark);
    font-size: 9px;
    font-weight: 800;
    letter-spacing: .14em;
}

.ag-roomcard__name {
    font-weight: 800;
    font-size: 14px;
    text-align: center;
    line-height: 1.25;
}

.ag-roomcard__seats {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 10px;
    border-radius: 999px;
    background: var(--primary-dark-t1);
    font-size: 12px;
    font-variant-numeric: tabular-nums;
}

.ag-roomcard__seats img { width: 13px; height: 13px; }

.ag-roomcard__fee {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-weight: 800;
    font-size: 14px;
}

.ag-roomcard__fee img { width: 17px; height: 17px; }

.ag-roomcard__launch { width: 16px; height: 16px; opacity: .6; }


/* ---------------------------------------------------------------- reconnecting overlay */

/* The transport is down: blur the whole game and say so in the centre. Fixed so it covers
   header and nav too — nothing on this screen is actionable until the socket is back. */
.ag-reconnecting {
    position: fixed;
    inset: 0;
    z-index: 50;
    display: grid;
    place-items: center;
    background: rgba(16, 2, 26, .45);
    -webkit-backdrop-filter: blur(14px) saturate(.8);
    backdrop-filter: blur(14px) saturate(.8);
    animation: ag-page-in 280ms var(--ease-out);
}

.ag-reconnecting__box {
    display: grid;
    justify-items: center;
    gap: 12px;
    padding: 30px 40px;
    border-radius: 24px;
    border: 1px solid var(--gold-1);
    background: var(--primary-dark-t1);
    text-align: center;
}

.ag-reconnecting__label {
    font-size: 13px;
    font-weight: 800;
    letter-spacing: .22em;
    color: var(--gold-2);
    animation: ag-vs-pulse 1.2s var(--ease-in-out) infinite;
}


/* ---------------------------------------------------------------- sponsored-seat gate */

.ag-adgate {
    width: min(420px, calc(100% - 2 * var(--gutter)));
    margin-inline: auto;
    display: grid;
    justify-items: center;
    gap: 8px;
    padding: 12px 16px;
    border-radius: 16px;
    border: 1px dashed var(--gold-1);
    background: var(--primary-dark-t1);
    text-align: center;
    font-size: 13px;
}

.ag-adgate__label {
    font-size: 9.5px;
    font-weight: 800;
    letter-spacing: .2em;
    color: var(--gold-2);
}
