/* Unturned statistics tool.
 *
 * One stylesheet for all seven sections, which is the point: the four pages this replaced
 * each carried their own inline <style> block and defined overlapping classes (.period-btn,
 * .stat-value, .section-title, .stat-highlight in more than one file), which is exactly why
 * they stopped looking related.
 *
 * The register is instrument panel, not marketing page.
 *
 * Gold is for interaction and identity, never for data. Active tab, primary chart series,
 * links, and our own plugins. Figures render in body colour at size instead, because when
 * every number is gold nothing is emphasised.
 */

:root {
    /* The second series colour, shared by the charts and the share bars so that "servers"
       looks like the same thing wherever it is drawn. */
    --stat-series-2: #4c7fa8;
    --stat-up: #2c7a31;
    --stat-down: #a33a2a;
    --stat-flat: var(--bs-secondary-color);
}

[data-bs-theme="dark"] {
    --stat-series-2: #6fa8d0;
    --stat-up: #6fbf73;
    --stat-down: #e08272;
}

/* ── Section navigation ───────────────────────────────────────────────────────
 * The same underlined strip the server detail page uses. Kept as its own class
 * rather than reusing .server-tabs directly so the server page is not destabilised
 * by edits made for this tool; the two should be merged into one component later.
 */
/* Sticky, so the section you are in and the way out of it stay reachable down a long
   table. It carries its own background because a transparent sticky strip lets the rows
   scroll through it. */
.stats-tabs-bar {
    position: sticky;
    top: 0;
    z-index: 3;
    background: var(--bs-body-bg);
    border-bottom: 1px solid var(--bs-border-color);
    margin-bottom: 0.5rem;
}


.stats-tabs {
    display: flex;
    /* No gap. Any space between two tabs is space the active underline cannot reach,
       so moving between neighbours shows a break in the gold rule. */
    margin: 0;
    padding: 0;
    list-style: none;
    /* Seven tabs do not fit a phone. Scroll rather than wrap into a second row. */
    flex-wrap: nowrap;
    overflow-x: auto;
    /* Explicit: one axis set to auto computes the other from visible to auto, which is
       how a one-line strip ends up offering a vertical scrollbar it has no use for. */
    overflow-y: hidden;
    scrollbar-width: none;
}

.stats-tabs::-webkit-scrollbar {
    display: none;
}

/* Fades the tabs out on whichever side still has more, rather than casting a shadow. A
   fade is the right metaphor for a strip that scrolls, and unlike a shadow it needs no
   per-theme colour: it reveals whatever is behind, so it reads the same on the light and
   the dark ground. Toggled by script, since a mask cannot know the scroll position. */
.stats-tabs.fade-start {
    -webkit-mask-image: linear-gradient(to right, transparent, #000 28px);
    mask-image: linear-gradient(to right, transparent, #000 28px);
}

.stats-tabs.fade-end {
    -webkit-mask-image: linear-gradient(to left, transparent, #000 28px);
    mask-image: linear-gradient(to left, transparent, #000 28px);
}

.stats-tabs.fade-start.fade-end {
    -webkit-mask-image: linear-gradient(to right, transparent, #000 28px, #000 calc(100% - 28px), transparent);
    mask-image: linear-gradient(to right, transparent, #000 28px, #000 calc(100% - 28px), transparent);
}

.stats-tabs .nav-item:first-child .nav-link {
    padding-left: 0;
}

.stats-tabs .nav-link {
    white-space: nowrap;
    color: var(--bs-secondary-color);
    background: transparent;
    border: 0;
    /* The active marker sits on the strip's own rule, so it needs a matching offset to
       cover it rather than stack under it. */
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    border-radius: 0;
    font-weight: 500;
    padding: 0.55rem 0.8rem;
}

.stats-tabs .nav-link:hover {
    color: var(--bs-body-color);
    border-bottom-color: var(--bs-border-color);
}

.stats-tabs .nav-link.active {
    color: var(--bs-body-color);
    border-bottom-color: var(--bs-primary);
}

/* Leaves the tool, so it is not one of the sections and never takes the active underline.
   Pushed to the far end and set in the muted weight, so it reads as an exit rather than as
   an eighth thing to choose between. */
.stats-tabs-exit .nav-link {
    padding-right: 0;
    font-weight: 400;
}

.stats-tabs-exit .nav-link:hover {
    color: var(--bs-primary);
    border-bottom-color: transparent;
}

/* On a phone the strip scrolls, so an exit pinned to its far end is the one item certain
   to be off screen. It is dropped there and reappears as a button in the header instead,
   where there is room beside the cadence chip. */
@media (max-width: 767.98px) {
    .stats-tabs-exit {
        display: none;
    }
}

/* The header's own way back, small screens only. Sits on the dark photographic ground, so
   it takes its colours from there rather than from the theme, the same way the cadence chip
   beside it does. */
.stats-browser-btn {
    margin-left: auto;
    color: rgba(255, 255, 255, 0.85);
    background: rgba(255, 255, 255, 0.12);
    border: 1px solid rgba(255, 255, 255, 0.18);
    font-size: 0.8rem;
    padding: 0.25rem 0.7rem;
    white-space: nowrap;
}

.stats-browser-btn:hover,
.stats-browser-btn:focus {
    color: #fff;
    background: rgba(255, 255, 255, 0.2);
    border-color: rgba(255, 255, 255, 0.3);
}

/* The header uses the site's own page-header treatment, so text sits on a dark
   photographic ground and takes its colours from there rather than from the theme. */
.stats-page-header .stats-head {
    min-width: 0;
}

.stats-head h1 {
    font-size: 1.7rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    margin: 0;
    color: #fff;
}

/* A dot rather than the word "live", because the timestamp beside it already says what it
   means and two words saying the same thing is one too many. */
.stats-asof {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.8rem;
    color: rgba(255, 255, 255, 0.72);
    white-space: nowrap;
    background: rgba(255, 255, 255, 0.10);
    border-radius: 2rem;
    padding: 0.25rem 0.7rem;
    cursor: default;
}

.stats-live-dot {
    width: 0.45rem;
    height: 0.45rem;
    border-radius: 50%;
    background: var(--stat-up);
    flex: 0 0 auto;
}

/* One line, on every section.
 *
 * The header is the same furniture on seven pages, so it must not grow and shrink as you
 * move between them. Every standfirst is written short enough to sit on one line inside the
 * 68ch measure, and the min-height holds the line open on the one section that has no
 * subtitle at all, so the header keeps its height there too. */
.stats-standfirst {
    font-size: 0.95rem;
    line-height: 1.5;
    min-height: 1.5em;
    color: rgba(255, 255, 255, 0.72);
    margin: 0.35rem 0 0;
}

/* ── Headline figures ──────────────────────────────────────────────────────── */
/* Flex, not grid, and the reason is the grey.
 *
 * The separators here are the container's own background showing through a 1px gap, which
 * is a neat trick until a row is not full. A grid keeps its columns whether or not there is
 * a tile in them, so five tiles in a three-column grid left an empty cell in the second row
 * and that cell showed the container background: a slab of border grey, the width of a
 * whole tile, that looked like something had failed to load.
 *
 * Flex has no columns to leave empty. Items grow into whatever width is left, so the last
 * row is always full however many tiles ended up on it, and the layout resolves itself at
 * every width instead of only at the ones a column count happens to suit.
 *
 * On a wide screen the basis is small enough that every tile fits on one row: five of them
 * come to 880px against a container of 1140. An earlier version gave the overview's first
 * two half the width each, which pushed the other three onto a second row that the page had
 * plenty of room for, and spent a row of height to say nothing. */
.stat-tiles {
    display: flex;
    flex-wrap: wrap;
    gap: 1px;
    background: var(--bs-border-color);
    border: 1px solid var(--bs-border-color);
    border-radius: 0.5rem;
    overflow: hidden;
}

.stat-tile {
    /* Grows to fill the row it lands on. The basis is what decides how many fit before a
       wrap, so it is the only number that needs tuning for the whole thing to behave. */
    flex: 1 1 11rem;
    min-width: 0;
    background: var(--bs-body-bg);
    padding: 0.9rem 1.05rem;
    /* Three lines, always, whatever the tile has to say. Anything that runs out of room is
       cut with an ellipsis rather than wrapped, because one tile taking a second line makes
       the whole row taller and the set stops looking like a set. */
    min-width: 0;
}

.stat-tile .value,
.stat-tile .label,
.stat-tile .sub {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* One size for every value, name or number alike. A name used to drop a step, which made
   the odd tile out visibly smaller than the figures beside it for no reason a reader could
   infer. Long names are cut instead, and carry the full text in a tooltip. */
.stat-tile .value {
    font-size: 1.6rem;
    font-weight: 600;
    line-height: 1.2;
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
    color: var(--bs-body-color);
}

/* A tile holding a name rather than a figure. Same size as the rest now; the only thing it
   changes is turning tabular numerals off, since those exist to line up columns of digits
   and do nothing for letters but space them oddly. */
.stat-tile .value.is-text {
    font-variant-numeric: normal;
}

.stat-tile .label {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-weight: 600;
    color: var(--bs-secondary-color);
    margin-top: 0.25rem;
}

/* The change sits beside the figure rather than under it, on the same baseline. On its own
   row it was a fourth line that only some tiles had, and it read as another statistic
   instead of as an annotation on the one above it. Next to the number it is obviously
   about that number. */
.stat-value-row {
    display: flex;
    align-items: baseline;
    gap: 0.4rem;
    min-width: 0;
}

/* The figure gives way first, so a long name is what gets cut rather than the change
   being pushed out of the tile. */
.stat-value-row .value {
    min-width: 0;
}

.stat-value-row .delta {
    flex: 0 0 auto;
}

/* Change against the same figure a while back. The site already shows this on the browser
   and the server page, in green and red with an arrow, so it uses the same language here. */
.stat-tile .delta {
    font-size: 0.75rem;
    font-weight: 600;
    line-height: 1.2;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.stat-tile .delta .bi {
    font-size: 0.7rem;
}

.stat-tile .delta.is-up { color: var(--stat-up); }
.stat-tile .delta.is-down { color: var(--stat-down); }
.stat-tile .delta.is-flat { color: var(--bs-secondary-color); }

/* Holds the third line open whether or not the tile has one, so a tile with nothing to add
   is the same height as the one beside it rather than shorter. */
.stat-tile .sub {
    font-size: 0.78rem;
    line-height: 1.35;
    min-height: 1.35em;
    color: var(--bs-secondary-color);
    margin-top: 0.15rem;
}

/* Below the wide layout, every tile is half a row.
 *
 * Left to its own devices, flex fits as many as the basis allows and the remainder wrap,
 * which on four tiles in a middling window gives three and then one stretched across the
 * full width on its own. No grey hole, but not a layout anyone would draw. Pinning the
 * basis to half means the wrap is deliberate at every size: four tiles go 2 and 2, five go
 * 2, 2 and 1, and the odd one out is the only tile that ever spans a row. */
@media (max-width: 991.98px) {
    .stat-tile {
        flex: 1 1 calc(50% - 1px);
    }
}

/* ── Section headings ──────────────────────────────────────────────────────── */
.stats-section {
    margin-top: 1.75rem;
}

.stats-section-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    column-gap: 0.75rem;
    row-gap: 0.15rem;
    padding-bottom: 0.4rem;
    border-bottom: 1px solid var(--bs-border-color);
    margin-bottom: 0.75rem;
}

.stats-section-head h2 {
    font-size: 1.02rem;
    font-weight: 600;
    letter-spacing: -0.01em;
    margin: 0;
}

.stats-section-head .note {
    font-size: 0.82rem;
    color: var(--bs-secondary-color);
    min-width: 0;
}

/* Held against the far edge only while it shares a line with the heading. Below that the
   head stacks, and an auto margin would strand this against the right edge on a line of its
   own, reading as a stray rather than as a footnote to the heading above it. */
@media (min-width: 768px) {
    .stats-section-head .spacer {
        margin-left: auto;
    }
}

@media (max-width: 767.98px) {
    .stats-section-head {
        flex-direction: column;
        align-items: flex-start;
    }
}

/* ── Ranked tables ─────────────────────────────────────────────────────────────
 * Alignment follows the rule that makes long tables readable: text left, numbers right,
 * and every header aligned with the column it heads. A right-aligned number column under a
 * left-aligned header is the single most common way a data table reads as sloppy.
 *
 * Tabular numerals throughout, so digits occupy the same width in every row and the
 * thousands separators line up into a vertical rule the eye can scan.
 */
.stats-table {
    font-size: 0.92rem;
    margin-bottom: 0;
}

.stats-table > :not(caption) > * > * {
    padding: 0.5rem 0.7rem;
}

/* Clear of the frame at both ends, so the rank and the last figure are not pressed against
   the border. */
.stats-table > :not(caption) > * > *:first-child {
    padding-left: 0.9rem;
}

.stats-table > :not(caption) > * > *:last-child {
    padding-right: 0.9rem;
}

/* Not sticky, deliberately, after two attempts at making it so.
 *
 * The table sits in .table-responsive, which is overflow-x: auto. An overflow ancestor
 * becomes the containing block for position: sticky, so a sticky header inside one sticks
 * to that box rather than to the viewport, and a top offset then pushes it down *into* its
 * own rows: empty space above the header, first row hidden behind it. That is what it was
 * doing, and the offset fix made it worse by making the push exact.
 *
 * The ways out are to drop the responsive wrapper, which hands narrow screens a
 * horizontally scrolling page, or to drop the sticky header. The header is a convenience;
 * the wrapper stops the page breaking on a phone. The header loses.
 */
.stats-table thead th {
    font-size: 0.68rem;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    font-weight: 600;
    color: var(--bs-secondary-color);
    border-top: 0;
    border-bottom: 1px solid var(--bs-border-color);
    white-space: nowrap;
}

/* The same box the tile blocks sit in, so a table and a row of tiles read as the same kind
   of object rather than one being framed and the other floating on the page.
 *
 * The radius clips the header's corners without overflow: hidden, which would kill the
   horizontal scrolling this wrapper exists for in the first place. */
.stats-table-wrap {
    border: 1px solid var(--bs-border-color);
    border-radius: 0.5rem;
}

/* The header sits against the top edge, so its own bottom rule is the only line it needs;
   the wrapper draws the rest. */
.stats-table-wrap .stats-table > thead > tr > th:first-child {
    border-top-left-radius: 0.5rem;
}

.stats-table-wrap .stats-table > thead > tr > th:last-child {
    border-top-right-radius: 0.5rem;
}

/* ── Sortable headers ─────────────────────────────────────────────────────────
 * No marker at rest. A caret on all seven headers at once was clutter that said the same
 * thing seven times, and the pointer already changes over a sortable header. Only the
 * column actually being sorted carries one, which makes it state rather than decoration.
 *
 * The caret is a Bootstrap icon element set by script, not CSS content: it is then the same
 * icon set as the rest of the site, and it cannot be mangled by an escape sequence on its
 * way into this file, which is exactly what happened to the arrows it replaced.
 */
.stats-sortable {
    cursor: pointer;
    user-select: none;
    white-space: nowrap;
}

.stats-sortable:hover,
.stats-sortable:focus-visible {
    color: var(--bs-body-color);
}

.stats-sortable:focus-visible {
    outline: 2px solid var(--bs-primary);
    outline-offset: -2px;
}

/* Reserves the caret's width whether or not one is showing, so a header does not shift
   sideways the moment it becomes the sorted column. */
.stats-sort-mark {
    display: inline-block;
    width: 0.85rem;
    margin-left: 0.15rem;
    text-align: center;
}

.stats-sort-mark .bi {
    font-size: 0.7rem;
    vertical-align: baseline;
    color: var(--bs-primary);
}

.stats-sort-active {
    color: var(--bs-body-color);
}

/* Hairlines, not Bootstrap's default row borders. At a hundred rows the default reads as a
   grid of boxes; a faint rule just separates. */
.stats-table tbody td {
    border-top: 0;
    border-bottom: 1px solid color-mix(in srgb, var(--bs-border-color) 55%, transparent);
    vertical-align: middle;
}

.stats-table tbody tr:last-child td {
    border-bottom: 0;
}

/* No zebra striping. Stripes plus a hover highlight plus a sparkline is three things
   competing for one row.
 *
 * Bootstrap's .table-hover paints its hover through --bs-table-bg-state on each cell, which
 * layers over a background set on the row and left the proportional bar looking like it had
 * two different tints. The table drops .table-hover and states its own hover on the cells,
 * so there is exactly one hover background per row. */
.stats-table tbody tr:hover > td {
    background-color: var(--bs-secondary-bg);
}

/* The thumbnail cell keeps its black letterbox on hover rather than taking the row tint,
   which would put a grey frame around the image. */
.stats-table tbody tr:hover > td.stats-thumb-cell {
    background-color: transparent;
}

.stats-rank {
    width: 3.6rem;
    text-align: right;
    font-variant-numeric: tabular-nums;
    color: var(--bs-secondary-color);
    font-size: 0.85rem;
}

/* The top three rows carry a little more weight, which is the cheapest way to give a ranked
   table a shape you can see from across the room.
 *
 * nth-child, so this follows the current order rather than the rank: after a sort by players
 * it emphasises the top three by players, which is the top of what is actually being read.
 * The rank number in those cells is still whatever the row earned. */
.stats-table tbody tr:nth-child(-n+3) .stats-rank {
    color: var(--bs-body-color);
    font-weight: 600;
}

.stats-name {
    max-width: 0;
    width: 40%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.stats-name a {
    color: var(--bs-body-color);
    text-decoration: none;
}

.stats-name a:hover {
    color: var(--bs-primary);
    text-decoration: underline;
    text-underline-offset: 0.2em;
}

/* Our own plugins, the one place gold marks a row rather than a control. */
.stats-name a.is-ours {
    color: var(--bs-primary);
    font-weight: 600;
}

/* The measure the table is ranked by, with a proportional bar behind it.
 *
 * The bar is what turns a column of numbers into a shape. It is drawn behind the figure and
 * right-aligned so it grows from the number outwards, which keeps the digits themselves on
 * a clean right edge rather than riding on top of a moving left edge. */
.stats-figure {
    position: relative;
    text-align: right;
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    white-space: nowrap;
    min-width: 5.5rem;
}

.stats-bar {
    position: absolute;
    right: 0.6rem;
    top: 50%;
    transform: translateY(-50%);
    height: 1.35rem;
    border-radius: 0.2rem;
    background: rgba(var(--bs-primary-rgb), 0.16);
    pointer-events: none;
}

[data-bs-theme="dark"] .stats-bar {
    background: rgba(var(--bs-primary-rgb), 0.20);
}

.stats-figure > span:last-child {
    position: relative;
}

.stats-figure-soft {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    color: var(--bs-secondary-color);
}

/* Workshop previews, the same way the server page's mod list shows them.
 *
 * They come in every shape: tall, panoramic, and often smaller than the box. A square box
 * with object-fit: cover, which is what this used, lopped the top off portrait covers and
 * the sides off panoramic ones. The box is a fixed 16:9 instead and the image is fitted
 * inside it against black, the way Steam letterboxes its own, so every row presents the
 * same rectangle.
 *
 * Its cell carries no padding and the box runs the full row height, because padding around
 * a 16:9 image only shrinks the image.
 */
.stats-thumb-cell {
    width: 64px;
    padding: 0 !important;
}

.stats-thumb-box {
    width: 64px;
    height: 36px;
    overflow: hidden;
    background-color: #000;
    border-radius: 0.2rem;
    display: block;
}

/* When it is a link out, it should look like one on approach. */
a.stats-thumb-box {
    position: relative;
    outline-offset: 2px;
}

a.stats-thumb-box img {
    transition: transform 0.15s ease, opacity 0.15s ease;
}

a.stats-thumb-box:hover img,
a.stats-thumb-box:focus-visible img {
    transform: scale(1.06);
    opacity: 0.85;
}

@media (prefers-reduced-motion: reduce) {
    a.stats-thumb-box img {
        transition: none;
    }

    a.stats-thumb-box:hover img,
    a.stats-thumb-box:focus-visible img {
        transform: none;
    }
}

.stats-thumb-box img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
}

/* Fitted by default so nothing is cropped, but a preview already within a few percent of
   16:9 gains only hairline bars down its sides, which read as a rendering fault rather than
   a deliberate letterbox. Those are filled instead; the crop is a pixel or two. Applied by
   script, since CSS cannot branch on an image's own aspect ratio. */
.stats-thumb-box img.thumb-fill {
    object-fit: cover;
}

.stats-thumb-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    color: var(--bs-secondary-color);
    opacity: 0.45;
    font-size: 0.9rem;
}

/* Flags are 4:3 artwork, so a square box would letterbox them. A hairline border keeps a
   mostly-white flag from dissolving into a light background. */
.stats-flag {
    width: 1.4rem;
    height: 1.05rem;
    object-fit: cover;
    border-radius: 0.15rem;
    margin-right: 0.55rem;
    vertical-align: middle;
    border: 1px solid var(--bs-border-color);
}

/* ── Movement ──────────────────────────────────────────────────────────────── */
.stats-change {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    width: 4.5rem;
}

.stats-up {
    color: var(--stat-up);
}

.stats-down {
    color: var(--stat-down);
}

.stats-badge-new {
    background: rgba(var(--bs-primary-rgb), 0.15);
    color: var(--bs-primary);
    font-weight: 600;
    font-size: 0.7rem;
}

/* Deliberately quiet. There can be a hundred of these on one page, and at full strength
   they read as a wall of scribble rather than one figure per row. */
.stats-spark-col {
    width: 5.5rem;
}

.stats-spark {
    width: 5rem;
    height: 1.2rem;
    display: block;
    color: var(--bs-secondary-color);
    opacity: 0.75;
}

/* ── Share bar ─────────────────────────────────────────────────────────────────
 * One 100% stacked bar, used for every composition figure in the tool: game mode,
 * perspective, framework, country share, map share. It replaced a doughnut chart whose
 * slice colours were hashed from the label text, which meant they repeated, meant nothing,
 * and were never checked against the dark ground.
 */
.share-bar {
    display: flex;
    height: 1.6rem;
    border-radius: 0.3rem;
    overflow: hidden;
    background: var(--bs-secondary-bg);
}

.share-seg {
    height: 100%;
    min-width: 2px;
}

.share-seg-1 { background: #c8a415; }
.share-seg-2 { background: #4c7fa8; }
.share-seg-3 { background: #6a9a5b; }
.share-seg-4 { background: #a8694c; }
.share-seg-5 { background: #7d6a9a; }
.share-seg-6 { background: #8a8f95; }

[data-bs-theme="dark"] .share-seg-1 { background: #e4b607; }
[data-bs-theme="dark"] .share-seg-2 { background: #6fa8d0; }
[data-bs-theme="dark"] .share-seg-3 { background: #8fbf7f; }
[data-bs-theme="dark"] .share-seg-4 { background: #d08f70; }
[data-bs-theme="dark"] .share-seg-5 { background: #a596c4; }
[data-bs-theme="dark"] .share-seg-6 { background: #a9aeb4; }

.share-key {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem 1rem;
    margin-top: 0.5rem;
    font-size: 0.82rem;
}

.share-key-item {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    color: var(--bs-secondary-color);
    text-decoration: none;
}

.share-key-item:hover {
    color: var(--bs-body-color);
}

.share-key-dot {
    width: 0.7rem;
    height: 0.7rem;
    border-radius: 0.15rem;
    flex: 0 0 auto;
}

.share-key-item strong {
    color: var(--bs-body-color);
    font-variant-numeric: tabular-nums;
}

/* ── Range selector ────────────────────────────────────────────────────────────
 * Pills, because in this codebase pills already mean "filter" and underlines mean
 * "section". Keeping those two languages separate is what lets a range control sit inside
 * a page without competing with the section strip above it.
 *
 * A range with no data behind it is disabled and says why, rather than hidden. A greyed
 * button that re-enables itself as history accrues reads as a promise; a missing one reads
 * as a feature nobody built.
 */
.stats-range .btn {
    --bs-btn-padding-y: 0.15rem;
    --bs-btn-padding-x: 0.5rem;
    --bs-btn-font-size: 0.78rem;
}

.stats-range .btn:disabled {
    opacity: 0.4;
}

/* The page's own setting rather than one of its sections, so it gets a quiet bar instead
   of a heading and a rule. It used to be announced as "Player history" directly above a
   chart announced as "Players over time", which was two headings for one thing. */
.stats-range-bar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-bottom: 1rem;
}

.stats-range-bar .note {
    font-size: 0.85rem;
    color: var(--bs-secondary-color);
}

/* ── Charts ────────────────────────────────────────────────────────────────────
 * In a plain section, not a card. A card here is a border plus 1.5rem of padding around
 * content that already occupies its own column.
 */
.stats-chart {
    position: relative;
    height: 320px;
}

.stats-chart-sm {
    position: relative;
    height: 220px;
}

/* ── Provenance ────────────────────────────────────────────────────────────────
 * The cheapest credibility feature a statistics tool can have: every series' start date,
 * stated once per page. It also converts every absence on the page into a stated fact.
 */
.stats-provenance {
    font-size: 0.82rem;
    color: var(--bs-secondary-color);
    border-top: 1px solid var(--bs-border-color);
    padding-top: 0.75rem;
    margin-top: 2rem;
}

.stats-tracked-since {
    font-size: 0.78rem;
    color: var(--bs-secondary-color);
}

/* ── Overview teaser blocks ────────────────────────────────────────────────── */
.stats-teaser .list-group-item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.45rem 1rem;
    font-size: 0.92rem;
}

.stats-teaser .teaser-rank {
    width: 1.2rem;
    text-align: right;
    color: var(--bs-secondary-color);
    font-variant-numeric: tabular-nums;
    font-size: 0.85rem;
}

.stats-teaser .teaser-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.stats-teaser .teaser-figure {
    margin-left: auto;
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    white-space: nowrap;
}


/* ── Teaser lists on the overview ─────────────────────────────────────────────
 * Rows in a card rather than a table: five of them do not need column headings, and a
 * heading row above five rows is more furniture than content.
 */
.stats-teaser .list-group-item:hover .teaser-name {
    color: var(--bs-primary);
}

.stats-teaser .teaser-name {
    color: var(--bs-body-color);
}

/* Cards across a row end level whatever their contents, so four teasers in a 2x2 grid do
   not step up and down. */
.stats-teaser-card {
    display: flex;
    flex-direction: column;
    height: 100%;
}

.stats-teaser-card .list-group {
    flex: 1 1 auto;
}

/* ── Responsive ───────────────────────────────────────────────────────────────
 * The sticky table header offsets by the tab strip's height on wide screens. On a phone
 * the strip scrolls sideways and the offset stops being right, so the header sticks to the
 * top of the viewport instead.
 */
@media (max-width: 767.98px) {
    .stats-table thead th {
        top: 0;
    }

    .stat-tile .value {
        font-size: 1.3rem;
    }

    .stats-head h1 {
        font-size: 1.35rem;
    }
}


/* The teaser rows on the overview. list-group-item-action already paints its own hover, so
   this only adds the colour change on the name and must not set a second background. */
.stats-teaser .list-group-item-action:hover,
.stats-teaser .list-group-item-action:focus {
    background-color: var(--bs-secondary-bg);
}

/* Bootstrap's .list-group-item-action sets a colour on :hover that beat the name's own, so
   the name stayed body-coloured while everything else said the row was interactive. */
.stats-teaser .list-group-item-action:hover .teaser-name,
.stats-teaser .list-group-item-action:focus .teaser-name {
    color: var(--bs-primary);
}

.stats-teaser .list-group-item-action .stats-thumb-box {
    flex: 0 0 auto;
}


/* Anything scrolled to inside the tool clears both sticky bars, rather than arriving
   underneath them. */
.stats-section,
.stats-table tbody tr {
    scroll-margin-top: calc(var(--stats-sticky-top, 2.7rem) + 2.5rem);
}
