/* Flowten Admin - dark design system.
   One stylesheet for the whole site; components are flat, class-based, no framework.
   Palette extends the original inline theme (see the frozen contract tokens). */

:root {
    color-scheme: dark;

    /* Surfaces */
    --bg: #15171c;
    --panel: #1d2026;
    --panel-2: #22262e;
    --border: #2b2f37;

    /* Text */
    --text: #e6e8ec;
    --muted: #9aa3b2;

    /* Status / accent */
    --accent: #7aa2ff;
    --ok: #5fd68b;
    --warn: #f0c05a;
    --err: #ff8a8a;

    /* Derived surfaces (slightly lifted / inset variants of the base panels) */
    --input-bg: #11131a;
    --hover: #262b34;
    --accent-soft: rgba(122, 162, 255, .14);

    /* Shape + depth */
    --radius: 12px;
    --radius-sm: 8px;
    --shadow: 0 1px 2px rgba(0, 0, 0, .3), 0 8px 24px rgba(0, 0, 0, .22);
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, .35);

    --nav-h: 56px;
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
    margin: 0;
    font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    background: var(--bg);
    color: var(--text);
    font-size: 15px;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

/* ------------------------------------------------------------------ *
 *  Top navigation
 * ------------------------------------------------------------------ */
/* Wraps at EVERY width, not just under a breakpoint: a fixed-height non-wrapping row has a dead zone
   (roughly 760-900px) where the 6 links + username + button no longer fit, and flex resolves that by
   squeezing the username until it breaks over several lines while the page grows a sideways scrollbar.
   Wrapping to a second row instead keeps every item whole. On a wide screen everything still fits on
   one line, so min-height keeps the bar exactly as tall as it was. */
.topnav {
    position: sticky;
    top: 0;
    z-index: 50;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: .5rem 1.5rem;
    min-height: var(--nav-h);
    padding: .35rem 1.25rem;
    background: rgba(29, 32, 38, .88);
    backdrop-filter: saturate(140%) blur(10px);
    -webkit-backdrop-filter: saturate(140%) blur(10px);
    border-bottom: 1px solid var(--border);
}

.topnav .brand {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    font-weight: 700;
    font-size: 1.02rem;
    letter-spacing: .01em;
    color: var(--text);
}
.topnav .brand .dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}

.topnav .links {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: .25rem;
}
.topnav .links a {
    color: var(--muted);
    padding: .4rem .7rem;
    border-radius: var(--radius-sm);
    font-weight: 500;
    font-size: .92rem;
    line-height: 1;
    transition: background .12s ease, color .12s ease;
}
.topnav .links a:hover { color: var(--text); background: var(--hover); text-decoration: none; }
.topnav .links a.active { color: var(--accent); background: var(--accent-soft); }

.topnav .spacer { margin-left: auto; }

.topnav .who {
    color: var(--muted);
    font-size: .88rem;
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    white-space: nowrap; /* an account name is an identifier - it never breaks across lines */
    flex: none;          /* and flex may not shrink it into wrapping */
}
.topnav .who::before {
    content: "";
    width: 7px; height: 7px;
    border-radius: 50%;
    background: var(--ok);
}
.topnav .nav-right { display: flex; align-items: center; gap: 1rem; flex: none; }
.topnav form { margin: 0; }

/* ------------------------------------------------------------------ *
 *  Layout
 * ------------------------------------------------------------------ */
/* Wide by design: the panel shows long single-line values (build strings, console prompts, the users
   table's action cluster) that must never wrap, so the page gets all the width the screen offers before
   anything falls back to a scrollbar. The cap only stops line lengths going silly on an ultrawide. */
main {
    max-width: 1720px;
    margin: 1.75rem auto 3rem;
    padding: 0 1.25rem;
}

h1 {
    font-size: 1.5rem;
    font-weight: 650;
    letter-spacing: -.01em;
    margin: 0 0 1.25rem;
}
h2 {
    font-size: .82rem;
    font-weight: 650;
    text-transform: uppercase;
    letter-spacing: .07em;
    color: var(--muted);
    margin: 2rem 0 .85rem;
}
h2:first-of-type { margin-top: .5rem; }

.page-head {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 1rem;
    margin-bottom: 1.25rem;
}
.page-head h1 { margin: 0; }
.page-head .head-right { margin-left: auto; display: flex; align-items: center; gap: .85rem; }
.updated { color: var(--muted); font-size: .82rem; font-variant-numeric: tabular-nums; white-space: nowrap; }

.muted { color: var(--muted); }
.err { color: var(--err); }
.flash { color: var(--ok); }

.banner {
    padding: .7rem .9rem;
    border-radius: var(--radius-sm);
    font-size: .9rem;
    margin: 0 0 1rem;
    border: 1px solid var(--border);
}
.banner.err { background: rgba(255, 138, 138, .08); border-color: rgba(255, 138, 138, .35); color: var(--err); }
.banner.ok { background: rgba(95, 214, 139, .08); border-color: rgba(95, 214, 139, .32); color: var(--ok); }

/* ------------------------------------------------------------------ *
 *  Cards + responsive grid
 * ------------------------------------------------------------------ */
.cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 1rem;
}

.card {
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    padding: 1.1rem 1.15rem;
}
.card > h3 {
    margin: 0 0 .85rem;
    font-size: .82rem;
    font-weight: 650;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--muted);
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: .6rem;
}
.card > h3 .pill { text-transform: none; letter-spacing: 0; }
.card.span-2 { grid-column: span 2; }
.card.pad-0 { padding: 0; }

/* ------------------------------------------------------------------ *
 *  Stat cell (label / big value / sub)
 * ------------------------------------------------------------------ */
.stat { position: relative; display: flex; flex-direction: column; gap: .3rem; }
/* A long status pill (e.g. "offline - no heartbeat") drops under the label instead of overflowing the card. */
.stat .stat-top { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: .5rem; }
.stat .label {
    font-size: .78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--muted);
}
.stat .value {
    font-size: 1.85rem;
    font-weight: 640;
    letter-spacing: -.02em;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.stat .sub { font-size: .82rem; color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
/* Sparkline: Chart.js (responsive + maintainAspectRatio:false) needs a fixed-height, positioned
   parent it can measure — a bare canvas in the flex column self-feeds its own resize (endless growth). */
.stat .spark-box { position: relative; height: 40px; margin-top: .55rem; }
.stat .spark-box canvas { width: 100% !important; }

/* key/value rows inside a card (gameserver, meta panels).
   Values like "v1.4.2 #128 (7a3f2c1)" or a UTC timestamp must stay on ONE line, so the dd is a
   nowrap scroll container. A dd that actually shows its scrollbar is ~15px taller than a plain one
   (22px -> 37px), which makes the row alignment mode load-bearing. Measured in Chrome on the real
   dashboard markup, label-vs-value top offset on an overflowing row: center 8.5px (a visibly ragged
   label column on exactly the rows that overflow), baseline 1.0px, start 0px. Hence `start` - it
   pins both boxes to the same top edge, so the scrollbar can only add height below and can never
   shift the label. Don't "restore" center. */
.kv { display: grid; grid-template-columns: auto 1fr; gap: .4rem .9rem; align-items: start; }
.kv dt { color: var(--muted); font-size: .84rem; white-space: nowrap; }
.kv dd {
    margin: 0;
    text-align: right;
    font-variant-numeric: tabular-nums;
    font-size: .92rem;
    white-space: nowrap;
    min-width: 0;
    overflow-x: auto;
}
.kv dd.strong { font-weight: 600; }

/* horizontal pill strip (pings) */
.pill-row { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; }
.pill-row .pk { color: var(--muted); font-size: .84rem; margin-right: .1rem; }

/* ------------------------------------------------------------------ *
 *  Pills / status badges
 * ------------------------------------------------------------------ */
.pill {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .22rem .55rem;
    border-radius: 999px;
    font-size: .76rem;
    font-weight: 600;
    line-height: 1;
    border: 1px solid transparent;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
.pill::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex: none; }
.pill.no-dot::before { display: none; }
.pill.ok { color: var(--ok); background: rgba(95, 214, 139, .12); border-color: rgba(95, 214, 139, .25); }
.pill.warn { color: var(--warn); background: rgba(240, 192, 90, .12); border-color: rgba(240, 192, 90, .25); }
.pill.err { color: var(--err); background: rgba(255, 138, 138, .12); border-color: rgba(255, 138, 138, .25); }
.pill.muted { color: var(--muted); background: rgba(154, 163, 178, .1); border-color: rgba(154, 163, 178, .22); }
.pill.accent { color: var(--accent); background: var(--accent-soft); border-color: rgba(122, 162, 255, .28); }

/* ------------------------------------------------------------------ *
 *  Buttons
 * ------------------------------------------------------------------ */
button, .btn {
    background: var(--panel-2);
    border: 1px solid var(--border);
    color: var(--text);
    border-radius: var(--radius-sm);
    padding: .45rem .8rem;
    font: inherit;
    font-size: .88rem;
    font-weight: 500;
    cursor: pointer;
    line-height: 1.2;
    transition: background .12s ease, border-color .12s ease;
}
button:hover, .btn:hover { background: var(--hover); border-color: #3a4150; }
button:active, .btn:active { transform: translateY(1px); }
button:focus-visible, .btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

button.primary, .btn.primary {
    background: var(--accent-soft);
    border-color: rgba(122, 162, 255, .4);
    color: #cfe0ff;
}
button.primary:hover, .btn.primary:hover { background: rgba(122, 162, 255, .22); }

button.danger, .btn.danger {
    background: rgba(255, 138, 138, .1);
    border-color: rgba(255, 138, 138, .3);
    color: var(--err);
}
button.danger:hover, .btn.danger:hover { background: rgba(255, 138, 138, .18); border-color: rgba(255, 138, 138, .5); }

/* ------------------------------------------------------------------ *
 *  Inputs / selects
 * ------------------------------------------------------------------ */
input, select, textarea {
    background: var(--input-bg);
    border: 1px solid var(--border);
    color: var(--text);
    border-radius: var(--radius-sm);
    padding: .45rem .6rem;
    font: inherit;
    font-size: .9rem;
}
input::placeholder { color: #656d7c; }
input:focus, select:focus, textarea:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}
input[type=checkbox] { width: 1rem; height: 1rem; accent-color: var(--accent); vertical-align: -2px; }
label { font-size: .9rem; }

form.row {
    display: flex;
    flex-wrap: wrap;
    gap: .6rem;
    align-items: center;
}

/* ------------------------------------------------------------------ *
 *  Tables (wrapped in cards)
 * ------------------------------------------------------------------ */
.table-wrap { overflow-x: auto; border-radius: var(--radius); }
table { width: 100%; border-collapse: collapse; }
th, td {
    text-align: left;
    padding: .6rem .8rem;
    border-bottom: 1px solid var(--border);
    font-size: .9rem;
    vertical-align: middle;
    white-space: nowrap;
}
thead th {
    color: var(--muted);
    font-weight: 600;
    font-size: .76rem;
    text-transform: uppercase;
    letter-spacing: .04em;
    background: var(--panel-2);
    position: sticky;
    top: 0;
}
tbody tr { transition: background .1s ease; }
tbody tr:hover { background: var(--hover); }
tbody tr:last-child td { border-bottom: none; }
td.num { text-align: right; font-variant-numeric: tabular-nums; }

/* Users / Whitelist: the per-row cluster of small inline action forms. The flex layout sits on an INNER
   .cluster wrapper, not on the td: a display:flex td stops being a table cell, so its row border no longer
   spans it and vertical-align: middle has nothing to act on - visible the moment another cell in the row
   (the loadout grid) is taller than the buttons. The cluster may FOLD onto extra lines when the table is
   squeezed: on a wide screen it is one line, on a narrower one the row simply grows - the users table never
   pushes a sideways scrollbar for it. Every form stays whole (inline-flex), so a fold happens between forms. */
td.actions .cluster { display: flex; flex-wrap: wrap; gap: .4rem; align-items: center; }
td.actions form { display: inline-flex; gap: .3rem; align-items: center; margin: 0; }
td.actions input[type=password] { width: 175px; } /* fits the "(12+)" placeholder without clipping it */

/* ------------------------------------------------------------------ *
 *  Upgrade loadout (users table) - the shop's icon grid per account
 * ------------------------------------------------------------------ */
/* One chip per catalog entry, laid out by _UpgradeLoadout.cshtml: row 1 the stat tracks (icon + rank, a
   progress underline, green at the cap), row 2 the signatures (icon + tick when owned). Unowned entries stay
   IN PLACE, ghosted, so every account's grid has the same shape and two rows compare at a glance. The grid
   is fixed-size by construction (chips never shrink or wrap), which is what lets the auto table layout leave
   it alone and take the slack out of the action cluster instead. The icons are the game's own 32px pixel art
   scaled by the browser (no `pixelated`: 32 -> 20 is not an integer ratio and nearest-neighbour would drop
   pixel rows), and the full name + blurb rides the title tooltip, so a chip need not be recognized on sight. */
.loadout {
    --chip-w: 40px;
    --chip-h: 24px;
    --chip-icon: 20px;
    --chip-gap: 4px;
    display: flex;
    align-items: center;
    gap: .75rem;
}
.loadout .rows { display: grid; gap: var(--chip-gap); }
.loadout .row { display: flex; gap: var(--chip-gap); }
.loadout .chip {
    position: relative;
    display: grid;
    grid-template-columns: 24px 1fr;
    align-items: center;
    width: var(--chip-w);
    height: var(--chip-h);
    flex: none;
    border-radius: 6px;
    background: var(--input-bg);
    border: 1px solid var(--border);
    overflow: hidden;
}
.loadout .chip img { width: var(--chip-icon); height: var(--chip-icon); display: block; margin: 0 auto; }
.loadout .chip .rank,
.loadout .chip .tick {
    font-size: .68rem;
    font-weight: 700;
    line-height: 1;
    padding-right: 4px;
    text-align: right;
    color: var(--text);
    font-variant-numeric: tabular-nums;
}
.loadout .chip .tick { color: var(--accent); font-size: .72rem; }
.loadout .chip.off { opacity: .3; filter: grayscale(1); }
.loadout .chip.sig.on { border-color: rgba(122, 162, 255, .5); background: rgba(122, 162, 255, .09); }
.loadout .chip.max { border-color: rgba(95, 214, 139, .4); }
.loadout .chip.max .rank { color: var(--ok); }
/* rank progress: a 2px underline along the chip's bottom edge, --p = rank/max as a percentage */
.loadout .chip .fill { position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: rgba(255, 255, 255, .06); }
.loadout .chip .fill i { display: block; height: 100%; width: var(--p, 0%); background: var(--accent); }
.loadout .chip.max .fill i { background: var(--ok); }
/* the point balance beside the grid: spent over available, plus any unknown-id pills */
.loadout .sum {
    display: grid;
    gap: .1rem;
    color: var(--muted);
    font-size: .8rem;
    line-height: 1.25;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.loadout .sum b { color: var(--text); font-weight: 600; }

.empty { color: var(--muted); font-size: .9rem; padding: .5rem .2rem; }

/* ------------------------------------------------------------------ *
 *  Charts
 * ------------------------------------------------------------------ */
.chart-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem;
}
.chart-card {
    position: relative;
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    padding: 1rem 1.1rem 1.1rem;
    min-width: 0;
}
.chart-card h3 {
    margin: 0 0 .75rem;
    font-size: .88rem;
    font-weight: 600;
    color: var(--text);
    display: flex;
    align-items: baseline;
    gap: .5rem;
}
.chart-card h3 .unit { color: var(--muted); font-weight: 500; font-size: .78rem; }
.chart-card .canvas-box { position: relative; height: 220px; }
.chart-card canvas { width: 100% !important; }

/* empty-chart overlay */
.nodata-msg {
    display: none;
    position: absolute;
    inset: 2.6rem .5rem .5rem;
    align-items: center;
    justify-content: center;
    color: var(--muted);
    font-size: .85rem;
    letter-spacing: .02em;
    background: repeating-linear-gradient(45deg, transparent, transparent 9px, rgba(255, 255, 255, .015) 9px, rgba(255, 255, 255, .015) 18px);
    border-radius: var(--radius-sm);
    pointer-events: none;
}
.chart-card.nodata .nodata-msg { display: flex; }
.chart-card.nodata canvas { opacity: .12; }

/* ------------------------------------------------------------------ *
 *  Segmented range picker
 * ------------------------------------------------------------------ */
.seg {
    display: inline-flex;
    padding: 3px;
    gap: 2px;
    background: var(--panel-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
}
.seg button {
    background: transparent;
    border: none;
    color: var(--muted);
    padding: .32rem .7rem;
    font-size: .84rem;
    font-weight: 600;
    border-radius: 6px;
    line-height: 1;
}
.seg button:hover { background: var(--hover); color: var(--text); }
.seg button.active { background: var(--accent-soft); color: var(--accent); }
.seg button.active:hover { background: var(--accent-soft); }

/* ------------------------------------------------------------------ *
 *  Login
 * ------------------------------------------------------------------ */
.login-wrap {
    min-height: calc(100vh - var(--nav-h) - 5rem);
    display: flex;
    align-items: center;
    justify-content: center;
}
.login-card {
    width: 100%;
    max-width: 340px;
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 1.75rem;
}
.login-card h1 { text-align: center; margin-bottom: .35rem; }
.login-card .lead { text-align: center; color: var(--muted); font-size: .88rem; margin: 0 0 1.4rem; }
.login-card form { display: grid; gap: 1rem; }
.login-card label { display: grid; gap: .35rem; font-size: .82rem; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
.login-card input { width: 100%; }
.login-card button { width: 100%; padding: .6rem; margin-top: .25rem; }

/* ------------------------------------------------------------------ *
 *  Utilities
 * ------------------------------------------------------------------ */
.stack { display: grid; gap: 1rem; }
/* Inline code/identifier runs (paths, hashes, timestamps): never split a token across two lines.
   Surrounding prose still wraps normally - only the token itself is glued together. */
.mono { font-variant-numeric: tabular-nums; white-space: nowrap; }
.nowrap { white-space: nowrap; }

/* A long one-line value that must stay readable and copyable in full (TOTP secret, otpauth URI):
   one line, its own scrollbar, click-to-select-all. */
.code-line {
    display: block;
    white-space: nowrap;
    overflow-x: auto;
    user-select: all;
    -webkit-user-select: all;
    padding-bottom: .15rem;
}

/* Console log/output block. `pre` (not pre-wrap) so the ONLY line breaks shown are the ones the
   output actually contains - nothing is re-wrapped or broken mid-token; over-long lines scroll.
   Selector is `pre.pre-log` so it outranks `.mono`'s nowrap regardless of source order. */
pre.pre-log {
    margin: .5rem 0 0;
    white-space: pre;
    overflow: auto;
    max-height: 32rem;
    background: rgba(0, 0, 0, .18);
    padding: .75rem;
    border-radius: 6px;
}
pre.pre-log.compact { max-height: 8rem; }

/* ------------------------------------------------------------------ *
 *  Responsive
 * ------------------------------------------------------------------ */
@media (max-width: 760px) {
    .chart-grid { grid-template-columns: 1fr; }
    .card.span-2 { grid-column: auto; }
    main { margin-top: 1.25rem; padding: 0 1rem; }
    /* Wrapping itself is handled by the base .topnav rule at every width; here we only tighten the
       spacing and drop the brand wordmark to buy back room on a phone. */
    .topnav { gap: .5rem 1rem; padding: .5rem 1rem; }
    .topnav .brand span.full { display: none; }
    .page-head .head-right { margin-left: 0; width: 100%; }
}
