/****** THEME VARIABLES ******/
/* Modernized-crimson dark palette. Introduced 2026-07 as the first
   CSS-variable layer in this theme (none existed before). Structural
   surfaces + accents point at these; deep component colors (crime bar,
   button gradients, etc.) still use their own hex further down. Swap
   --accent / --accent-hover to re-skin the whole accent identity in
   one place. */
:root {
    --bg: #0d0d0f;
    --surface: #17171b;
    --surface-2: #202027;
    --surface-3: #2a2a32;
    --border: #2e2e37;
    --border-soft: #23232a;
    --text: #ececf1;
    --text-muted: #9a9aa6;
    --accent: #c8202f;
    --accent-hover: #b71f1f;
    --accent-soft: rgba(200, 32, 47, 0.14);
    --panel-bg: rgba(0, 0, 0, .75);
    --radius: 0px;
    --gap: 14px;
}

/****** GLOBAL STYLES ******/
html {
    height: 100%;
}

/* body is a fixed-height (100vh) flex column that never scrolls itself -
   .header and .round-bar keep their natural height, .game-shell grows to
   fill the rest, and .side-bar/.game-container inside it get their own
   independent overflow so the game content is the only thing that scrolls
   while header/round-bar/sidebar stay pinned in place. */
body {
    background-image: url("../images/main-background.jpg") !important;
    background-position: top center !important;
    background-repeat: repeat-y !important;
    background-color: var(--bg) !important;
    color: var(--text);
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    height: 100vh;
    overflow: hidden;
    display: flex;
    flex-direction: column;
}

a,
a:focus,
a:active,
a:hover {
    color: inherit;
}

hr {
    border-top: 1px solid var(--border) !important;
}

/****** MISC STYLES ******/
.no-scroll {
    overflow: hidden;
}

.padding {
    padding: 0 10%;
}

.tiny {
    font-size: 12px;
    line-height: 20px;
}

.timer-active {
    color: #a94442 !important;
}

.timer-done {
    color: #3c763d !important;
}

.timer-ready-label {
    font-size: 0.85em;
}

.new {
    color: #3c763d ;
    font-weight: bold;
}

/****** BBCODE STYLES ******/
.bb_image {
    max-width: 100%;
}

/****** LOGIN STYLES ******/
/* Scoped to body[data-page-wrapper="login"] (see class/template.php /
   themes/default/login.php) so this doesn't leak into the shared
   .panel/.btn/.form-control styling used across the logged-in game. */
body[data-page-wrapper="login"] {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 32px 16px;
}

body[data-page-wrapper="login"] .login-logo {
    padding-top: 0;
    padding-bottom: 28px;
    text-align: center;
}

body[data-page-wrapper="login"] .login-logo img {
    max-width: 260px;
    width: 100%;
    height: auto;
    filter: drop-shadow(0 6px 28px rgba(0, 0, 0, 0.65));
}

.login-form {
    width: 100%;
    max-width: 400px;
    margin-left: auto;
    margin-right: auto;
    margin-bottom: 18px;
}

body[data-page-wrapper="login"] .login-form .panel-heading {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-bottom: 2px solid var(--accent);
    font-size: 15px;
    letter-spacing: 0.6px;
    text-transform: uppercase;
}

body[data-page-wrapper="login"] .login-form .panel-body {
    background: rgba(23, 23, 27, 0.88);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border: 1px solid rgba(255, 255, 255, 0.08);
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.55);
    padding: 22px;
}

body[data-page-wrapper="login"] .login-form .nav-pills > li > a {
    border-radius: var(--radius);
    font-weight: 600;
    letter-spacing: 0.2px;
}

body[data-page-wrapper="login"] .login-form .nav-pills > li.active > a {
    background: var(--accent);
    color: #fff;
}

body[data-page-wrapper="login"] .login-form .form-control {
    background-color: rgba(0, 0, 0, 0.4);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    height: 44px;
    padding: 10px 14px;
    margin-bottom: 12px;
    transition: border-color .15s ease, box-shadow .15s ease;
}

body[data-page-wrapper="login"] .login-form .form-control:focus {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}

body[data-page-wrapper="login"] .login-form .form-control::placeholder {
    color: var(--text-muted);
}

body[data-page-wrapper="login"] .login-form a {
    color: var(--text-muted);
    font-size: 13px;
    transition: color .15s ease;
}

body[data-page-wrapper="login"] .login-form a:hover {
    color: var(--text);
}

body[data-page-wrapper="login"] .login-form .btn {
    border-radius: var(--radius);
    font-weight: 600;
    letter-spacing: 0.3px;
    padding: 10px 22px;
    transition: transform .1s ease, filter .15s ease;
}

body[data-page-wrapper="login"] .login-form .btn:hover {
    filter: brightness(1.12);
}

body[data-page-wrapper="login"] .login-form .btn:active {
    transform: translateY(1px);
}

/****** USER STATUS STYLES ******/
.user-status-0 .side-bar {
    display: none;
}

.user-status-0 .game-container {
    max-width: 800px;
    margin-top: 0;
    margin-left: auto;
    margin-right: auto;
    float: none;
}

.user-status-0 .logo-container {
    text-align: center !important;
    width: 100%;
}

.user-status-0 .sub-header,
.user-status-0 .header .col-md-2,
.user-status-0 .header .col-md-3 {
    display: none;
}

.user-level-0:before {
    content: "[BANNED]";
}
.user-level-0,
.user-level-0:hover {
    color: #777;
}

.user-level-2,
.user-level-2:hover {
    color: #ff0;
    font-weight: bold;
}

/****** HEADER STYLES ******/
.header {
    /* No opaque background-color here on purpose - only semi-
       transparent gradient layers below, so the page's own city-
       skyline background-image (painted on <body>, positioned "top
       center" starting at body's own top edge) bleeds through the
       header instead of being covered by a flat bar sitting on top of
       it. The gold radial layer is a soft glow centered behind the
       logo, echoing the same glow already used on .gv-section-title.

       There USED to also be a linear dark-to-surface gradient here
       for a "floor"/legibility effect, sized to match header-art.svg's
       own width so it wouldn't span the full header - but constraining
       its WIDTH like that just traded one hard edge for another: the
       gradient only fades vertically, so at the art's left/right
       boundary it now cut off abruptly instead of fading, reading as
       harsh rather than smooth. Removed rather than chase a shape that
       fades cleanly on all four sides - the art's own internal mask
       already handles legibility/fade within its own footprint, and
       the true page background is a fine "floor" everywhere else. */
    background-image:
        /* Scrim, sized just to the logo's own footprint (not the
           whole header) - the logo's white "MAFIA" text sits directly
           over the sun disc in header-art.svg, the single toughest
           spot for contrast in the whole piece. This punches up local
           darkness right behind the wordmark without touching the art
           surrounding it. */
        radial-gradient(ellipse 300px 80px at center, rgba(6, 4, 5, 0.6) 0%, rgba(6, 4, 5, 0.3) 55%, rgba(6, 4, 5, 0) 100%),
        url("../images/header-art.svg"),
        radial-gradient(ellipse 460px 170px at center, rgba(212, 175, 55, 0.08) 0%, rgba(212, 175, 55, 0.025) 50%, rgba(212, 175, 55, 0) 100%);
    background-repeat: no-repeat, no-repeat, no-repeat;
    background-position: center center, center center, center center;
    /* Desktop default: a fixed, moderate width - the art is meant to
       wrap the logo closely, not stretch thin across the full
       ~1170px container. Narrower breakpoints override this below. */
    background-size: auto, 580px auto, auto;
    border-bottom: none;
    box-shadow: 0 1px 0 rgba(0, 0, 0, 0.5);
    /* Minimal - the header hamburger is gone everywhere now (moved
       into the bottom nav's Menu tab on mobile; was already hidden on
       desktop), so this only ever has to fit the logo, which is sized
       to fill nearly the whole header height below. */
    padding: 6px 0;
    position: relative;
    flex: 0 0 auto;
    /* No width override here in the base rule anymore - see the
       max-width:767px block below for why. At >=768px, Bootstrap's own
       .container rules (which .header also carries, same as .round-bar/
       .game-shell) give it an explicit width (750/970/1170px per
       breakpoint) and center it with margin:auto - letting that apply
       naturally here is what makes the header's width actually match
       round-bar/game-shell's, since they're all sized by the exact same
       mechanism. */
}

/* Below Bootstrap's own smallest .container breakpoint (768px),
   .container has NO explicit width at all (only margin:auto +
   padding) - the exact gap that caused .header's original collapse-
   to-98px bug (a flex item with no explicit width sizes to its
   content, and .header's content - just the logo - is genuinely
   narrow, so the auto margins centered that tiny box instead of
   stretching it). Re-applying width:100% only in this range keeps
   that fix scoped to where it's actually needed, instead of also
   overriding Bootstrap's real container width on desktop. */
@media (max-width: 767px) {
    .header {
        width: 100%;
        /* Fill the header's own width here specifically (matches the
           original ask - the art should span the mobile header edge
           to edge, fading to transparent via its own internal mask
           rather than CSS clipping it). Desktop keeps the fixed
           580px from the base rule instead, since stretching this
           across a much wider container would thin it out badly. */
        background-size: auto, 100% auto, auto;
    }
}

/* Gold gradient + diamond bottom accent, replacing the old flat 1px
   border - same "◆ ... ◆" motif already used on every .gv-section-
   title, just stretched into a full-width line instead of flanking a
   short heading. */
.header::after {
    content: "";
    position: absolute;
    left: 50%;
    bottom: 5px;
    transform: translateX(-50%);
    width: min(280px, 68%);
    height: 1px;
    background: linear-gradient(90deg, transparent 0%, var(--gv-gold, #d4af37) 50%, transparent 100%);
    opacity: 0.85;
}

.header::before {
    content: "\2666";
    position: absolute;
    left: 50%;
    bottom: 1px;
    transform: translateX(-50%);
    color: var(--gv-gold, #d4af37);
    font-size: 9px;
    text-shadow: 0 0 6px rgba(212, 175, 55, 0.5);
    z-index: 1;
}

.header .container {
    position: relative;
}

.header .logo-container {
    text-align: center;
    line-height: normal;
}

.header .logo-container img {
    /* max-width:15% used to be the only rule here, computed against
       .logo-container's width (the full header width) - reasonable-
       looking on a wide desktop container by accident, but the real
       intent ("fill the header, small margin only") is better
       expressed directly off the header's own height instead of an
       unrelated percentage of its width. Same size on every
       breakpoint now that the hamburger's gone from the header
       everywhere (was previously mobile-only). */
    max-width: none;
    width: auto;
    height: 56px;
    /* Legibility against header-art.svg's busy sunburst/skyline -
       hugs the actual letter shapes (unlike a box-shadow, which only
       has the image's rectangular bounding box to work with), same
       technique already used on the login page's logo. */
    filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.85)) drop-shadow(0 0 10px rgba(0, 0, 0, 0.6));
}

/* Hamburger is desktop-hidden; the mobile media query below shows it.
   mobile.js binds to .navbar-toggle and toggles body.show-sidebar. */
.header .navbar-toggle {
    display: none;
    position: absolute;
    left: 15px;
    top: 50%;
    transform: translateY(-50%);
    margin: 0;
}

/****** ROUND BAR ******/
/* The clock + round name, moved out of .header into their own strip
   sitting directly on top of .game-shell - same border/radius scheme
   with the touching edge left square on both sides, so the two read
   as one connected panel (round-bar as the "heading", game-shell as
   the "body"), same way .panel-heading connects to .panel-body. */
.round-bar {
    /* A subtle lift off the page's near-black --bg (#0d0d0f is barely
       distinguishable from flat --surface #17171b) - same gradient
       recipe as .gv-panel, so the bar reads as a distinct surface
       instead of just "less black", without going as bright/boxed as
       a full .gv-panel card would look stacked directly under the
       header. */
    background: linear-gradient(180deg, var(--gv-panel-alt, #1e1e26) 0%, var(--surface, #17171b) 100%);
    border: 1px solid var(--gv-border, var(--border));
    border-bottom: none;
    border-radius: var(--radius) var(--radius) 0 0;
    color: var(--text-muted);
    font-size: 12px;
    letter-spacing: 0.3px;
    /*margin-top: var(--gap);*/
    flex: 0 0 auto;
    /* Belt-and-suspenders for the Nerve/Energy/Awake row staying
       visible while scrolling: .game-container is meant to be the
       only thing that scrolls (see the note above body's rules), but
       mobile browsers' own dynamic-toolbar handling of 100vh can make
       the body itself the scrolling element instead on some devices.
       Sticky here keeps this bar pinned to the top of WHICHEVER
       element actually ends up scrolling, in either case. */
    position: sticky;
    top: 0;
    z-index: 150;
}

/* Compact overhead stat strip - built on the shared "gv-" gold/dark
   design system (see the SHARED "gv-" DESIGN SYSTEM block further
   down) instead of the old Bootstrap list-group/progress-bar look, so
   the very first thing on every page reads as premium instead of
   dated. Two rows: identity/currency chips, then resource + rank
   bars - both wrap independently so this stays readable down to
   phone widths without needing its own mobile rewrite. */
.round-bar .gv-topbar {
    display: flex;
    flex-direction: column;
    gap: 7px;
    padding: 9px 16px;
}

.round-bar .gv-topbar-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 5px 16px;
}

.round-bar .gv-topbar-stat {
    display: flex;
    align-items: baseline;
    gap: 6px;
    white-space: nowrap;
}

/* Thin vertical hairline between identity chips (same recipe as
   .gv-banner-divider) instead of a "•" glyph - the bullet span had its
   own margin:0 7px stacked ON TOP of this row's gap:16px, so spacing
   compounded unevenly around every dot depending on font/glyph
   rendering. A single 1px line with no margin of its own gets its
   entire spacing from the row's gap, so every gap - chip-to-divider or
   divider-to-chip - comes out identical. align-self:stretch (not the
   row's own align-items:center) makes it span the full row height
   instead of sitting as a short center-anchored mark. */
.round-bar .gv-topbar-divider {
    align-self: stretch;
    width: 1px;
    background: var(--gv-border, var(--border));
    opacity: 0.7;
}

.round-bar .gv-topbar-label {
    color: var(--gv-text-dim, var(--text-muted));
    text-transform: uppercase;
    letter-spacing: 0.5px;
    font-size: 10px;
}

/* No max-width/ellipsis here on purpose - this holds Money/Points/Gold
   Coins, which only ever grow. Truncating with an ellipsis would hide
   real digits (misleading, not just "looks a little tight"). Instead
   the value stays nowrap and the whole label+value pair (.gv-topbar-
   stat, itself white-space:nowrap) wraps as one atomic unit onto its
   own line via the row's flex-wrap once it no longer fits - so a big
   number pushes layout, never gets cut off or breaks mid-digit. */
.round-bar .gv-topbar-value {
    color: var(--gv-gold-bright, #f4d35e);
    font-weight: 700;
    font-size: 12px;
    white-space: nowrap;
}

/* Bar row: each slot is label + track + value, sized to share the row
   and wrap onto its own line once it can't fit - same shrink-safe
   pattern the old .round-bar-stat used. */
.round-bar .gv-topbar-bar-slot {
    display: flex;
    align-items: center;
    gap: 7px;
    flex: 1 1 165px;
    min-width: 0;
}

.round-bar .gv-topbar-bar-label {
    color: var(--gv-text-dim, var(--text-muted));
    text-transform: uppercase;
    letter-spacing: 0.5px;
    font-size: 10px;
    flex: 0 0 auto;
    white-space: nowrap;
}

.round-bar .gv-topbar-bar {
    flex: 1 1 auto;
    min-width: 36px;
    height: 8px;
}

.round-bar .gv-topbar-bar-value {
    color: var(--gv-text, var(--text));
    font-size: 10px;
    flex: 0 0 auto;
    min-width: 30px;
    text-align: right;
    white-space: nowrap;
}

/* Per-resource fill colours - kept distinct from each other and from
   the default gold (.gv-bar-fill) so Health/Energy/Awake/Nerve stay
   instantly tellable apart at a glance, matching the colour identity
   the old Bootstrap contextual classes (progress-bar-info etc.) gave
   them.

   REASSIGNED 2026-08-04 as one even rotation (fuego's call - the
   round-bar's Rank/EXP bar and the sidebar User Account panel's own
   Rank/EXP bar used to be different colours, crimson vs gold, since
   the round-bar deliberately avoided gold to stay distinct from the
   four gold-adjacent resource bars sharing that panel; that reasoning
   no longer applies now that Nerve has moved off gold). Each bar
   picked up the color the bar before it in the rotation used to have,
   freeing gold back up for Rank/EXP to match the sidebar everywhere:
   Health -> red (was the old accent/crimson slot), Energy -> green
   (was Health's), Nerve -> blue (was Energy's), Rank/EXP -> gold
   (was Nerve's, and already the sidebar's own default .gv-bar-fill
   color - see the plain <div class="gv-bar-fill"> Rank bar in
   loggedin.php's User Account panel, no override needed there). */
.round-bar .gv-bar-fill-energy {
    background: linear-gradient(90deg, #2e7d32 0%, #66bb6a 100%);
}

.round-bar .gv-bar-fill-awake {
    background: linear-gradient(90deg, #7986cb 0%, #5c6bc0 100%);
}

.round-bar .gv-bar-fill-nerve {
    background: linear-gradient(90deg, #4fc3f7 0%, #29b6f6 100%);
}

.round-bar .gv-bar-fill-accent {
    background: linear-gradient(90deg, var(--gv-gold) 0%, var(--gv-gold-bright) 100%);
}

@media (max-width: 500px) {
    .round-bar .gv-topbar {
        padding: 7px 10px;
        gap: 5px;
    }

    .round-bar .gv-topbar-row {
        gap: 4px 10px;
    }

    .round-bar .gv-topbar-value {
        max-width: 110px;
    }

    .round-bar .gv-topbar-bar-slot {
        flex: 1 1 130px;
    }
}


/* Inlaid date/round strip at the top of every page's game-container -
   recessed (inset shadow, darker than the surrounding surface) rather
   than a raised bordered card, so it reads as part of the game area
   itself instead of competing with the actual content cards below it.
   Was previously wrapped in .panel-default/.panel-heading (a generic
   Bootstrap card, complete with panel-heading's crimson underline),
   which read as its own separate card floating at the top of the
   page - not the intent. */
.gv-game-topbar {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    background: var(--gv-ink, #0c0c10);
    border: 1px solid var(--gv-border, var(--border));
    border-radius: 6px;
    padding: 7px 14px;
    margin-bottom: var(--gap);
    font-size: 11px;
    letter-spacing: 0.4px;
    color: var(--gv-text-dim, var(--text-muted));
    box-shadow: inset 0 1px 4px rgba(0, 0, 0, .5);
}

.gv-game-round {
    color: var(--gv-gold-bright, #f4d35e);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 1px;
}

.gv-game-topbar-sep {
    opacity: 0.5;
}

/****** SIDEBAR + GAME LAYOUT ******/
/* game-shell is the flex row holding the left sidebar + the game area
   - it already wraps both, so it doubles as the "translucent panel"
   surface: --panel-bg (Theme Editor > Appearance) fills it, and its
   border/radius pick up right where .round-bar leaves off above it.
   Replaces the old float scheme. The outer .container is still capped
   at Bootstrap's ~1170px, giving the "classic PBBG" width. */
.game-shell {
    display: flex;
    align-items: flex-start;
    gap: var(--gap);
    background: var(--panel-bg);
    border: 1px dotted var(--border);
    border-top: none;
    border-radius: 0 0 var(--radius) var(--radius);
    /* No top padding here - .side-bar/.game-container are the actual
       scrolling elements (overflow-y:auto, below), not this element,
       so a top padding here would sit OUTSIDE their scroll area: a
       permanent static gap between the sticky round-bar above and
       whatever content is currently scrolled to the top, which never
       gets covered by anything since it isn't part of what scrolls.
       Confirmed live as the "content disappears into a gap instead of
       flowing behind the overhead bar" report - scrolled content was
       clipping at game-shell's own padded edge, well below round-bar,
       instead of tucking directly under it. The equivalent breathing
       room now lives as padding-top on .side-bar/.game-container
       themselves, so it's part of the scrolled content and moves
       (and gets covered by round-bar) right along with it. */
    padding: 0 var(--gap) var(--gap) var(--gap);
    /*margin-bottom: var(--gap);*/
    flex: 1 1 auto;
    min-height: 0; /* let this flex child shrink so its children can scroll instead of growing the (non-scrolling) body */
    /* Without an explicit max-width, this auto-sized flex child (body
       is display:flex; flex-direction:column) sizes to fit its
       CONTENT first and adds its own padding/border on top of that -
       instead of being constrained to the viewport and letting
       .game-container's own min-width:0 shrink ITS content to fit
       within that. On a narrow phone screen this pushed the whole
       page ~30px (this element's own padding+border) wider than the
       actual device width, forcing the entire site into horizontal
       scroll - confirmed live: .game-shell rendered at 530px on a
       375px-wide viewport before this fix, matching exactly its
       child's needed width (500px) plus its own padding (28px) and
       border (2px). 100vw (not 100%) specifically because .game-shell
       has no percentage-friendly ancestor chain guaranteeing 100%
       resolves to the true viewport width here.
     */
    max-width: 100vw;
}

/****** SIDEBAR STYLES ******/
.side-bar {
    flex: 0 0 185px;
    width: 185px;
    float: none;
    height: 100%;
    overflow-y: auto;
    /* This padding lives here (not on .game-shell) specifically so it
       scrolls away WITH the content instead of sitting outside the
       scroll area as a static gap - .game-shell itself has no top
       padding (see below), so this element's own top edge is already
       flush with the sticky round-bar, and content clips cleanly
       against that edge once scrolled past this initial breathing
       room. Resting gap + smooth scroll-under at the same time. */
    padding-top: var(--gap);
}

.side-bar .label {
    float: right;
}

.side-bar .list-group {
    border: 1px solid #474747;
    border-top: none;
    border-bottom-left-radius: 3px;
    border-bottom-right-radius: 3px;
}

.side-bar .list-group .list-group-item {
    position: relative;
    padding: 0px 5px;
    line-height: 22px;
    background-color: #111 !important;
    background-color: #111 !important;
    font-size: 12px;
}

.side-bar .list-group .list-group-item:hover {
    background-color: #222 !important;
}

.side-bar .list-group .list-group-item small {
    position: relative;
    font-size: 11px;
    z-index: 200;
}

.side-bar .list-group .progress {
    position: absolute;
    top: 3px;
    right: 3px;
    bottom: 3px;
    width: 100px;
    height: 16px;
    z-index: 100;
}


/****** GAME CONTAINER STYLES ******/
.game-container {
    flex: 1 1 auto;
    min-width: 0; /* let the flex child shrink so wide tables/cards don't force overflow */
    width: auto;
    float: none;
    height: 100%;
    overflow-y: auto;
    /* This padding lives here (not on .game-shell) specifically so it
       scrolls away WITH the content instead of sitting outside the
       scroll area as a static gap - .game-shell itself has no top
       padding, so this element's own top edge is already flush with
       the sticky round-bar, and content clips cleanly against that
       edge once scrolled past this initial breathing room. Resting
       gap + smooth scroll-under at the same time. */
    padding-top: var(--gap);
}

/****** TOAST NOTIFICATIONS ******/
/* Replaces the old full-width .game-alerts blocks that used to sit
   inline in the content flow. #toast-container lives outside the
   AJAX-swapped .game-cards region (see loggedin.php) so a toast's own
   timeout/DOM node survives whatever page the player navigates to
   next - see ajax.js's showToasts()/activateToast(). */
#toast-container {
    position: fixed;
    top: 16px;
    right: 16px;
    z-index: 1200;
    display: flex;
    flex-direction: column;
    gap: 10px;
    width: 320px;
    max-width: calc(100vw - 32px);
    pointer-events: none;
}

#toast-container .alert {
    pointer-events: auto;
    position: relative;
    margin: 0;
    padding: 10px 30px 10px 14px;
    font-size: 13px;
    line-height: 1.4;
    text-align: left;
    background: var(--surface-2);
    color: var(--text);
    border: 1px solid var(--border);
    border-left: 4px solid transparent;
    border-radius: var(--radius);
    box-shadow: 0 12px 30px rgba(0, 0, 0, 0.5);
    opacity: 0;
    /* Direction a toast slides in from/out to - defaults match the
       top-right position below. Admin Panel > Site Features > Toast
       Notifications (see loggedin.php's toastCSS) overrides these two
       custom properties per the saved position, so the animation
       direction always matches wherever the container actually sits. */
    --toast-enter-x: 24px;
    --toast-enter-y: 0px;
    transform: translate(var(--toast-enter-x), var(--toast-enter-y));
    transition: opacity .2s ease, transform .2s ease;
}

#toast-container .alert.toast-visible {
    opacity: 1;
    transform: translate(0, 0);
}

#toast-container .alert.toast-leaving {
    opacity: 0;
    transform: translate(var(--toast-enter-x), var(--toast-enter-y));
}

#toast-container .alert-success { border-left-color: #00c300; }
#toast-container .alert-danger  { border-left-color: #c30000; }
#toast-container .alert-info    { border-left-color: #00f3ff; }
#toast-container .alert-warning { border-left-color: #ffd400; }

#toast-container .alert .close {
    position: absolute;
    top: 6px;
    right: 8px;
    background: none;
    border: 0;
    padding: 0;
    line-height: 1;
    font-size: 16px;
    color: var(--text-muted);
    opacity: .7;
    cursor: pointer;
}

#toast-container .alert .close:hover {
    opacity: 1;
    color: var(--text);
}

@media (max-width: 480px) {
    #toast-container {
        left: 16px;
        right: 16px;
        width: auto;
    }
}

/* Even-fill card rhythm. The module's raw HTML is dumped into
   .game-cards; making it a flex column with a consistent gap gives
   every top-level card the same spacing regardless of the per-module
   margins the templates used to rely on. Top-level cards stay
   full-width by default (safe across every module); modules opt into
   side-by-side via Bootstrap .row / .col-* as before. */
.game-cards {
    display: flex;
    flex-direction: column;
    gap: var(--gap);
}

.game-cards > .panel,
.game-cards > .row {
    margin-bottom: 0; /* spacing now comes from the flex gap */
}

/* Equal-height side-by-side cards: turning a .row into a flex row
   makes paired .col-* cards match heights so they read as "even"
   (the main visible win, e.g. bank Deposit/Withdraw). Bootstrap's
   negative row margins are neutralized to avoid horizontal overflow
   inside the flex column. */
.game-cards .row {
    display: flex;
    flex-wrap: wrap;
    margin-left: 0;
    margin-right: 0;
}

.game-cards .row > [class*="col-"] {
    display: flex;
    flex-direction: column;
}

.game-cards .row > [class*="col-"] > .panel,
.game-cards .row > [class*="col-"] > form {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    height: 100%;
}

.game-cards .row > [class*="col-"] > .panel > .panel-body,
.game-cards .row > [class*="col-"] > form > .panel > .panel-body {
    flex: 1 1 auto;
}

/* Opt-in helper: a module (or Module Factory output) can wrap N cards
   in .card-grid to auto-fill them into equal columns that wrap. */
.card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: var(--gap);
}

/****** CRIME HOLDER ******/
.crime-holder {
    border:1px solid #555;
    background: #010101;
    margin-bottom:10px;
}

.crime-holder p {
    padding:10px;
    margin:0px;
    text-align: right;
}

.crime-holder .cooldown {
    color: #777;
    padding-right: 20px;
}

.crime-holder .action {
    float: left;
}

.crime-holder .commit {
    background-color: #222;
    border: 1px solid #555;
    padding: 5px 6px;
    border-radius: 3px;
}

.crime-holder .crime-perc {
    width:100%;
    height:2px;
    background-color:#900;
}

.crime-holder .crime-perc .perc {
    height:2px;
    background-color:#090;
    width: 0px;
}

.crime-holder .crime-header {
    background-color: #272727;
    border-bottom: 1px solid #474747;
    padding: 0px 5px;
}

/****** BOOTSTRAP OVERRIDES ******/
.alert {
    border: 1px solid;
}

.well {
    background-color: #151515;
    border: 1px solid #474747;
    text-align: left;
}

.well h3 {
    margin-top: 0px;
}

/*** Panel (card) ***/
.panel {
    background-color: transparent;
    border: none;
    margin-bottom: 0; /* game-cards flex gap handles spacing now */
}

.panel-heading {
    position: relative;
    text-transform: capitalize;
    color: var(--text);
    border-bottom: none;
    min-height: 38px;
    padding: 0 12px;
    text-align: center;
    line-height: 38px;
    font-weight: 600;
    letter-spacing: 0.3px;
    border-top-left-radius: var(--radius) !important;
    border-top-right-radius: var(--radius) !important;
}

.panel-body {
    background: var(--surface);
    border: 1px solid var(--border);
    border-top: none;
    border-radius: 0 0 var(--radius) var(--radius);
    padding: 14px;
}

/*** Forms ***/
.form-control {
    background-color: rgba(0, 0, 0, 0.67);
    border: 1px solid rgba(255, 255, 255, 0.14);
}

.form-control:focus {
    border: 1px solid rgba(255, 255, 255, 0.35);
    box-shadow: none;
}

.form-control-inline {
    display: inline-block;
    width: 200px;
}

.form-group .form-control {
    color: #aaa;
}

/*** Drop Down Menu ***/
.dropdown-menu {
    background-color: #272727;
}


.dropdown-menu>li>a:hover, .dropdown-menu>li>a:focus {
    background-color: #474747;
    color: #b7b7b7;
}

.dropdown-menu>li>a {
    color: #979797;
}
.dropdown-menu .divider {
    background-color: #979797;
}

/*** Tables ***/
table tr td, table tr th {
    text-align: left;
}

.table-borderless tr, .table-borderless tr td, .table-borderless tr th {
    border: none !important;
}

.table-bordered,
.table-bordered th,
.table-bordered td {
    border-color: #272727 !important;
}

.table-striped>thead>tr:nth-child(odd)>td, .table-striped>thead>tr:nth-child(odd)>th {
    background-color: #171717;
}
.table-striped>tbody>tr:nth-child(odd)>td, .table-striped>tbody>tr:nth-child(odd)>th {
    background-color: #272727;
}

.table-striped>tbody>tr:nth-child(even)>td, .table-striped>tbody>tr:nth-child(even)>th {
    background-color: #373737;
}

.table-condensed>thead>tr>th, .table-condensed>tbody>tr>th, .table-condensed>tfoot>tr>th, .table-condensed>thead>tr>td, .table-condensed>tbody>tr>td, .table-condensed>tfoot>tr>td {
    padding: 2px 5px;
}

/*** Images ***/
.img-thumbnail {
    background-color: transparent;
    border-color: #555;
}

/****** Progress Bars ******/
.progress {
    background-color: #050505;
    border: 1px solid #000;
}

.progress-bar-success {
    background-color: #040;
}


.hprogress-bar {
    float: none;
    width: 0;
    height: 100%;
    font-size: 12px;
    line-height: 20px;
    color: #fff;
    text-align: center;
    background-color: #428bca;
    -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);
    box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);
    -webkit-transition: width .6s ease;
    transition: width .6s ease;
}


/****** Navs ******/
.nav-pills>li>a {
    padding: 5px;
    margin-bottom: 10px;
}

.nav-pills>li>a:hover {
    background-color: #474747;
}

.nav-tabs {
    border-bottom: 1px solid #474747 !important;
    margin-bottom: 10px;
    padding-bottom: 10px;
}

.nav-tabs li a {
    border-bottom-color: transparent !important;
}

.nav-tabs li a:hover {
    background-color: #474747;
    border-radius: 5px;
    border-color: transparent;
}

/****** Lists ******/
.list-group, .list-group .list-group-item {
    border-color: #474747;
    color: #fff;
}

.list-group .list-group-item:nth-child(odd) {
    background-color: #171717;
}

.list-group .list-group-item:nth-child(even) {
    background-color: #252525;
}

.list-group .list-group-item .badge {
    background-color: transparent;
}
/* Container to hold the items in a row */
.list-group-horizontal {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    list-style: none;
    padding: 0;
    margin: 0;
}

.list-group-horizontal .list-group-item {
    position: relative;
    display: block;
    padding: 10px 15px;
    margin-bottom: px;
    background-color: #fff;
    border: 1px solid #ddd;
}

/****** Pagnation ******/
.pagination li a {
    background-color: #252524;
    color: #fff;
    border-color: #474747;
}

.pagination li:hover a {
    background-color: inherit !important;
    color: inherit !important;
    border-color: #474747;
}

.pagination li.active a {
    background-color: #676767 !important;
    color: #fff;
    border-color: #ccc;
}

.pagination li:nth-child(odd) a {
    background-color: #161616;
}

/****** Buttons ******/
.btn {
    color:#fff;
    position: relative;
    border: none;
    background-color: transparent !important;
}

.btn:hover{
    text-decoration: underline;
    background-color: inherit;
}

/****** Colors ******/
.btn-default,
.btn.btn-default:hover {
    background: rgb(48,48,48);
    background: linear-gradient(180deg, rgba(86,86,86,1) 0%, rgba(48,48,48,1) 5%, rgba(48,48,48,1) 35%, rgba(36,36,36,1) 50%);
    border: #2c2c2c 1px solid;
    color: #fff;
}

/* Card headings: flat, modern, with a thin crimson accent underline so
   the brand color reads on every card without shouting. */
.panel-default > .panel-heading {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-bottom: 2px solid var(--accent);
    color: var(--text);
}

.text-success {
    color: #00c300;
}

.btn-success,
.btn.btn-success:hover,
.panel-success > .panel-heading {
    background: rgb(00,75,00);
    background: linear-gradient(180deg, rgba(00,125,00,1) 0%, rgba(00,75,00,1) 5%, rgba(00,75,00,1) 35%, rgba(00,45,00,1) 50%);
    border: #0c560c 1px solid;
    color: #fff;
}

.text-danger {
    color: #c30000;
}

.btn-danger,
.btn.btn-danger:hover,
.panel-danger > .panel-heading {
    background: rgb(90,00,00);
    background: linear-gradient(180deg, rgba(150,00,00,1) 0%, rgba(90,00,00,1) 5%, rgba(90,00,00,1) 35%, rgba(60,00,00,1) 50%);
    border: #650c0c 1px solid;
    color: #fff;
}

.text-info {
    color: #00f3ff;
}

.btn-info,
.btn.btn-info:hover,
.panel-info > .panel-heading {
    background: rgb(00,90,90);
    background: linear-gradient(180deg, rgba(0,150,150,1) 0%, rgba(00,90,90,1) 5%, rgba(00,90,90,1) 35%, rgba(00,70,70,1) 50%);
    border: #0c6365 1px solid;
    color: #fff;
}

.text-warning {
    color: #ffd400;
}

.btn-warning,
.btn.btn-warning:hover,
.panel-warning > .panel-heading {
    background: rgb(90,75,00);
    background: linear-gradient(180deg, rgba(150,110,00,1) 0%, rgba(90,75,00,1) 5%, rgba(90,75,00,1) 35%, rgba(60,45,00,1) 50%);
    border: #65500c 1px solid;
    color: #fff;
}


/* (The former min-width:1600px .game-container{max-width:1400px} rule
   was removed — it was dead code: the parent .container is Bootstrap-
   capped at ~1170px, so the 1400px cap could never take effect. The
   layout now tops out at the classic-PBBG ~1200px container width.) */

/****** TABLET STYLES ******/
@media (min-width: auto) and (max-width: 175px) {
    .side-bar {
        flex: 0 0 150px;
        width: 150px;
    }
}

/* Bottom nav is mobile-only (built entirely inside the max-width:500px
   block below) - hidden by default here, ahead of that block, so the
   real display:flex declared inside it is the one that wins the
   cascade at narrow widths (same selector, source order decides, and
   this needs to lose that tie-break outside the media query). */
.gv-bottom-nav {
    display: none;
}

/****** MOBILE STYLES ******/
@media (max-width: 500px) {
    body {
        font-size: 12px;
    }

    /* Sidebar and game area are mutually-exclusive full-width panes on
       mobile, toggled by body.show-sidebar (mobile.js / .navbar-toggle).
       Re-expressed for the flex game-shell without changing that UX. */
    .game-shell {
        flex-wrap: wrap;
    }

    .side-bar {
        display: none;
        flex-basis: 100%;
        width: 100%;
    }

    .show-sidebar .side-bar {
        display: block;
        flex-basis: 100%;
        width: 100%;
    }

    .show-sidebar .game-container {
        display: none;
    }

    /* Header hamburger no longer shown on mobile at all - the bottom
       nav's own Menu tab (gv-bottom-nav below) is the sidebar toggle
       now, so the header can shrink to just the logo instead of also
       reserving height/width for this button. Base rule already sets
       display:none, so simply not overriding it here is enough. */

    body[data-page-wrapper="login"] {
        padding: 20px 12px;
    }

    body[data-page-wrapper="login"] .login-logo {
        padding-top: 0;
        padding-bottom: 18px;
    }

    .mobile-menu {
        background-color: #272727;
        height: 100%;
        overflow: auto;
        position: absolute;
        top: 0px;
        bottom: 0px;
        left: 0px;
        right: 0px;
        display: none;
        z-index: 1000;
    }

    .mobile-menu ul.nav {
        position: absolute;
        top: 0px;
        bottom: 30px;
        left: 0px;
        right: 0px;
        overflow: auto;
    }

    .mobile-menu .close-mobile-menu {
        position: absolute;
        text-align: center;
        bottom: 0px;
        left: 0px;
        right: 0px;
        line-height: 30px;
        color: #fff;
        z-index: 1100;
        background-color: #474747;
    }

    .mobile-menu li {
        float: left;
        text-align: center;
    }

    .mobile-menu li a {
        padding: 7px 15px;
        margin-bottom: 0px;
    }

    .mobile-menu .title {
        background-color: #171717;
        display: block;
        clear: both;
        font-weight: bold;
    }

    .padding {
        padding: 0 2%;
    }

    .game-container {
        width: 100%;
        /* Left/right reset to 0 (game-shell's own padding already
           provides side breathing room) - top keeps the base rule's
           var(--gap) (resting gap that scrolls away smoothly behind
           the round-bar), and the bottom-nav padding rule further
           down re-adds bottom clearance on top of this. */
        padding: var(--gap) 0 0 0;
    }

    .crime-holder p {
        text-align: center;
    }
    .crime-holder .action {
        display: block;
        float: none;
    }
    .crime-holder .cooldown,
    .crime-holder .commit {
        width: 49%;
        float: none;
        display: inline-block !important;
        text-align: center;
        font-size: 12px;
        margin-top: 8px;
    }
    .crime-holder .commit:after {
        content: "";
        clear: both;
        display: block;
    }

    /* Mobile bottom tab bar - City/Bank/Crimes/Workout/More, always on
       screen so the most-used pages are one tap away without opening
       the full sidebar drawer first. Desktop never sees this (it's
       declared entirely inside this max-width:500px block); the
       sidebar stays the only nav on wider screens. */
    :root {
        /* 44px is Apple HIG's minimum recommended tap target - kept at
           that floor rather than going smaller, even though this was
           trimmed down from 58px to leave more room for game content. */
        --gv-bottom-nav-h: 44px;
    }

    .gv-bottom-nav {
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 800;
        display: flex;
        /* EXPERIMENT: reusing the exact same header-art.svg + gold
           glow treatment as .header, just centered/cropped to this
           bar's much shorter height - quick look before deciding
           whether this is worth keeping or needs its own art. */
        background-color: var(--surface, #17171b);
        background-image:
            url("../images/header-art.svg"),
            radial-gradient(ellipse 300px 90px at center, rgba(212, 175, 55, 0.08) 0%, rgba(212, 175, 55, 0.025) 50%, rgba(212, 175, 55, 0) 100%);
        background-repeat: no-repeat, no-repeat;
        background-position: center center, center center;
        background-size: 100% auto, auto;
        border-top: 1px solid var(--gv-border, var(--border));
        height: var(--gv-bottom-nav-h);
        /* iPhone home-indicator safe area - without this the bar (and
           its tap targets) sit partly under the gesture strip. */
        height: calc(var(--gv-bottom-nav-h) + env(safe-area-inset-bottom, 0px));
        padding-bottom: env(safe-area-inset-bottom, 0px);
    }

    .gv-bottom-nav-item {
        flex: 1 1 0;
        display: flex;
        align-items: center;
        justify-content: center;
        background: none;
        border: none;
        border-top: 2px solid transparent;
        /* White (not the usual dim gray) for the unhovered/inactive
           state specifically - easier to read at a glance against the
           art background before tapping, gold still marks active/hover. */
        color: #fff;
        font-size: 11px;
        font-weight: 600;
        text-transform: uppercase;
        letter-spacing: 0.4px;
        text-decoration: none;
        min-width: 0;
        /* The Menu tab is a real <button>, which (unlike the <a> tabs)
           carries the browser's default form-control padding (~9px
           top/bottom) - confirmed live as the cause of its icon+label
           rendering squeezed to almost nothing, since that padding ate
           most of the bar's 44px height before the flex column content
           ever got a share of it. Harmless on the <a> tabs, which have
           no default padding to begin with. */
        padding: 0;
        font-family: inherit;
        /* Legibility against header-art.svg bleeding through this bar
           (same background as the header) - text-shadow is the text
           equivalent of the drop-shadow filter already used on the
           logo image, since these are real characters, not an image
           filter can hug. */
        text-shadow: 0 1px 3px rgba(0, 0, 0, 0.9), 0 0 6px rgba(0, 0, 0, 0.7);
    }

    .gv-bottom-nav-item span {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /* Menu tab (the old header hamburger, moved here) - icon stacked
       above its label instead of the single centered span the other
       tabs use, matching the icon+label pattern of a native app tab
       bar's "More" slot. currentColor on the bars means they pick up
       this item's normal/hover/active color automatically, same as
       the text labels on every other tab. */
    .gv-bottom-nav-item.navbar-toggle {
        flex-direction: column;
        gap: 4px;
    }

    .gv-bottom-nav-icon {
        display: flex;
        flex-direction: column;
        justify-content: center;
        gap: 3px;
        width: 18px;
    }

    .gv-bottom-nav-icon-bar {
        display: block;
        height: 2px;
        width: 100%;
        background: currentColor;
        border-radius: 1px;
    }

    .gv-bottom-nav-item:hover,
    .gv-bottom-nav-item:focus {
        color: var(--gv-gold-bright, #f4d35e);
        text-decoration: none;
    }

    .gv-bottom-nav-active {
        color: var(--gv-gold-bright, #f4d35e);
        border-top-color: var(--gv-gold, #d4af37);
    }

    /* Room at the bottom of the scrolling area so the fixed bar never
       covers the last card/button - .game-container is the element
       that actually scrolls (see the note above body's rules), not
       body itself, so the padding has to live here. */
    .game-container {
        padding-bottom: calc(var(--gv-bottom-nav-h) + env(safe-area-inset-bottom, 0px) + 12px);
    }

    /* The floating phone/radio launchers are fixed at bottom:16-22px
       (see phone.styles.css / radio.styles.css) - directly under where
       the new tab bar now sits. Lifted by the bar's height so they
       float just above it instead of overlapping.

       "body " prefixed (not !important) on purpose - both modules'
       drag code repositions the bar by switching from bottom-anchored
       to top-anchored (setting inline style.bottom = "auto") while
       dragging. !important on this rule overrode that inline value
       unconditionally, so a dragged radio bar ended up with BOTH top
       and bottom resolving to real px values at once - per spec, a
       fixed-position element with non-auto top AND bottom and no
       explicit height stretches to fill the distance between them.
       Confirmed live as the radio bar's "expands when you try to move
       it" bug. The extra "body " ancestor is enough specificity to
       still beat radio.styles.css/phone.styles.css's own plain-ID
       bottom rule (loaded earlier) without needing !important, so a
       plain (non-!important) inline style set by the drag JS can
       still win over this one normally. */
    body #gl-phone-controls {
        bottom: calc(var(--gv-bottom-nav-h) + env(safe-area-inset-bottom, 0px) + 12px);
    }

    body #gl-radio-bar,
    body #gl-radio-restore {
        bottom: calc(var(--gv-bottom-nav-h) + env(safe-area-inset-bottom, 0px) + 10px);
    }

}

/* ================================================================
   QUICK-ACCESS TRAY (phone toggle + radio icon)
   ================================================================
   Both floating widgets are hidden by default and only shown while
   body carries .gl-tray-open (toggled by the handle below - see
   mobile.js) - collapsed out of the way of page content/admin buttons
   until actually wanted, on both mobile and desktop. !important here
   is deliberate and safe (unlike the earlier bottom-position bug):
   this rule means "hidden, full stop" with no inline style anywhere
   that's ever supposed to win over it - phone.script.js/radio.script.js
   keep managing their OWN visibility logic (which of bar/restore icon
   shows, phone's own panel) entirely unaffected once the tray IS open,
   since this rule simply doesn't match at that point. */
body:not(.gl-tray-open) #gl-phone-controls,
body:not(.gl-tray-open) #gl-radio-bar,
body:not(.gl-tray-open) #gl-radio-restore {
    display: none !important;
}

:root {
    --gl-tray-handle-size: 40px;
    --gl-tray-handle-gap: 10px;
}

.gl-tray-handle {
    position: fixed;
    right: 22px;
    bottom: 22px;
    z-index: 9001;
    width: var(--gl-tray-handle-size);
    height: var(--gl-tray-handle-size);
    border-radius: 50%;
    background: rgba(30, 30, 34, 0.92);
    color: #f0f0f0;
    border: 2px solid rgba(255, 255, 255, 0.15);
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35);
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
}

.gl-tray-handle:hover {
    border-color: rgba(255, 255, 255, 0.35);
}

.gl-tray-open .gl-tray-handle {
    border-color: var(--gv-gold, #d4af37);
    color: var(--gv-gold-bright, #f4d35e);
}

@media (max-width: 500px) {
    .gl-tray-handle {
        bottom: calc(var(--gv-bottom-nav-h) + env(safe-area-inset-bottom, 0px) + 12px);
    }
}

/* The handle sits at the exact same right:22px/bottom:22px spot phone
   and radio's own CSS already anchors to (that's the point - it's
   their shared "home" corner) - but that means the handle would sit
   directly ON TOP of the phone toggle once the tray opens, instead of
   beside it. Shifting the phone toggle (and, on mobile, the radio bar/
   restore icon that dock relative to it) further from the edge by the
   handle's own width+gap while the tray is open clears that spot -
   confirmed live as blocking the phone toggle's tap target entirely
   before this fix. positionRestoreButton() in radio.script.js reads
   the phone toggle's LIVE rect, so the restore icon (when that's the
   one showing) follows this shift automatically once mobile.js's tray
   toggle fires a resize event - no extra coupling needed there. */
body.gl-tray-open #gl-phone-controls {
    right: calc(22px + var(--gl-tray-handle-size) + var(--gl-tray-handle-gap));
}

body.gl-tray-open #gl-radio-bar {
    right: calc(22px + var(--gl-tray-handle-size) + var(--gl-tray-handle-gap) + var(--gl-phone-button-size, 56px) + 10px);
}

@media (min-width: 768px) {
    /* Desktop's #gl-radio-bar is left-docked regardless of tray state
       (see radio.styles.css) - cancel the mobile-only shift above so
       it doesn't pick up a stray right value fighting that. */
    body.gl-tray-open #gl-radio-bar {
        right: auto;
    }
}

/* Mobster status hover tooltip (class/template.php's userName partial,
   used everywhere a username renders - topbar, sidebar, forum posts,
   etc). #global-user-tooltip is ONE shared element appended to <body>
   and positioned by themes/default/js/ajax.js on hover (a CSS-only
   ::after would get clipped by the sidebar's overflow:auto - see the
   comment there for why this needs JS instead). position:fixed +
   translate(-50%, -100%) centers it directly above the cursor
   regardless of where the hovered username sits on the page. */
#global-user-tooltip {
    display: none;
    position: fixed;
    transform: translate(-50%, calc(-100% - 8px));
    background: var(--surface-2);
    color: var(--text);
    border: 1px solid var(--accent);
    padding: 4px 10px;
    border-radius: 4px;
    font-size: 12px;
    font-weight: normal;
    white-space: nowrap;
    z-index: 3000;
    pointer-events: none;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.5);
}

/* ================================================================
 * SHARED "gv-" DESIGN SYSTEM
 * ================================================================
 * The dark/gold "VIP card" look piloted on Crimes and Upgrade
 * Account (each of which still carries its own scoped copy of these
 * rules under .crime-shop/.upgrade-account - this is the SAME visual
 * recipe promoted to global reusable classes for every other module,
 * so it doesn't need re-inventing/copy-pasting per page). Drop these
 * classes into any module's own .tpl.php markup; no per-module CSS
 * file is required unless that page needs something bespoke on top.
 *
 * --gv-gold/--gv-gold-bright are a SEPARATE accent from the site's
 * base --accent (crimson) - deliberately so, since this is meant to
 * read as a distinct "premium" treatment (packages, crimes, and now
 * whichever pages get ported next), not a wholesale re-skin of every
 * link/button on the site.
 * ================================================================
 */
:root {
    --gv-gold: #d4af37;
    --gv-gold-bright: #f4d35e;
    --gv-ink: #0c0c10;
    --gv-panel: #17171d;
    --gv-panel-alt: #1e1e26;
    --gv-border: #33322a;
    --gv-text: #cfcdc2;
    --gv-text-dim: #8b8878;
}

/* A titled block of content (a card grid, a panel) with consistent
   spacing before the next one. */
.gv-section {
    margin-bottom: 34px;
}

/* Section captions - "◆ TITLE ◆" */
.gv-section-title {
    color: var(--gv-gold-bright);
    text-transform: uppercase;
    letter-spacing: 3px;
    font-size: 13px;
    font-weight: 700;
    text-align: center;
    margin: 0 0 4px;
    text-shadow: 0 0 10px rgba(212, 175, 55, 0.35);
}

.gv-section-title::before,
.gv-section-title::after {
    content: "\2666";
    color: var(--gv-gold);
    margin: 0 10px;
    font-size: 10px;
    vertical-align: middle;
}

.gv-section-sub {
    text-align: center;
    color: var(--gv-text-dim);
    font-size: 12px;
    margin: 0 0 20px;
}

/* Banner - a bordered gradient strip for a headline stat (balance,
   a resource total, etc), optionally with a bar and/or a button
   alongside (see .gv-banner-bar / .gv-btn). */
.gv-banner {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 20px;
    flex-wrap: wrap;
    background: linear-gradient(135deg, #1c1a10 0%, #100f0b 100%);
    border: 1px solid var(--gv-gold);
    border-radius: 8px;
    padding: 16px 22px;
    margin-bottom: 30px;
    box-shadow: 0 0 20px rgba(212, 175, 55, 0.12) inset, 0 6px 18px rgba(0, 0, 0, 0.4);
}

.gv-banner-info {
    flex: 0 0 auto;
    text-align: center;
}

.gv-banner-label {
    color: var(--gv-text-dim);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 1.5px;
    margin: 0 0 2px;
}

.gv-banner-amount {
    color: var(--gv-gold-bright);
    font-size: 22px;
    font-weight: 700;
    margin: 0;
    white-space: nowrap;
}

.gv-banner-amount small {
    color: var(--gv-text-dim);
    font-size: 13px;
    font-weight: 400;
}

/* Vertical hairline between two .gv-banner-info blocks, for a banner
   with several stats side by side (location/rank/nerve/energy, etc)
   instead of just one headline amount. */
.gv-banner-divider {
    width: 1px;
    align-self: stretch;
    background: var(--gv-border);
}

/* Progress bar - reused standalone (.gv-bar) or inside a .gv-banner
   (.gv-banner-bar just adds flex-grow so it fills the remaining
   banner width alongside a label and/or button). */
.gv-bar {
    height: 10px;
    background: var(--gv-ink);
    border: 1px solid var(--gv-border);
    border-radius: 5px;
    overflow: hidden;
}

.gv-banner-bar {
    flex: 1 1 160px;
    height: 10px;
    background: var(--gv-ink);
    border: 1px solid var(--gv-border);
    border-radius: 5px;
    overflow: hidden;
}

.gv-bar-fill {
    height: 100%;
    background: linear-gradient(90deg, var(--gv-gold) 0%, var(--gv-gold-bright) 100%);
}

/* Gold gradient button - the one CTA style for every "cool" page
   (buy/commit/save/submit). .gv-btn-block makes it full-width (for
   inside a card); omit for an inline/auto-width button (e.g. inside
   a .gv-banner). */
.gv-btn {
    display: inline-block;
    padding: 8px 22px;
    background: linear-gradient(180deg, var(--gv-gold-bright) 0%, var(--gv-gold) 100%);
    color: #1a1400;
    font-weight: 700;
    text-transform: uppercase;
    font-size: 12px;
    letter-spacing: 0.5px;
    border-radius: 5px;
    text-decoration: none;
    border: 1px solid #8a6d10;
    text-align: center;
    cursor: pointer;
    transition: transform 0.12s ease, box-shadow 0.12s ease, filter 0.12s ease;
}

.gv-btn:hover {
    filter: brightness(1.08);
    transform: translateY(-2px);
    box-shadow: 0 4px 14px rgba(212, 175, 55, 0.45);
    color: #1a1400;
    text-decoration: none;
}

.gv-btn-block {
    display: block;
    width: 100%;
}

/* Destructive-action variant (Sell, Delete, etc) - same shape as
   .gv-btn, crimson instead of gold so it reads as "careful" rather
   than "go", matching the base theme's --accent color. */
.gv-btn-danger {
    background: linear-gradient(180deg, var(--accent-hover) 0%, var(--accent) 100%);
    color: #fff;
    border-color: #7a1518;
}

.gv-btn-danger:hover {
    box-shadow: 0 4px 14px rgba(200, 32, 47, 0.45);
    color: #fff;
}

/* Unfilled variant - the "not selected" side of a two-way toggle
   (View X / View Y), or any secondary action that shouldn't compete
   with a page's one filled gold CTA. */
.gv-btn-outline {
    background: transparent;
    color: var(--gv-text-dim);
    border: 1px solid var(--gv-border);
}

.gv-btn-outline:hover {
    filter: none;
    transform: none;
    box-shadow: none;
    border-color: var(--gv-gold);
    color: var(--gv-gold-bright);
}

/* Card grid - a flex-wrapping row of .gv-card, sized by whatever the
   page needs (set flex-basis/max-width per module if the default
   220px is wrong for that content - see crimes.styles.css for an
   example of a narrower override for a page with many small cards). */
.gv-card-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    justify-content: center;
}

.gv-card {
    flex: 1 1 200px;
    max-width: 260px;
    background: linear-gradient(180deg, var(--gv-panel) 0%, var(--gv-ink) 100%);
    border: 1px solid var(--gv-border);
    border-radius: 10px;
    padding: 18px 16px;
    text-align: center;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.45);
    transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}

.gv-card:hover {
    transform: translateY(-5px);
    border-color: var(--gv-gold);
    box-shadow: 0 12px 28px rgba(0, 0, 0, 0.55), 0 0 22px rgba(212, 175, 55, 0.16);
}

/* A .gv-card variant WITH a header strip, for pages where a distinct
   colored top bar (matching the rest of the site's panel-heading
   look) reads better than a floating title - e.g. list-style pages
   where each card represents a record rather than a single choice. */
.gv-card-headed {
    padding: 0;
    overflow: hidden;
}

.gv-card-headed .gv-card-head {
    background: linear-gradient(90deg, #000 0%, #1a1a12 60%, #2a230f 100%);
    color: var(--gv-gold-bright);
    padding: 10px 16px;
    font-weight: 700;
    letter-spacing: 0.5px;
    border-bottom: 1px solid var(--gv-gold);
}

.gv-card-headed .gv-card-body {
    padding: 16px;
}

.gv-card-title {
    color: #fff;
    font-size: 15px;
    font-weight: 700;
    margin: 0 0 10px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.gv-card-price {
    font-size: 20px;
    font-weight: 700;
    color: #fff;
    margin-bottom: 14px;
}

/* Dark/gold reskin of a plain data table, for genuinely tabular
   content (transaction logs, admin lists) that shouldn't be forced
   into cards. Apply alongside (not instead of) Bootstrap's .table. */
.gv-table {
    width: 100%;
    border-collapse: collapse;
    background: var(--gv-panel);
    border: 1px solid var(--gv-border);
    border-radius: 8px;
    overflow: hidden;
}

.gv-table th {
    background: var(--gv-panel-alt);
    color: var(--gv-gold-bright);
    text-transform: uppercase;
    font-size: 11px;
    letter-spacing: 0.5px;
    padding: 10px 14px;
    text-align: left;
    border-bottom: 1px solid var(--gv-gold);
}

.gv-table td {
    padding: 10px 14px;
    color: var(--gv-text);
    border-bottom: 1px solid var(--gv-border);
}

.gv-table tbody tr:hover td {
    background: rgba(212, 175, 55, 0.06);
}

.gv-empty {
    text-align: center;
    color: var(--gv-text-dim);
    font-style: italic;
    padding: 20px;
    width: 100%;
}

/* Sidebar "Menu" panel (themes/default/loggedin.php) - every page's
   main navigation list. Distinct card + row treatment (NOT a plain
   Bootstrap list-group) so it matches the rest of the "gv-" design
   system instead of reading as a plain link list. */
.gv-sidebar-menu {
    padding: 14px 10px;
}

.gv-sidebar-menu .gv-section-title {
    padding: 0 6px;
}

.gv-user-panel .gv-section-title {
    white-space: nowrap;
    letter-spacing: 1px;
    font-size: 12px;
}

.gv-user-panel .gv-section-title::before,
.gv-user-panel .gv-section-title::after {
    margin: 0 6px;
}

.gv-nav-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.gv-nav-list li {
    margin-bottom: 4px;
}

.gv-nav-link {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 6px;
    padding: 9px 12px;
    border-radius: 6px;
    border-left: 3px solid transparent;
    color: var(--gv-text);
    font-size: 12px;
    font-weight: 600;
    text-decoration: none;
    transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}

.gv-nav-link:hover,
.gv-nav-link:focus {
    background: rgba(212, 175, 55, 0.08);
    border-left-color: var(--gv-gold);
    color: var(--gv-gold-bright);
    text-decoration: none;
}

.gv-nav-link > span:first-child {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
    flex: 1 1 auto;
}

.gv-nav-link small {
    color: var(--gv-text-dim);
    font-size: 9px;
    font-weight: 400;
    white-space: nowrap;
    flex: 0 0 auto;
}

/* User Account panel (themes/default/loggedin.php) - label/value
   stat rows instead of a plain Bootstrap list-group, sized to stay
   on one line at the sidebar's narrow width. */
.gv-user-panel {
    padding: 14px 16px;
}

.gv-user-panel .gv-section-title {
    margin-bottom: 12px;
}

/* Quick Links panel (themes/default/loggedin.php, replaced the old
   User Account stat block 2026-08-04 - see the HTML comment right
   above it for the rollback copy). Icon grid of shortcut destinations
   plus the Quick Use slot row. */
.ql-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 8px;
    margin-bottom: 4px;
}

.ql-item {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 0;
    aspect-ratio: 1;
    background: var(--gv-panel-alt);
    border: 1px solid var(--gv-border);
    border-radius: 8px;
    text-decoration: none;
    transition: border-color 0.15s ease, transform 0.15s ease;
}

.ql-item:hover {
    border-color: var(--gv-gold);
    transform: translateY(-2px);
    text-decoration: none;
}

.ql-icon {
    width: 26px;
    height: 26px;
    color: var(--gv-gold-bright);
}

.ql-badge {
    position: absolute;
    top: -6px;
    right: -6px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--accent);
    color: #fff;
    font-size: 9px;
    font-weight: 700;
    border-radius: 8px;
    line-height: 1;
}

.ql-quickuse-title {
    margin-top: 14px;
}

.ql-quickuse-row {
    display: flex;
    gap: 8px;
}

.ql-quickuse-form {
    margin: 0;
    flex: 1 1 0;
}

.ql-quickuse-slot {
    position: relative;
    width: 100%;
    aspect-ratio: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(180deg, var(--gv-panel) 0%, var(--gv-ink) 100%);
    border: 1px dashed var(--gv-border);
    border-radius: 8px;
    cursor: pointer;
    padding: 0;
}

.ql-quickuse-slot:not(.ql-quickuse-empty) {
    border-style: solid;
    border-color: var(--gv-gold);
    cursor: pointer;
}

.ql-quickuse-slot:not(.ql-quickuse-empty):hover {
    box-shadow: 0 0 10px rgba(212, 175, 55, 0.35);
}

.ql-quickuse-slot.ql-quickuse-empty {
    cursor: default;
    opacity: 0.5;
}

.ql-quickuse-icon {
    width: 22px;
    height: 22px;
    fill: var(--gv-gold-bright);
}

.ql-quickuse-fallback {
    width: 22px;
    height: 22px;
    border-radius: 5px;
    background: var(--gv-text-dim);
    color: #1a1400;
    font-weight: 700;
    font-size: 11px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.ql-quickuse-plus {
    color: var(--gv-text-dim);
    font-size: 16px;
}

.ql-quickuse-qty {
    background: var(--gv-gold, #d4af37);
    color: #1a1400;
}

.gv-stat-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
    padding: 6px 0;
    border-bottom: 1px solid var(--gv-border);
    font-size: 12px;
}

.gv-stat-row:last-child {
    border-bottom: none;
}

.gv-stat-row-bar {
    display: block;
    padding-bottom: 8px;
}

.gv-stat-row-top {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 6px;
}

.gv-stat-label {
    color: var(--gv-text-dim);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    font-size: 11px;
    white-space: nowrap;
    flex: 0 0 auto;
}

.gv-stat-value {
    color: #fff;
    font-weight: 600;
    text-align: right;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.gv-stat-bar {
    height: 8px;
}

/* Red, not Energy's old green - see the color-rotation note above
   .round-bar .gv-bar-fill-energy for the full reasoning. Global (not
   round-bar-scoped) since Health is the one bar shared verbatim by
   both the round-bar and the sidebar User Account panel. */
.gv-bar-fill-health {
    background: linear-gradient(90deg, var(--accent-hover) 0%, var(--accent) 100%);
}

/* Plain bordered container - for content that's a single full-width
   section (a log table, a settings block) rather than a grid of
   .gv-card choices. Same surface/border treatment as .gv-card without
   the hover-lift/grid sizing. */
.gv-panel {
    background: linear-gradient(180deg, var(--gv-panel) 0%, var(--gv-ink) 100%);
    border: 1px solid var(--gv-border);
    border-radius: 10px;
    padding: 20px;
    margin-bottom: 24px;
}

.gv-panel .gv-section-title {
    margin-bottom: 16px;
}

/* Form fields matching the gold-accented dark inputs already piloted
   on Upgrade Account's custom-amount field. */
.gv-input,
.gv-select {
    width: 100%;
    background: var(--gv-ink);
    border: 1px solid var(--gv-border);
    border-radius: 5px;
    color: #fff;
    padding: 10px 12px;
    font-size: 14px;
}

.gv-input:focus,
.gv-select:focus {
    outline: none;
    border-color: var(--gv-gold);
    box-shadow: 0 0 8px rgba(212, 175, 55, 0.3);
}

.gv-input::placeholder {
    color: var(--gv-text-dim);
}

.gv-label {
    display: block;
    color: var(--gv-text-dim);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 1px;
    margin-bottom: 6px;
}

.gv-field {
    margin-bottom: 14px;
}

/* Simple row-list (active deposits, recent activity, etc) - an
   alternative to .gv-table when each row is more of a description
   line than tabular data. */
.gv-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.gv-list li {
    padding: 10px 12px;
    border-bottom: 1px solid var(--gv-border);
    color: var(--gv-text);
    font-size: 13px;
}

.gv-list li:last-child {
    border-bottom: none;
}

/* Generic list row - a record with a title/badge on one side and
   meta info/actions on the other (a destination, a log entry, etc),
   as an alternative to .gv-table when a full table feels heavier
   than the content needs. */
.gv-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 10px;
    padding: 12px 16px;
    margin-bottom: 8px;
    background: var(--gv-panel-alt);
    border: 1px solid var(--gv-border);
    border-radius: 6px;
}

.gv-row:last-child {
    margin-bottom: 0;
}

.gv-row-title {
    color: #fff;
    font-weight: 600;
    font-size: 14px;
}

.gv-row-title a {
    color: #fff;
    text-decoration: none;
}

.gv-row-meta {
    color: var(--gv-text-dim);
    font-size: 12px;
}

.gv-badge {
    display: inline-block;
    background: var(--gv-gold);
    color: #1a1400;
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    padding: 2px 8px;
    border-radius: 10px;
    margin-left: 8px;
}

/* Neutral variant - a status worth noting but not celebrating or
   warning about (e.g. "No Nerve", a cooldown still running). */
.gv-badge-outline {
    display: inline-block;
    background: transparent;
    border: 1px solid var(--gv-border);
    color: var(--gv-text-dim);
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    padding: 1px 8px;
    border-radius: 10px;
    margin-left: 8px;
}

/* Urgent variant - something that needs attention (in jail, in the
   hospital), crimson to match .gv-btn-danger/--accent. */
.gv-badge-danger {
    display: inline-block;
    background: var(--accent);
    color: #fff;
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    padding: 2px 8px;
    border-radius: 10px;
    margin-left: 8px;
}

.gv-btn-sm {
    padding: 6px 16px;
    font-size: 11px;
}

/* Centers a single card (a CTA, a confirmation) instead of letting it
   stretch full width - use around one .gv-card when it's the only
   thing on the page rather than one of a grid. */
.gv-center-wrap {
    max-width: 420px;
    margin: 0 auto;
}

/* Weapon/medical item icons - themes/default/images/weapon-icons.svg,
   referenced via <use> in inventory.tpl.php's inventoryItem and
   blackmarket's item template. currentColor in the sprite means this
   is the only place the color needs setting; unsized <svg> defaults
   to a large intrinsic box, so the explicit width/height here is load
   -bearing, not decorative. */
.inv-item-icon {
    width: 28px;
    height: 28px;
    flex-shrink: 0;
    color: var(--gv-gold, #d4af37);
}

.inv-item-info {
    display: flex;
    align-items: center;
    gap: 10px;
}

.market-item-icon {
    width: 36px;
    height: 36px;
    flex-shrink: 0;
    color: var(--gv-gold, #d4af37);
}

/* ================================================================
 * SHARED CASINO CARD-GAME SYSTEM
 * ================================================================
 * Piloted on Blackjack, promoted here once Tonk needed the identical
 * card faces and betting-chip selector - same "promote to global
 * reusable classes" pattern as the rest of the gv- system above.
 * Per-game table layout (felt shape, hand positions, pile placement)
 * stays in each module's own {name}.styles.css; only the genuinely
 * game-agnostic pieces (a card, a card back, a betting chip) live
 * here.
 * ================================================================
 */

.card {
    position: relative;
    width: clamp(48px, 9vw, 72px);
    height: clamp(68px, 12.6vw, 100px);
    display: inline-block;
    margin: 0 4px;
    border-radius: 6px;
    background: linear-gradient(160deg, #fbfbf8 0%, #eceae0 100%);
    box-shadow: 0 3px 8px rgba(0, 0, 0, 0.45), inset 0 0 0 1px rgba(0, 0, 0, 0.06);
    vertical-align: top;
    animation: gv-card-deal-in 0.28s ease-out;
}

/* suits - color + the glyph every rank rule below concatenates in */
.card.clubs { color: #1a1a1a; --suit-glyph: "\2663"; }
.card.spades { color: #1a1a1a; --suit-glyph: "\2660"; }
.card.hearts { color: #b3222f; --suit-glyph: "\2665"; }
.card.diamonds { color: #b3222f; --suit-glyph: "\2666"; }

/* corner index - rank on top, suit glyph below, top-left of the card */
.card::before {
    position: absolute;
    top: 4px;
    left: 6px;
    font-size: clamp(10px, 1.9vw, 13px);
    font-weight: 700;
    line-height: 1.05;
    white-space: pre;
    font-family: Georgia, "Times New Roman", serif;
}

/* large centered watermark glyph - the card's dominant visual */
.card::after {
    content: var(--suit-glyph);
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -52%);
    font-size: clamp(20px, 4vw, 32px);
    opacity: 0.32;
}

.card.card-A::before { content: "A" "\A" var(--suit-glyph); }
.card.card-2::before { content: "2" "\A" var(--suit-glyph); }
.card.card-3::before { content: "3" "\A" var(--suit-glyph); }
.card.card-4::before { content: "4" "\A" var(--suit-glyph); }
.card.card-5::before { content: "5" "\A" var(--suit-glyph); }
.card.card-6::before { content: "6" "\A" var(--suit-glyph); }
.card.card-7::before { content: "7" "\A" var(--suit-glyph); }
.card.card-8::before { content: "8" "\A" var(--suit-glyph); }
.card.card-9::before { content: "9" "\A" var(--suit-glyph); }
.card.card-10::before { content: "10" "\A" var(--suit-glyph); }
.card.card-J::before { content: "J" "\A" var(--suit-glyph); }
.card.card-Q::before { content: "Q" "\A" var(--suit-glyph); }
.card.card-K::before { content: "K" "\A" var(--suit-glyph); }

/* card back - gold diamond lattice on dark ink. Single design (no
   "red"/"blue" back variant - that distinction was purely cosmetic in
   the old sprite-based Blackjack and never read by any game logic). */
.card.backs {
    background:
        repeating-linear-gradient(45deg, rgba(212, 175, 55, 0.22) 0 2px, transparent 2px 14px),
        repeating-linear-gradient(-45deg, rgba(212, 175, 55, 0.22) 0 2px, transparent 2px 14px),
        linear-gradient(160deg, var(--gv-panel) 0%, var(--gv-ink) 100%);
    border: 1px solid var(--gv-gold);
    box-shadow: 0 3px 8px rgba(0, 0, 0, 0.45);
}

.card.backs::before,
.card.backs::after {
    content: none;
}

@keyframes gv-card-deal-in {
    from { transform: translateY(-14px) scale(0.92); opacity: 0; }
    to { transform: translateY(0) scale(1); opacity: 1; }
}

/* Betting-chip selector - a row of clickable denomination chips that
   fill a bet <input>, plus a Clear chip. See blackjack.script.js /
   tonk.script.js for the click handler (client-side only, no new
   endpoint - the existing "bet" field is what actually submits). */
.gv-chip-row {
    display: flex;
    justify-content: center;
    gap: 8px;
    flex-wrap: wrap;
    margin-bottom: 16px;
}

.gv-chip-btn {
    width: 56px;
    height: 56px;
    border-radius: 50%;
    border: 2px dashed rgba(255, 255, 255, 0.5);
    color: #fff;
    font-size: 12px;
    font-weight: 700;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 3px 6px rgba(0, 0, 0, 0.5), inset 0 0 0 3px rgba(255, 255, 255, 0.15);
    transition: transform 0.1s ease;
}

.gv-chip-btn:hover {
    transform: translateY(-3px);
}

.gv-chip-btn:active {
    transform: translateY(0);
}

.gv-chip-100 { background: #4a4a52; }
.gv-chip-500 { background: #5a2d8c; }
.gv-chip-1000 { background: #1a1a1a; }
.gv-chip-5000 { background: var(--accent); }

.gv-chip-clear {
    width: auto;
    height: 56px;
    padding: 0 14px;
    border-radius: 10px;
    background: var(--gv-panel-alt);
    border: 1px solid var(--gv-border);
    box-shadow: none;
}

/* A small stack of poker-chip discs, used to represent the current
   pot/stake on a felt table. */
.gv-chip-stack {
    display: flex;
    flex-direction: column-reverse;
    align-items: center;
}

.gv-chip-stack .gv-chip {
    width: 34px;
    height: 10px;
    border-radius: 50%;
    background: repeating-conic-gradient(var(--gv-gold-bright) 0deg 30deg, var(--accent) 30deg 60deg);
    border: 1px solid var(--gv-ink);
    box-shadow: 0 2px 3px rgba(0, 0, 0, 0.5);
    margin-top: -6px;
}