        :root {
            /* Fluid scale tokens: clamp(min, preferred, max).
               preferred is today's vw/vh value, unchanged - min/max are that
               same formula evaluated at the supported viewport floor/ceiling
               (1280x800 .. 2560x1440). Inside that range this renders pixel-for-
               pixel identical to before; outside it, the value clamps instead of
               shrinking/growing without limit.
               --u-N = width axis, anchored 1280px/2560px (N = vw value x100)
               --v-N = height axis, anchored 800px/1440px (N = vh value x100) */
            --u-5: clamp(1px, 0.05vw, 1px);
            --u-10: clamp(1px, 0.1vw, 3px);
            --u-15: clamp(2px, 0.15vw, 4px);
            --u-20: clamp(3px, 0.2vw, 5px);
            --u-25: clamp(3px, 0.25vw, 6px);
            --u-30: clamp(4px, 0.3vw, 8px);
            --u-35: clamp(4px, 0.35vw, 9px);
            --u-40: clamp(5px, 0.4vw, 10px);
            --u-50: clamp(6px, 0.5vw, 13px);
            --u-52: clamp(7px, 0.52vw, 13px);
            --u-60: clamp(8px, 0.6vw, 15px);
            --u-65: clamp(8px, 0.65vw, 17px);
            --u-68: clamp(9px, 0.68vw, 17px);
            --u-70: clamp(9px, 0.7vw, 18px);
            --u-75: clamp(10px, 0.75vw, 19px);
            --u-80: clamp(10px, 0.8vw, 20px);
            --u-85: clamp(11px, 0.85vw, 22px);
            --u-90: clamp(12px, 0.9vw, 23px);
            --u-95: clamp(12px, 0.95vw, 24px);
            --u-100: clamp(13px, 1vw, 26px);
            --u-105: clamp(13px, 1.05vw, 27px);
            --u-110: clamp(14px, 1.1vw, 28px);
            --u-120: clamp(15px, 1.2vw, 31px);
            --u-126: clamp(16px, 1.26vw, 32px);
            --u-130: clamp(17px, 1.3vw, 33px);
            --u-140: clamp(18px, 1.4vw, 36px);
            --u-150: clamp(19px, 1.5vw, 38px);
            --u-160: clamp(20px, 1.6vw, 41px);
            --u-170: clamp(22px, 1.7vw, 44px);
            --u-180: clamp(23px, 1.8vw, 46px);
            --u-190: clamp(24px, 1.9vw, 49px);
            --u-200: clamp(26px, 2vw, 51px);
            --u-210: clamp(27px, 2.1vw, 54px);
            --u-220: clamp(28px, 2.2vw, 56px);
            --u-240: clamp(31px, 2.4vw, 61px);
            --u-250: clamp(32px, 2.5vw, 64px);
            --u-260: clamp(33px, 2.6vw, 67px);
            --u-280: clamp(36px, 2.8vw, 72px);
            --u-300: clamp(38px, 3vw, 77px);
            --u-320: clamp(41px, 3.2vw, 82px);
            --u-340: clamp(44px, 3.4vw, 87px);
            --u-350: clamp(45px, 3.5vw, 90px);
            --u-380: clamp(49px, 3.8vw, 97px);
            --u-450: clamp(58px, 4.5vw, 115px);
            --u-460: clamp(59px, 4.6vw, 118px);
            --u-500: clamp(64px, 5vw, 128px);
            --u-900: clamp(115px, 9vw, 230px);
            --u-1200: clamp(154px, 12vw, 307px);
            --u-1600: clamp(205px, 16vw, 410px);
            --u-2000: clamp(256px, 20vw, 512px);
            --u-2500: clamp(320px, 25vw, 640px);
            --u-3000: clamp(384px, 30vw, 768px);

            --v-20: clamp(2px, 0.2vh, 3px);
            --v-30: clamp(2px, 0.3vh, 4px);
            --v-50: clamp(4px, 0.5vh, 7px);
            --v-150: clamp(12px, 1.5vh, 22px);
            --v-200: clamp(16px, 2vh, 29px);
            --v-550: clamp(44px, 5.5vh, 79px);
            --v-600: clamp(48px, 6vh, 86px);
            --v-750: clamp(60px, 7.5vh, 108px);
            --v-800: clamp(64px, 8vh, 115px);
            --v-1600: clamp(128px, 16vh, 230px);
            --v-2000: clamp(160px, 20vh, 288px);
        }

        .server-item {
            transform: translateZ(0);
            will-change: transform;
        }
        html, body {
            margin: 0;
            padding: 0;
        }

        body {
            font-family: 'Outfit', sans-serif;
            background-color: #121212;
            color: #ffffff;
            background-image: url("/images/background_pripyat_2752x1536.png");
            background-size: cover;
            background-position: center;
            background-repeat: no-repeat;
            background-attachment: fixed;
        }

        .glass-panel {
            /* No backdrop-filter (see prior perf notes on this) - panels stay
               readable via a near-opaque background instead of blur. */
            background-color: rgba(20, 20, 20, 0.95);
            border: 1px solid rgba(255, 255, 255, 0.05);
            box-shadow: 0 6px 16px -8px rgba(0, 0, 0, 0.5);
        }

        .active-duration {
            border-color: #cd412b !important;
            color: #cd412b !important;
            background-color: rgba(205, 65, 43, 0.05);
            box-shadow: 0 0 12px rgba(205, 65, 43, 0.35);
        }

        .server-item.active {
            border-color: rgba(205, 65, 43, 0.4);
            background-color: rgba(205, 65, 43, 0.05);
        }

        /* Deliberately plain: one element, one transition, no child elements
           with their own separate fade timing. Two independent fades
           (text fading in, then the whole overlay fading out moments later)
           overlapping is what read as flickering/blinking before. */
        #preloader {
            transition: opacity 0.4s ease-out;
        }
        #preloader.preloader-hidden {
            opacity: 0;
            pointer-events: none;
        }

        .command-well {
            box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.55), inset 0 0 0 1px rgba(255, 255, 255, 0.04);
            transition: box-shadow 0.3s ease;
        }
        .command-well.copy-success {
            box-shadow: inset 0 2px 8px rgba(34, 197, 94, 0.35), inset 0 0 0 1px rgba(34, 197, 94, 0.5);
        }

        /* Server-stats charts panel (Connect/Server tab, right column) */
        .stat-section {
            flex: 1;
            display: flex;
            flex-direction: column;
            padding: var(--u-100) var(--u-120);
            background: #171717;
            border: 1px solid rgba(255, 255, 255, 0.1);
            border-radius: var(--u-120);
            /* Was a flat 220px - immune to viewport height, so three stacked
               panels (660px+ before gaps) would blow through anything shorter
               than that regardless of window height. Height-axis token
               instead, so all three shrink together on short viewports. */
            min-height: var(--v-1600);
        }
        /* Grid, not flex+absolute: the old version centered the geo-location
           caption with position:absolute + left:50% so it wouldn't shift
           when the ms/GB/% value's text width changed - but that gave it
           zero collision guard against the title or value, so a longer
           location name (or just a narrower panel) visually overlapped
           both. A grid's middle track can shrink and ellipsize on its own,
           but by construction can never overlap the outer two tracks.

           Side columns are minmax(0, 1fr) - i.e. forced EQUAL to each
           other - rather than each auto-sized to its own content. They
           used to be `auto auto`, which sized column 1 to the title's
           width and column 3 to the value's width independently - so the
           middle (caption) track was centered in whatever space was left
           BETWEEN those two, not centered on the card. Every time the
           value's digit count changed (27ms vs 142ms), column 3's width
           changed, and the caption visibly shifted left/right along with
           it despite never itself changing. Equal 1fr side columns keep
           the caption's center fixed at the card's actual center
           regardless of how wide either side's content is. */
        .stat-header {
            display: grid;
            grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
            align-items: center;
            column-gap: var(--u-40);
            margin-bottom: var(--u-80);
        }
        /* Explicit columns, not auto-placement: the RAM/CPU headers have only
           two children (title + value, no center caption) - left to
           auto-placement, grid fills cells in DOM order, which would put
           the value into the empty middle track instead of the right one. */
        .stat-title { grid-column: 1; justify-self: start; }
        .stat-header-center {
            /* justify-self must stay stretch (the default - not "center"):
               a non-stretch justify-self sizes the item to its own content's
               preferred width instead of clamping it to the track, which
               silently let a long location name render at full width again,
               spilling over the title/value with no ellipsis ever kicking
               in. Stretch to the track, then center the *content* inside it
               with the element's own justify-content (it's a flex row via
               the "flex justify-center" Tailwind classes). min-width:0 is
               what actually lets that stretched box shrink below its
               content's natural size in the first place - a grid item's
               default min-width is auto ("never shrink below content"). */
            grid-column: 2;
            min-width: 0;
            overflow: hidden;
        }
        .stat-current-value { grid-column: 3; justify-self: end; }
        .stat-title {
            display: flex;
            align-items: center;
            gap: var(--u-40);
            font-size: var(--u-80);
            font-weight: bold;
            color: #888888;
            text-transform: uppercase;
            letter-spacing: 0.05em;
        }
        .stat-title i { width: 1em; height: 1em; }
        .stat-current-value {
            font-size: var(--u-110);
            font-weight: 800;
            color: #cd412b;
        }
        .time-filters {
            display: flex;
            gap: var(--u-40);
            margin-bottom: var(--u-80);
            flex-wrap: wrap;
        }
        .time-btn {
            background: transparent;
            border: 1px solid rgba(255, 255, 255, 0.1);
            color: #888888;
            padding: var(--u-30) var(--u-40);
            border-radius: var(--u-40);
            font-size: var(--u-70);
            font-weight: 600;
            cursor: pointer;
            transition: all 0.2s ease;
            flex-grow: 1;
            text-align: center;
        }
        .time-btn:hover {
            background: rgba(255, 255, 255, 0.05);
            color: white;
        }
        .time-btn.active {
            background: #cd412b;
            color: white;
            border-color: #cd412b;
        }
        .chart-container {
            flex-grow: 1;
            position: relative;
            width: 100%;
            min-height: 0;
            display: flex;
            flex-direction: column;
        }

        /* Hand-rolled sparkline (Ping/RAM/CPU) - a plain SVG line plotted at
           exact pixel coordinates we compute ourselves, plus tick labels laid
           out with flexbox space-between. No charting library scale/tick
           logic involved, so there's no category-vs-linear axis confusion,
           no tick-collision, no index-based positioning that drifts between
           refreshes - the line always spans the SVG edge-to-edge by
           construction, and the labels are just N flex children. */
        .sparkline-row {
            flex: 1;
            min-height: 0;
            display: flex;
            gap: var(--u-50);
        }
        /* SVG is a replaced element with an intrinsic aspect ratio (from its
           viewBox) - in a flex row that can make it size by aspect ratio
           instead of stretching to the row's full height like a plain <div>
           would, which is exactly why the grid lines and the (correctly
           stretched) Y-label column drifted out of alignment. Absolute-fill
           inside a relatively-positioned wrapper sidesteps that entirely:
           inset:0 always matches the wrapper's box exactly, no intrinsic
           sizing involved. */
        .sparkline-plot {
            flex: 1;
            min-width: 0;
            position: relative;
        }
        .sparkline-svg {
            position: absolute;
            inset: 0;
            width: 100%;
            height: 100%;
            display: block;
        }
        .sparkline-line {
            stroke-width: 2;
            vector-effect: non-scaling-stroke;
        }
        .sparkline-fill {
            opacity: 0.12;
        }
        .sparkline-grid {
            stroke: #2c2c2c;
            stroke-width: 1;
            vector-effect: non-scaling-stroke;
        }
        .sparkline-y-labels {
            width: var(--u-240);
            flex-shrink: 0;
            display: flex;
            flex-direction: column;
            justify-content: space-between;
            text-align: right;
        }
        .sparkline-y-labels span {
            color: #888888;
            font-size: var(--u-65);
            line-height: 1;
        }
        .sparkline-x-labels {
            display: flex;
            justify-content: space-between;
            margin-top: var(--u-40);
            margin-right: calc(var(--u-240) + var(--u-50)); /* stay under the SVG, not the y-labels column */
        }
        .sparkline-x-labels span {
            color: #888888;
            font-size: var(--u-65);
            white-space: nowrap;
        }
        .sparkline-cursor-line {
            stroke: rgba(255, 255, 255, 0.25);
            stroke-width: 1;
            vector-effect: non-scaling-stroke;
            pointer-events: none;
        }
        .sparkline-cursor-dot {
            stroke: #121212;
            stroke-width: 4;
            vector-effect: non-scaling-stroke;
            pointer-events: none;
        }
        .sparkline-tooltip {
            position: absolute;
            top: var(--u-40);
            transform: translateX(-50%);
            background: rgba(26, 26, 26, 0.95);
            border: 1px solid #2c2c2c;
            border-radius: var(--u-40);
            padding: var(--u-30) var(--u-60);
            color: white;
            font-size: var(--u-70);
            font-weight: 600;
            white-space: nowrap;
            pointer-events: none;
            z-index: 1;
        }
        .sparkline-tooltip .sparkline-tooltip-time {
            color: #888888;
            font-weight: 500;
            margin-right: var(--u-40);
        }

        .custom-scroll::-webkit-scrollbar { width: var(--u-30); }
        .custom-scroll::-webkit-scrollbar-track { background: transparent; }
        .custom-scroll::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.1); border-radius: var(--u-30); }
        .custom-scroll::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.2); }

        /* Every clickable element here already shows state via hover/active scale +
           color, so the browser's default blue focus ring is just visual noise on
           top of that — applies to server-item cards and leaderboard rows too, not
           just <a>/<button>. */
        *:focus {
            outline: none;
        }

