/* chillrust.org - shared site styling.
 *
 * Single source of truth for the Slate Glass palette + base reset + the
 * brand wordmark lockup. Loaded by every page on the site.
 *
 * Palette: cool slate base with a cyan accent. Metallic gold/silver/bronze
 * are independent of the accent and live in --rank-* variables so tier
 * badges always read as real medals, not as palette accent.
 *
 * Historical note: --gold and --sky are NOT actually gold/sky anymore;
 * the names are preserved from the previous warm-sunset palette so all
 * existing page CSS that uses var(--gold) inherits the new accent
 * without per-page edits. Treat --gold as "primary accent" and --sky as
 * "secondary accent", even though both now resolve to cyan tones.
 */

:root {
  color-scheme: dark;

  --bg:            #0a1118;   /* deep slate body */
  --bg-glow:       #15212e;   /* radial cyan glow under cards */
  --panel:         #161d26;   /* slate panel surface */
  --panel-inset:   #10151c;   /* darker inset / header strip */
  --text:          #e8eef5;   /* slate cream, primary copy */
  --muted:         #7a8694;   /* taupe-slate, secondary copy */
  --gold:          #7dd3fc;   /* PRIMARY ACCENT (cyan; name preserved) */
  --gold-deep:     #0ea5e9;   /* accent hover / button border */
  --sky:           #7dd3fc;   /* SECONDARY ACCENT (same cyan; name preserved) */
  --border:        #1f2933;   /* subtle slate borders */
  --border-bright: #2d3a48;   /* slightly brighter for input borders */
  --err:           #f87171;   /* error red */

  /* Independent metallic tier colors for ranks + medal pills. These
     stay constant even if the accent palette shifts. */
  --rank-gold:     #ffcc4d;
  --rank-silver:   #c0c0c0;
  --rank-bronze:   #cd7f32;

  /* Facepunch oxide-red for the Rust logo glow halo. */
  --rust-red:      #c93b22;
}

/* ─── Heat server focus (red glass). Overrides the cyan :root accent. The
   structure/spacing is identical; only palette vars change, so every page
   inherits the theme with no per-page edits. ──────────────────────────────── */
[data-server="heat"] {
  --bg:            #0a0708;
  --bg-glow:       #1b0e0f;   /* subtle warm wash */
  --panel:         #1a1213;
  --panel-inset:   #120c0d;
  --text:          #f3ebe9;
  --muted:         #9a8783;
  --gold:          #ff5a4d;   /* PRIMARY ACCENT (ember; name preserved) */
  --gold-deep:     #c93b22;
  --sky:           #ff5a4d;
  --border:        #2a1c1c;
  --border-bright: #3a2826;
  --err:           #fbbf24;   /* amber - kept distinct from the red accent */
  /* --rank-* and --rust-red intentionally inherit from :root (real medals). */
}

/* Explicit main (cyan) palette so a subtree tagged data-server="main" keeps the
   cyan accent even when the page focus (and <html> data-server) is "heat".
   Mirrors :root; needed for the /servers two-card browser where each card shows
   in its own server's color regardless of focus. */
[data-server="main"] {
  --bg:            #0a1118;
  --bg-glow:       #15212e;
  --panel:         #161d26;
  --panel-inset:   #10151c;
  --text:          #e8eef5;
  --muted:         #7a8694;
  --gold:          #7dd3fc;
  --gold-deep:     #0ea5e9;
  --sky:           #7dd3fc;
  --border:        #1f2933;
  --border-bright: #2d3a48;
  --err:           #f87171;
}

/* Heat brand wordmark gradient (parallels the cyan .chill-ph rule). */
[data-server="heat"] .site-nav .brand .chill-ph {
  background: linear-gradient(135deg, #ff8a7d 0%, #ff5a4d 50%, #c93b22 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
  filter: drop-shadow(0 0 8px rgba(255, 90, 77, 0.35));
}

* { box-sizing: border-box; }

body {
  margin: 0;
  min-height: 100vh;
  color: var(--text);
  font: 14px/1.5 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  background: radial-gradient(ellipse at top, var(--bg-glow) 0%, var(--bg) 60%) fixed;
}

a { color: var(--sky); text-decoration: none; }
a:hover { color: var(--gold); }

/* ─── Shared top nav ────────────────────────────────────────────────────── */

.site-nav {
  position: sticky; top: 0; z-index: 50;
  background: rgba(16, 21, 28, 0.85);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--border);
  padding: 0.75rem 1.25rem;
  display: flex; align-items: center; gap: 1.25rem;
  flex-wrap: wrap;
}

/* Site status bar: Server Browser / Live Stats / Wipe Info pills. Injected
   by /nav-status.js into <body> as the last child; position: fixed pins it
   to the bottom of the viewport on every page. Lives outside the nav after
   three iterations of trying to wedge it in there proved the nav is just
   too full (brand + 7 links + discord + avatar) to fit pills cleanly at
   any width without painful trade-offs. Footer dock is always visible,
   never competes with anything else for space. */
.site-status-bar {
  position: fixed; left: 0; right: 0; bottom: 0;
  z-index: 50;
  background: rgba(16, 21, 28, 0.92);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-top: 1px solid var(--border);
  padding: 0.5rem 0.75rem;
  display: flex; justify-content: center; align-items: center;
  gap: 0.4rem; flex-wrap: wrap;
}
/* Pages typically reserve their own bottom padding inside <main>; bump the
   body padding-bottom so the fixed bar never overlaps the page footer or
   the last row of content. */
body { padding-bottom: 3rem; }
.site-status-bar .nav-pill {
  display: inline-flex; align-items: center; gap: 0.4rem;
  padding: 0.28rem 0.7rem; border-radius: 999px;
  background: var(--panel-inset); border: 1px solid var(--border);
  font-size: 0.72rem; color: var(--muted);
  cursor: help; white-space: nowrap;
}
.site-status-bar .nav-pill .dot {
  width: 7px; height: 7px; border-radius: 50%; background: var(--muted);
}
.site-status-bar .nav-pill.is-up      .dot { background: #22c55e; box-shadow: 0 0 6px rgba(34, 197, 94, 0.5); }
.site-status-bar .nav-pill.is-partial .dot { background: #f59e0b; box-shadow: 0 0 6px rgba(245, 158, 11, 0.55); }
.site-status-bar .nav-pill.is-down    .dot { background: #ef4444; box-shadow: 0 0 6px rgba(239, 68, 68, 0.5); }
.site-status-bar .nav-pill.is-up      { color: var(--text); border-color: rgba(34, 197, 94, 0.25); }
.site-status-bar .nav-pill.is-partial { color: var(--text); border-color: rgba(245, 158, 11, 0.35); }
.site-status-bar .nav-pill.is-down    { color: var(--text); border-color: rgba(239, 68, 68, 0.3); }
/* Tighten on small phones so the row doesn't take two lines unless the
   viewport is genuinely tiny. flex-wrap on the bar means even if it does
   need to wrap, it stays readable rather than overflowing. */
@media (max-width: 540px) {
  .site-status-bar { padding: 0.4rem 0.5rem; gap: 0.3rem; }
  .site-status-bar .nav-pill {
    padding: 0.22rem 0.55rem; font-size: 0.68rem;
  }
}

/* Brand wordmark lockup: "Chill Philippines" in cyan gradient + the
   official Facepunch Rust logo image, sized to match cap-height. */
.site-nav .brand {
  display: inline-flex; align-items: center; gap: 0;
  font-weight: 800; font-size: 1.05rem; letter-spacing: 0.02em;
  white-space: nowrap;
  text-decoration: none;
}
.site-nav .brand .chill-ph {
  background: linear-gradient(135deg, #a5e3ff 0%, #7dd3fc 50%, #0ea5e9 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
  filter: drop-shadow(0 0 8px rgba(125, 211, 252, 0.35));
}
.site-nav .brand .rust-logo {
  height: 1em; width: auto; display: block;
  filter: drop-shadow(0 0 8px rgba(206, 65, 43, 0.35));
}

/* ── Server-name wordmark: "Philippines" white; Chill = frost, Heat = flame.
   Used in the nav brand (built by server-focus.js) and the home hero.
   The #cr-fireturb / #cr-frostturb SVG filters are injected once by
   server-focus.js. .brand-wm is a neutral container (no gradient/clip). ── */
.brand-wm { white-space: nowrap; }
.sw-ph { color:#fff; -webkit-text-fill-color:#fff; }

.sw-fire{ position:relative; color:#fff; -webkit-text-fill-color:#fff; white-space:nowrap; z-index:0;
  text-shadow:0 0 5px rgba(255,170,100,.6), 0 -2px 10px rgba(255,100,50,.5);
  animation:sw-fireglow 1.2s ease-in-out infinite alternate; }
@keyframes sw-fireglow{
  from{text-shadow:0 0 5px rgba(255,170,100,.5),0 -2px 9px rgba(255,100,50,.45)}
  to{text-shadow:0 0 8px rgba(255,195,120,.75),0 -3px 14px rgba(255,120,60,.6)}}
/* base at the baseline (bottom:12%), licks up to top:-10%; grows upward */
.sw-fire::before{ content:""; position:absolute; z-index:-1; transform-origin:50% 100%;
  left:-10%; right:-10%; top:-10%; bottom:12%;
  background:
    radial-gradient(40% 120% at 20% 100%, #ffe070 0%, #ff7a1f 36%, rgba(255,50,0,0) 74%),
    radial-gradient(46% 135% at 50% 100%, #fff0a0 0%, #ff5a14 32%, rgba(220,30,0,0) 72%),
    radial-gradient(40% 120% at 80% 100%, #ffe070 0%, #ff6a1f 36%, rgba(255,50,0,0) 74%);
  opacity:.74; filter:url(#cr-fireturb) blur(2.5px);
  animation:sw-firepulse .38s ease-in-out infinite alternate, sw-firerise 2.4s ease-in-out infinite; }
@keyframes sw-firepulse{from{opacity:.6;transform:scaleY(.93)}to{opacity:.82;transform:scaleY(1.1)}}
@keyframes sw-firerise{0%,100%{transform:translateX(0)}50%{transform:translateX(-4%)}}

.sw-frost{ position:relative; color:#fff; -webkit-text-fill-color:#fff; white-space:nowrap;
  animation:sw-frostglow 2.4s ease-in-out infinite alternate; }
@keyframes sw-frostglow{
  from{text-shadow:0 0 4px rgba(195,235,255,.45), 0 0 9px rgba(130,200,255,.28)}
  to{text-shadow:0 0 7px rgba(215,242,255,.7), 0 0 15px rgba(140,210,255,.45)}}
.sw-frost::after{ content:attr(data-word); position:absolute; inset:0; z-index:1; pointer-events:none;
  background:linear-gradient(100deg,transparent 34%,rgba(255,255,255,.98) 50%,transparent 66%);
  -webkit-background-clip:text; background-clip:text; -webkit-text-fill-color:transparent; color:transparent;
  background-size:300% 100%; animation:sw-shimmer 2.6s linear infinite; }
@keyframes sw-shimmer{0%{background-position:180% 0}100%{background-position:-120% 0}}
.sw-frost::before{ content:""; position:absolute; inset:-8% -4%; z-index:-1;
  background:#bfe8ff; opacity:.08; filter:url(#cr-frostturb) blur(.3px);
  -webkit-mask:radial-gradient(62% 72% at 50% 50%,#000 52%,transparent 80%);
  mask:radial-gradient(62% 72% at 50% 50%,#000 52%,transparent 80%); }

/* Respect reduced-motion: keep the colors/glow, drop the animation. */
@media (prefers-reduced-motion: reduce){
  .sw-fire, .sw-fire::before, .sw-frost, .sw-frost::after { animation:none !important; }
}

/* ─── Brand focus-switcher (server-focus.js turns .brand into a dropdown) ──── */
.brand-switch { position: relative; display: inline-flex; align-items: center; }
.brand-switch .caret { margin-left: .35rem; color: var(--gold); font-size: .7rem; }
.brand-switch .brand { cursor: pointer; }
.brand-menu {
  position: absolute; top: calc(100% + .4rem); left: 0; z-index: 60; width: 300px;
  background: var(--panel); border: 1px solid var(--border); border-radius: 12px;
  box-shadow: 0 30px 60px -20px rgba(0,0,0,.8); overflow: hidden; display: none;
}
.brand-menu.open { display: block; }
.brand-menu .head {
  font-size: .62rem; text-transform: uppercase; letter-spacing: .09em;
  color: var(--muted); padding: .6rem .85rem .35rem;
}
.brand-opt {
  display: flex; align-items: center; gap: .7rem; padding: .6rem .85rem;
  cursor: pointer; border-top: 1px solid var(--border); text-decoration: none; color: var(--text);
}
.brand-opt:hover { background: var(--panel-inset); }
.brand-opt .swatch { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
.brand-opt .swatch.main { background: #7dd3fc; box-shadow: 0 0 7px #7dd3fc; }
.brand-opt .swatch.heat { background: #ff5a4d; box-shadow: 0 0 7px #ff5a4d; }
.brand-opt .col { flex: 1; min-width: 0; }
.brand-opt .t { font-weight: 700; font-size: .86rem; }
.brand-opt .s { font-size: .7rem; color: var(--muted); }
.brand-opt .live { font-size: .72rem; color: var(--gold); font-variant-numeric: tabular-nums; }
.brand-opt.cur { background: var(--panel-inset); }

.site-nav .spacer { flex: 1; }
.site-nav .links {
  list-style: none; padding: 0; margin: 0;
  display: flex; gap: 0.25rem; flex-wrap: wrap;
}
.site-nav .links a {
  display: block; padding: 0.4rem 0.75rem;
  color: var(--text); font-size: 0.9rem; font-weight: 500;
  border-radius: 6px;
  transition: background 120ms, color 120ms, box-shadow 120ms;
  text-decoration: none;
}
.site-nav .links a:hover {
  background: rgba(125, 211, 252, 0.08);
  color: var(--gold);
}
.site-nav .links a.is-active {
  background: var(--panel);
  color: var(--gold);
  box-shadow: 0 0 0 1px rgba(125, 211, 252, 0.4),
              0 0 12px -2px rgba(125, 211, 252, 0.25);
}
.site-nav .discord {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px;
  color: var(--text); opacity: 0.7;
  border-radius: 8px;
  text-decoration: none;
  transition: opacity 120ms, background 120ms, color 120ms;
}
.site-nav .discord:hover {
  opacity: 1; color: var(--gold);
  background: rgba(125, 211, 252, 0.08);
}
.site-nav .discord svg { width: 22px; height: 22px; display: block; }

/* Auth state in nav (rendered by /auth.js into <span id="navAuth"></span>). */
.site-nav .nav-me-wrap { position: relative; display: inline-block; }
.site-nav .nav-me {
  display: inline-flex; align-items: center; gap: 0.5rem;
  padding: 0.25rem 0.625rem 0.25rem 0.25rem;
  border-radius: 999px;
  text-decoration: none;
  background: var(--panel-inset);
  border: 1px solid var(--border);
  color: var(--text); font-size: 0.85rem; font-weight: 600;
  max-width: 12rem;
  font-family: inherit;
  cursor: pointer;
  transition: border-color 120ms, background 120ms;
}
.site-nav .nav-me:hover,
.site-nav .nav-me-wrap.is-open .nav-me {
  border-color: var(--gold-deep); background: rgba(125, 211, 252, 0.06);
}
.site-nav .nav-me-caret {
  color: var(--muted); font-size: 0.7rem; margin-left: 0.1rem;
  transition: transform 120ms, color 120ms;
}
.site-nav .nav-me-wrap.is-open .nav-me-caret { transform: rotate(180deg); color: var(--gold); }

.site-nav .nav-me-menu {
  position: absolute; right: 0; top: calc(100% + 0.4rem);
  min-width: 9rem;
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 10px; padding: 0.3rem;
  box-shadow: 0 20px 40px -15px rgba(0,0,0,0.6),
              0 0 0 1px rgba(125, 211, 252, 0.04) inset;
  display: flex; flex-direction: column; gap: 1px;
  z-index: 50;
}
/* `display: flex` above outranks the browser's default `[hidden] { display:
   none }`, so [hidden] is a no-op without this. */
.site-nav .nav-me-menu[hidden] { display: none; }
.site-nav .nav-me-menu a {
  display: block; padding: 0.45rem 0.75rem;
  color: var(--text); text-decoration: none;
  font-size: 0.85rem; font-weight: 500;
  border-radius: 6px;
}
.site-nav .nav-me-menu a:hover {
  background: rgba(125, 211, 252, 0.08); color: var(--gold);
}
.site-nav .nav-me-menu a.signout {
  color: var(--muted);
  border-top: 1px solid var(--border);
  margin-top: 0.2rem; padding-top: 0.55rem;
  border-radius: 0 0 6px 6px;
}
.site-nav .nav-me-section-label {
  font-size: 0.7rem; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.08em; font-weight: 700;
  padding: 0.5rem 0.75rem 0.2rem;
  border-top: 1px solid var(--border); margin-top: 0.2rem;
}
.site-nav .nav-me-admin a { color: var(--sky); }
.site-nav .nav-me-admin a:hover { color: var(--gold); background: rgba(125, 211, 252, 0.08); }
.site-nav .nav-me-menu a.signout:hover { color: var(--err); background: rgba(239, 68, 68, 0.08); }
.site-nav .nav-me-avatar {
  width: 24px; height: 24px; border-radius: 50%;
  object-fit: cover; display: block;
  background: var(--panel);
}
.site-nav .nav-me-avatar-fallback {
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--gold); font-size: 0.75rem;
}
.site-nav .nav-me-name {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  max-width: 8rem;
}
.site-nav .nav-signin {
  display: inline-flex; align-items: center;
  padding: 0.35rem 0.75rem; border-radius: 999px;
  text-decoration: none;
  color: var(--gold); font-size: 0.85rem; font-weight: 600;
  border: 1px solid var(--gold-deep);
  background: rgba(125, 211, 252, 0.06);
  transition: background 120ms;
}
.site-nav .nav-signin:hover { background: rgba(125, 211, 252, 0.12); }

/* Clickable leaderboard rows: entire row jumps to /u/<sid>. Plain affordance
   (cursor + tinted hover background); skip transform to keep the table grid
   from jiggling row-by-row. */
.lb-table tbody tr.lb-row.is-clickable { cursor: pointer; transition: background 80ms; }
.lb-table tbody tr.lb-row.is-clickable:hover { background: rgba(125, 211, 252, 0.04); }

/* Row highlight for "this is you" on leaderboards: the chill cyan glow. */
.lb-table tbody tr.is-me {
  background: rgba(125, 211, 252, 0.08);
  box-shadow: inset 0 0 0 1px rgba(125, 211, 252, 0.4),
              inset 0 0 24px -8px rgba(125, 211, 252, 0.35);
}
.lb-table tbody tr.is-me td { color: var(--text); }
.lb-table tbody tr.is-me td.name { color: var(--gold); font-weight: 700; }

/* ≤1200px, STRUCTURE only: two-row layout.
     Row 1: [brand] ............................ [discord] [navAuth]
     Row 2: [home | servers | maps | leaderboards | hof | rules | link]
   Was 1000px when there were 6 links; bumped to 1200px after adding
   "Hall of Fame" (the seventh link). New math: brand 350 + 7 links ~580
   + discord 36 + pill 150 + gaps ~100 = needs ~1216px to lay out cleanly
   in a single row. Below that, the avatar pill (the last flex item)
   was wrapping to its own row on the left, which is the bug the user
   spotted at ~1200px wide.
   Typography stays at desktop sizes in this range. Only the layout
   changes. Phone-tight sizing happens at ≤540px below. */
@media (max-width: 1200px) {
  .site-nav .brand { order: 0; }
  .site-nav .spacer { order: 1; flex: 1; }
  .site-nav .discord { order: 2; }
  /* navAuth lives in <span id="navAuth">. Target the wrap inside, plus the
     signed-out pill which lives directly in the slot. */
  .site-nav #navAuth { order: 3; }
  /* Force the links UL to a second row by giving it full width AFTER the
     row-1 items have laid out. flex-basis:100% + flex-wrap parent does it. */
  .site-nav .links {
    order: 99; flex-basis: 100%;
    justify-content: center;
    margin-top: 0.1rem;
  }
}

/* ≤540px phone typography. Tighter padding, smaller fonts, shrunk
   icons so 6 links fit on one row + the avatar pill stays compact next
   to the Discord icon. */
@media (max-width: 540px) {
  .site-nav { padding: 0.6rem 0.75rem; gap: 0.4rem 0.5rem; }
  .site-nav .brand { font-size: 0.95rem; }
  .site-nav .discord { width: 32px; height: 32px; }
  .site-nav .discord svg { width: 20px; height: 20px; }
  .site-nav .links a { padding: 0.35rem 0.55rem; font-size: 0.85rem; }
  .site-nav .nav-me { padding: 0.2rem 0.55rem 0.2rem 0.2rem; font-size: 0.8rem; max-width: 9rem; }
  .site-nav .nav-me-avatar { width: 22px; height: 22px; }
  .site-nav .nav-me-name { max-width: 5.5rem; }
  .site-nav .nav-signin { padding: 0.3rem 0.65rem; font-size: 0.8rem; }
}

/* Below ~420px (small phones), drop the name from the pill and just show
   avatar + caret. Saves room for the discord icon + tap target. */
@media (max-width: 420px) {
  .site-nav .nav-me-name { display: none; }
  .site-nav .nav-me { padding: 0.2rem 0.35rem 0.2rem 0.2rem; gap: 0.2rem; }
}

/* ─── Shared loading states ──────────────────────────────────────────────
   Use .loading-shimmer on any element to give it the animated pulse. Common
   pattern: replace inner text with a few <.skeleton-bar> spans during fetch,
   replace with real content on resolve. */

.loading-shimmer {
  background: linear-gradient(
    90deg,
    var(--panel-inset) 0%,
    var(--border-bright) 50%,
    var(--panel-inset) 100%
  );
  background-size: 200% 100%;
  animation: shimmer 1.4s ease-in-out infinite;
  border-radius: 4px;
  color: transparent !important;
  user-select: none;
}
.skeleton-bar {
  display: inline-block;
  height: 0.9em;
  background: linear-gradient(
    90deg,
    var(--panel-inset) 0%,
    var(--border-bright) 50%,
    var(--panel-inset) 100%
  );
  background-size: 200% 100%;
  animation: shimmer 1.4s ease-in-out infinite;
  border-radius: 4px;
  vertical-align: middle;
}
@keyframes shimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* Small inline Skin Bench check, used next to a player name on any board to
   indicate they currently hold the servertoys.skinbench permission. Source
   of truth is the plugin's permission.UserHasPermission check. */
.skin-bench-check {
  display: inline-block;
  margin-left: 0.35em;
  color: var(--rank-gold);
  font-weight: 700;
  font-size: 0.85em;
  cursor: help;
}

/* Torch King — canonical Rust torch icon (web/assets/rust-torch.webp).
   Shown next to the player with the most torch kills this wipe on the PvP
   leaderboard and in the scope-text legend. A subtle drop-shadow gives
   the flame a faint glow against the slate background. */
.torch-king-icon {
  display: inline-block;
  height: 1.15em;
  width: auto;
  margin-left: 0.35em;
  vertical-align: -0.25em;
  cursor: help;
  filter: drop-shadow(0 0 3px rgba(249, 115, 22, 0.55));
}

/* ─── Footer global search ─────────────────────────────────────────────────
   Lives inside .site-status-bar (injected by nav-status.js). Input on the
   left, pills on the right with a flex spacer between. Below 540px the
   pills hide and the input takes the dock width. Results panel floats
   above the dock; on short viewports (mobile keyboard up) it docks to
   the viewport top instead. */
.site-status-bar { justify-content: flex-start; gap: 0.5rem; }
.site-status-bar .site-search-wrap {
  position: relative; flex: 1 1 240px; display: flex; max-width: 360px;
}
.site-status-bar .site-search {
  width: 100%;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(125, 211, 252, 0.22);
  border-radius: 999px;
  padding: 0.3rem 0.85rem;
  color: var(--text); font-size: 0.78rem;
  outline: none;
  transition: border-color 120ms;
}
.site-status-bar .site-search:focus {
  border-color: rgba(125, 211, 252, 0.6);
  background: rgba(255, 255, 255, 0.06);
}
.site-status-bar .site-search::placeholder { color: var(--muted); }
.site-status-bar .site-search-pills { display: flex; gap: 0.4rem; align-items: center; flex-wrap: wrap; }

.site-search-results {
  position: absolute; bottom: calc(100% + 8px); left: 0;
  width: min(540px, calc(100vw - 1rem));
  background: rgba(10, 14, 20, 0.98);
  border: 1px solid rgba(125, 211, 252, 0.25);
  border-radius: 10px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
  padding: 0.4rem 0;
  z-index: 60;
  max-height: 60vh; overflow-y: auto;
}
.site-search-results .cat {
  font-size: 0.62rem; text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--gold); padding: 0.5rem 0.85rem 0.2rem;
}
.site-search-results .row {
  padding: 0.4rem 0.85rem; display: flex; align-items: center; gap: 0.6rem;
  font-size: 0.82rem; cursor: pointer; color: var(--text);
  text-decoration: none;
}
.site-search-results .row.hl,
.site-search-results .row:hover { background: rgba(125, 211, 252, 0.08); }
/* .av is the positioning context for the online dot; the inner clipped
   wrapper (built by search.js) holds the round avatar so the dot can sit
   OUTSIDE the clip and remain visible at the avatar's edge. */
.site-search-results .row .av {
  width: 22px; height: 22px;
  flex-shrink: 0; position: relative;
}
.site-search-results .row .av .av-img {
  width: 100%; height: 100%; border-radius: 50%; overflow: hidden;
  background: linear-gradient(135deg, #374151, #1f2937);
}
.site-search-results .row .av .av-img img { width: 100%; height: 100%; display: block; }
.site-search-results .row .av.online::after {
  content: ""; position: absolute; right: -2px; bottom: -2px;
  width: 9px; height: 9px; border-radius: 50%;
  background: #22c55e; box-shadow: 0 0 6px rgba(34, 197, 94, 0.6);
  border: 2px solid rgba(10, 14, 20, 1);
  z-index: 1;
}
.site-search-results .row .name { color: var(--text); }
/* Prior-name match indicator — appended inside .name when the row was
   matched on an alias (admin/deputy-only path; see search.js matchPlayers).
   Muted, italic, smaller than the current name so it reads as annotation. */
.site-search-results .row .name .aka-hit {
  color: var(--muted);
  font-size: 0.78em;
  font-style: italic;
  margin-left: 6px;
}
.site-search-results .row .meta {
  color: var(--muted); font-size: 0.7rem; margin-left: auto;
  white-space: nowrap;
}
/* Dense dropdown override: strip the pill's chip framing in search
   results so it reads as compact inline annotation, not a chip. Same
   pattern as .lb-table — name stays primary. margin-left: auto pushes
   the pill to the right edge of the row, matching .meta placement. */
.site-search-results .row .hours-pill {
  background: transparent; border: 1px solid transparent;
  padding: 0; gap: 0.3rem;
  margin-left: auto;
  align-items: baseline;
}
.site-search-results .row .hours-pill .seg .val { font-weight: 500; }
.site-search-results .row .hours-pill .seg.server .label,
.site-search-results .row .hours-pill .seg.rust   .label { color: var(--muted); opacity: 1; }
.site-search-results .row .icon {
  width: 18px; text-align: center;
  color: var(--gold);
  font-family: ui-monospace, monospace;
}
.site-search-results .show-more {
  padding: 0.35rem 0.85rem; font-size: 0.72rem;
  color: var(--muted); cursor: pointer; text-align: center;
}
.site-search-results .show-more:hover { color: var(--gold); }
.site-search-results .empty {
  padding: 0.7rem 0.85rem; font-size: 0.78rem;
  color: var(--muted); text-align: center;
}

@media (max-width: 540px) {
  .site-status-bar .site-search-pills { display: none; }
  .site-status-bar .site-search-wrap { max-width: none; }
}

@media (max-height: 500px) {
  .site-search-results.mobile-top {
    position: fixed; top: 8px; left: 8px; right: 8px;
    bottom: auto; width: auto; max-height: calc(100vh - 80px);
  }
}

/* Hide promotional "Link account" CTAs for already-linked viewers. The /link
   nav menu item stays visible (so they can still unlink); this only hides
   the prominent buttons/cards that exist to nudge unlinked players in.
   Toggled by auth.js setting <html data-linked="true"> once /api/link/status
   confirms a link. */
html[data-linked="true"] .link-cta { display: none !important; }

/* ─── Hours pill ────────────────────────────────────────────────────────────
   Sits next to player names site-wide. Two segments: "Chill" = lifetime
   hours on this server (PlaytimeTracker), "Rust" = total Steam lifetime
   in the game (AdminWatch / Steam Web API). Rust segment is omitted if
   Steam profile is private or hours unknown. Default visual: chip with
   subtle cyan tint + brand-color labels (cyan "Chill", red "Rust").
   Dense table contexts (e.g. .lb-table) override this to a muted inline
   form to keep the player name primary; see each page's CSS. Data
   sourced via /web/hours.js from /api/search/players-index. */
.hours-pill {
  display: inline-flex; align-items: center; gap: 0.3rem;
  padding: 0.15rem 0.5rem; border-radius: 999px;
  background: rgba(125, 211, 252, 0.04);
  border: 1px solid rgba(125, 211, 252, 0.15);
  font-size: 0.7rem; color: var(--muted);
  font-variant-numeric: tabular-nums;
  cursor: help; white-space: nowrap;
  vertical-align: middle;
  margin-left: 0.45rem;
}
.hours-pill .seg { display: inline-flex; gap: 0.2rem; align-items: baseline; }
.hours-pill .seg .val { color: var(--text); font-weight: 600; }
.hours-pill .seg.server .label { color: var(--sky); }
.hours-pill .seg.rust   .label { color: var(--rust-red); opacity: 0.9; }
.hours-pill .dot { opacity: 0.4; }
/* On phones, drop the segment labels; the dot separator and the tooltip
   carry the meaning. Pill stays the same color and shape. */
@media (max-width: 540px) {
  .hours-pill .seg .label { display: none; }
  .hours-pill { padding: 0.12rem 0.42rem; gap: 0.25rem; }
}
/* Per-row sizing: the .name-line flex container that holds the name
   and pill should use flex-wrap so each row independently decides
   whether the pill fits inline. Short names keep the pill on the same
   line; long names push the pill to a second line below. No container
   query needed — the browser handles it dynamically per row. */

/* Past Wipes carousel on /u/<sid> ----------------------------------------- */
.wipes-carousel { padding: 14px 16px; }
.wipes-title { text-align: center; margin-bottom: 10px; }
.wipes-title__name { font-size: 1rem; color: var(--text); }
.wipes-title__name strong { color: var(--gold); margin-right: 4px; }
.wipes-title__date { font-size: 0.85rem; color: var(--muted); margin-top: 2px; }

.wipes-stage { display: flex; align-items: center; gap: 10px; }
.wipes-nav {
  flex: 0 0 32px; width: 32px; height: 32px;
  background: var(--panel-inset); border: 1px solid var(--border);
  color: var(--text); border-radius: 4px;
  cursor: pointer; font-size: 1.1rem; line-height: 1;
  padding: 0;
}
.wipes-nav:disabled { opacity: 0.3; cursor: default; }
.wipes-nav:not(:disabled):hover { border-color: var(--gold); }

.wipes-slide { flex: 1 1 auto; display: flex; gap: 12px; min-width: 0; align-items: center; justify-content: center; }
.wipe-thumb {
  flex: 0 0 72px; width: 72px; height: 72px;
  border-radius: 6px; overflow: hidden;
  background: var(--panel-inset);
  display: flex; align-items: center; justify-content: center;
}
.wipe-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.wipe-thumb--empty { opacity: 0.3; }
.wipe-slide__main { flex: 0 1 auto; min-width: 0; }
/* Divider-separated stat cells: single no-wrap row; scrolls horizontally on
   very narrow screens rather than wrapping (scrollbar hidden). */
.wipe-stats { display: flex; flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; -ms-overflow-style: none; }
.wipe-stats::-webkit-scrollbar { display: none; }
.wipe-stat { padding: 0 11px; text-align: center; border-left: 1px solid var(--border); white-space: nowrap; }
.wipe-stat:first-child { border-left: 0; padding-left: 0; }
.wipe-stat__v { display: block; font-size: 1.05rem; font-weight: 700; font-variant-numeric: tabular-nums; line-height: 1.15; }
.wipe-stat__v.is-accent { color: var(--gold); }
.wipe-stat__v.is-rank { color: var(--rank-gold); }
.wipe-stat__k { display: block; font-size: 0.6rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); margin-top: 2px; }
.wipe-slide__badges { margin-top: 4px; }
.wipe-slide__mates { display: flex; gap: 4px; margin-top: 6px; flex-wrap: wrap; justify-content: center; }

.wipe-mate {
  width: 24px; height: 24px; border-radius: 50%; overflow: hidden;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--panel-inset); border: 1px solid var(--border);
  text-decoration: none;
}
.wipe-mate img { width: 100%; height: 100%; object-fit: cover; }
.wipe-mate-init { color: var(--muted); font-size: 0.7rem; }
.wipe-mate-more { color: var(--muted); font-size: 0.8rem; padding: 0 4px; align-self: center; }
.wipe-badge {
  display: inline-block; margin-right: 4px; padding: 1px 6px;
  background: rgba(255, 204, 77, 0.12); color: var(--rank-gold);
  border-radius: 4px; font-size: 0.8rem;
}

.wipes-dots { display: flex; gap: 6px; justify-content: center; margin-top: 12px; }
.wipe-dot {
  width: 8px; height: 8px; padding: 0; border: 0;
  border-radius: 50%;
  background: var(--muted); opacity: 0.4;
  cursor: pointer;
}
.wipe-dot.is-active { opacity: 1; background: var(--gold); }
.wipe-dot:hover { opacity: 0.7; }


/* Current team grid on /u/<sid> -------------------------------------------- */
.team-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  padding: 14px 16px;
}
.team-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  width: 84px;
  padding: 8px 6px;
  border: 1px solid transparent;
  border-radius: 8px;
  text-decoration: none;
  color: var(--text);
  transition: border-color 120ms ease, background 120ms ease, transform 120ms ease;
}
.team-tile:hover {
  border-color: var(--gold);
  background: rgba(125, 211, 252, 0.06);
  transform: translateY(-1px);
}
.team-tile__avatar {
  width: 56px; height: 56px;
  border-radius: 50%;
  overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  background: var(--panel-inset);
  border: 1px solid var(--border);
  flex: 0 0 auto;
}
.team-tile__avatar img {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
.team-tile__initial {
  font-size: 1.1rem;
  font-weight: 600;
  color: var(--muted);
}
.team-tile__name {
  font-size: 0.8rem;
  text-align: center;
  width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: 1.2;
}

/* /servers + home current-wipe banner ------------------------------------ */
.current-wipe-banner {
  margin: 0.5rem 0 0.75rem;
  padding: 0.4rem 0.75rem;
  background: rgba(125, 211, 252, 0.08);
  border-left: 3px solid var(--gold);
  border-radius: 0 4px 4px 0;
  color: var(--text);
  font-size: 0.95rem;
}
.current-wipe-banner strong { color: var(--gold); }

/* Hall of Fame wipe-name heading ------------------------------------------- */
.hof-wipe-name {
  font-size: 1.05rem;
  color: var(--text);
  margin-bottom: 2px;
}
.hof-wipe-name strong { color: var(--gold); margin-right: 4px; }

/* ─── CLS guards on dynamically-injected images (audit 2026-05-27) ─────────
   Avatars and map thumbs are painted via innerHTML, so the browser doesn't
   know the box size until the image bytes arrive — causing layout shift.
   aspect-ratio reserves the box at parse time. Width/height are already
   set on each owner rule; aspect-ratio is purely a CLS safety net. */
.wipe-thumb,
.wipe-thumb img { aspect-ratio: 1 / 1; }
/* .player-row .avatar (home top-3) is 48x48 in index.html; .last-wipe-winner
   .avatar is 36x36; .me-hero-avatar is 96x96. The width/height already exist
   in their owner rules — these only add the aspect-ratio safety net. */
.player-row .avatar,
.last-wipe-winner .avatar,
.me-hero-avatar { aspect-ratio: 1 / 1; }
/* .torch-king-icon is already height:1.15em / width:auto; aspect-ratio
   would conflict with its intrinsic SVG ratio. Skip. */

/* ─── Utility classes (audit 2026-05-27 — replaces inline style="…") ───────
   Extracted from ~40 inline style attrs across rendered JS so the CSP
   report-only stream stops drowning in style-src violations. Names are
   short and intent-oriented; widths are em/px because skeleton sites use
   em/px (a percent-based scale would have nothing to bind to). */
.no-underline { text-decoration: none; }

/* Inline color overrides (mostly for <strong>/<span> inside dynamic HTML
   that needs a specific palette token without a parent context). */
.color-text   { color: var(--text); }
.color-muted  { color: var(--muted); }
.color-gold   { color: var(--gold); }
.color-sky    { color: var(--sky); }

/* Tier-color text (Hours leaderboard tier column + /me hero tier badge).
   Mirrors the in-game roster palette: gold for Gold/Admin, silver, bronze,
   muted for None. JS chooses the class by tier number. */
.tier-color-gold    { color: var(--rank-gold); }
.tier-color-silver  { color: var(--rank-silver); }
.tier-color-bronze  { color: var(--rank-bronze); }
/* "None" tier: warmer muted than var(--muted), matches the original inline
   value (#a08a72) on the Hours board. Used by /me hero too via tierColor(0). */
.tier-color-default { color: #a08a72; }
/* Used as .lb-tier-cell.tier-color-* on the Hours board cell (adds the
   600 weight the inline style had). */
.lb-tier-cell { font-weight: 600; }

/* Recoil-eval badge backgrounds (admin/deputy /me view). Strength + recommendation
   each map a small enum to a fixed color; classes let us drop the inline bg style.
   Colors copied verbatim from me.js so the visual is unchanged. */
.recoil-eval-badge.s-strongest    { background: #f87171; }
.recoil-eval-badge.s-strong       { background: #fb923c; }
.recoil-eval-badge.s-suggestive   { background: #fbbf24; }
.recoil-eval-badge.s-inconclusive { background: #9ca3af; }
.recoil-eval-badge.s-clean        { background: #34d399; }
.recoil-eval-badge.r-spectate-immediately { background: #f87171; }
.recoil-eval-badge.r-spectate-when-online { background: #fbbf24; }
.recoil-eval-badge.r-let-data-grow        { background: #9ca3af; }
.recoil-eval-badge.r-clean-no-action      { background: #34d399; }

/* Tier badge on the /me hero needs currentColor for its border so the border
   tracks the tier color. The text color comes from a .tier-color-* class. */
.badge-tier-outline { border-color: currentColor; }

/* Small inline meta text used in the recoil-eval card header + the
   "open full report" / "view overlay" inline links. */
.text-xs        { font-size: 12px; }
.text-xxs       { font-size: 11px; }
.ml-6          { margin-left: 6px; }
.heading-flush { margin: 0; }

/* Skeleton-bar sized variants. The "width" classes use the em/px units
   the call sites actually need — short token (xs/sm/...) keyed to the
   actual measurement, not abstract grades. Generated only for widths
   that are used by index.js + leaderboards.js + me.js today. */
.sk-w-1\.2em { width: 1.2em; }
.sk-w-2\.5em { width: 2.5em; }
.sk-w-3em    { width: 3em; }
.sk-w-4em    { width: 4em; }
.sk-w-7em    { width: 7em; }
.sk-w-8em    { width: 8em; }
.sk-w-11em   { width: 11em; }
.sk-w-12em   { width: 12em; }
/* Compound: 48x48 avatar-shaped skeleton tile used on home top-3 skeleton. */
.sk-avatar-48 { width: 48px; height: 48px; border-radius: 8px; }
/* Pill-shaped skeleton (badges on /me hero skeleton). */
.sk-pill-4em  { width: 4em; height: 1.2em; border-radius: 999px; }
.sk-pill-3em  { width: 3em; height: 1.2em; border-radius: 999px; }
/* Hero-avatar shaped skeleton tile (96x96 inherits from .me-hero-avatar;
   this class adds the radius the inline style had). */
.sk-hero-avatar { border-radius: 12px; }
/* Hero info wrapper held flex:1 inline. */
.flex-1 { flex: 1; }
