/* ─── CSS Custom Properties ──────────────────────────────────────────────── */
:root {
  --bg:          #06080d;
  --surface:     #0b0f17;
  --surface-2:   #0f1520;
  --surface-3:   #131d2a;
  --border:      #1a2840;
  --border-2:    #243550;
  --text:        #cbdeee;
  --head:        #ecf7ff;
  --text-muted:  #93aabf;
  --text-dim:    #647d91;
  --accent:      #00e5ff;
  --accent-dim:  #07333d;
  --accent-hover:#00c8e0;
  --green:       #00e676;
  --green-dim:   #06331e;
  --blue:        #38a8ff;
  --blue-dim:    #0c2440;
  --warning:     #ffea00;
  --warning-dim: #34300a;
  --danger:      #ff1744;
  --danger-dim:  #380a14;
  --purple:      #d500f9;
  --purple-dim:  #2a0635;
  --teal:        #2bd4d0;
  --sidebar-w:   240px;   /* desktop in-flow sidebar (compact) */
  --sidebar-w-mobile: 450px;   /* mobile off-canvas drawer (capped to 88vw) — kept large for touch */
  --header-h:    52px;
  --radius:      6px;
  --radius-lg:   10px;
  --shadow:      0 2px 8px rgba(0,0,0,.4);
  --font:        'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-mono:   'JetBrains Mono', 'Fira Code', 'Consolas', monospace;
  --scale:       1;
  font-size: calc(18px * var(--scale));
}

/* ── Selectable themes (client/js/appTheme.js sets <html data-theme>) ──────────────────────────────
   Each theme only re-tints the neutral palette + the accent trio; the SEMANTIC colors (green/danger/
   warning/blue/purple) are intentionally left as the :root defaults so an online dot / error is the same
   everywhere. Default (Aurora / neon-cyan) lives in :root above = no data-theme attribute. All dark. */
:root[data-theme="ember"] {
  --bg:#0c0806; --surface:#150e09; --surface-2:#1e140c; --surface-3:#281a10;
  --border:#3a2717; --border-2:#503620;
  --text:#efe1d2; --head:#fff2e2; --text-muted:#c4a888; --text-dim:#8b735a;
  --accent:#ff9838; --accent-dim:#3a2410; --accent-hover:#ffab5c;
}
:root[data-theme="amethyst"] {
  --bg:#0a0713; --surface:#130c22; --surface-2:#1b1132; --surface-3:#241740;
  --border:#33214f; --border-2:#472f69;
  --text:#e7ddf6; --head:#f5edff; --text-muted:#b4a0d2; --text-dim:#7e6b9e;
  --accent:#b06bff; --accent-dim:#291049; --accent-hover:#c489ff;
}
:root[data-theme="pine"] {
  --bg:#06110c; --surface:#0a1a13; --surface-2:#0f251a; --surface-3:#143122;
  --border:#1c4130; --border-2:#265a41;
  --text:#dcece1; --head:#eefff5; --text-muted:#94b8a4; --text-dim:#5f8271;
  --accent:#e6b24a; --accent-dim:#332610; --accent-hover:#f2c766;
}
:root[data-theme="slate"] {
  --bg:#0b0e14; --surface:#111621; --surface-2:#171f2e; --surface-3:#1f2a3d;
  --border:#28344a; --border-2:#384866;
  --text:#dbe4f0; --head:#f0f6ff; --text-muted:#9fb0c7; --text-dim:#6b7c93;
  --accent:#7c9cff; --accent-dim:#152142; --accent-hover:#9db4ff;
}

/* iOS-Safari "Add to Home Screen" nudge (survivor shell) — floats above the bottom nav, dismissible. */
.sv-install-hint {
  position: fixed; left: 10px; right: 10px; bottom: 74px; z-index: 9000;
  max-width: 460px; margin: 0 auto;
  display: flex; align-items: center; gap: 10px; padding: 10px 12px;
  background: var(--surface-2); border: 1px solid var(--border-2);
  border-radius: 12px; box-shadow: 0 10px 30px rgba(0,0,0,.5);
}
.sv-install-hint img { width: 34px; height: 34px; border-radius: 8px; flex: 0 0 auto; object-fit: cover; }
.sv-install-text { display: flex; flex-direction: column; gap: 2px; font-size: .8rem; line-height: 1.3; min-width: 0; }
.sv-install-text b { color: var(--head); }
.sv-install-text span { color: var(--text-muted); }
.sv-install-x { margin-left: auto; flex: 0 0 auto; background: none; border: none;
  color: var(--text-dim); font-size: 1rem; cursor: pointer; padding: 4px 8px; line-height: 1; }
.sv-install-x:hover { color: var(--text); }

/* Branded footer on the survivor Profile tab. */
.sv-brand-footer { display: flex; flex-direction: column; align-items: center; gap: 4px;
  margin: 26px 0 8px; opacity: .55; }
.sv-brand-footer img { width: 30px; height: 30px; border-radius: 7px; object-fit: cover; }
.sv-brand-mark { font: 700 .95rem var(--font); color: var(--text); }
.sv-brand-mark span { color: var(--accent); }
.sv-brand-sub { font-size: .68rem; letter-spacing: 1.5px; text-transform: uppercase; color: var(--text-dim); }

/* Branded boot splash (index.html #app) — shown during the initial JS/auth load, replaced on first render. */
#boot-splash { position: fixed; inset: 0; z-index: 1; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 16px; background: var(--bg); }
#boot-splash img { border-radius: 18px; box-shadow: 0 8px 34px -6px var(--accent); }
#boot-splash .boot-wordmark { font: 800 1.6rem var(--font); color: var(--head); letter-spacing: .5px; }
#boot-splash .boot-wordmark span { color: var(--accent); }

/* Theme picker popover (reuses the .scale-pop shell from the size control) */
.theme-grid { display:grid; grid-template-columns:1fr 1fr; gap:6px; margin-top:4px; }
.theme-swatch { display:flex; align-items:center; gap:7px; padding:6px 8px; border:1px solid var(--border);
  border-radius:var(--radius); background:var(--surface-2); color:var(--text); cursor:pointer; font-size:.8rem; text-align:left; }
.theme-swatch:hover { border-color:var(--accent); }
.theme-swatch.active { border-color:var(--accent); box-shadow:0 0 0 1px var(--accent) inset; }
.theme-dot { width:18px; height:18px; border-radius:50%; flex-shrink:0; }
.theme-name { white-space:nowrap; }
.theme-custom-edit { display:flex; flex-direction:column; gap:8px; margin-top:8px; padding-top:8px; border-top:1px solid var(--border); }
.tc-roles { display:flex; flex-wrap:wrap; gap:4px; }
.tc-role { display:flex; align-items:center; gap:5px; padding:4px 7px; border:1px solid var(--border); border-radius:6px; background:var(--surface-2); color:var(--text); font-size:.74rem; cursor:pointer; }
.tc-role.active { border-color:var(--accent); box-shadow:0 0 0 1px var(--accent) inset; }
.tc-sw { width:14px; height:14px; border-radius:3px; border:1px solid rgba(0,0,0,.4); flex-shrink:0; }
.tc-sliders { display:flex; flex-direction:column; gap:7px; }
.tc-ch { display:flex; align-items:center; gap:9px; font-size:.72rem; color:var(--text-muted); }
.tc-ch > span { width:12px; text-align:center; }
.tc-ch input[type=range] { flex:1; accent-color:var(--accent); }
.tc-hex { align-self:flex-start; width:96px; font-family:var(--font-mono); font-size:.76rem; padding:3px 7px; background:var(--surface-2); border:1px solid var(--border-2); border-radius:5px; color:var(--text); }
.theme-custom-edit .tc-reset { align-self:flex-start; font-size:.72rem; background:none; border:1px solid var(--border-2); color:var(--text-muted); border-radius:5px; padding:3px 9px; cursor:pointer; }
.theme-custom-edit .tc-reset:hover { color:var(--text); border-color:var(--accent); }

/* ─── Reset ──────────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { height: 100%; }
body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 1rem;
  line-height: 1.5;
  height: 100%;
  overflow: hidden;
}
a { color: var(--blue); text-decoration: none; }
a:hover { text-decoration: underline; }
img, svg { display: block; }
button, input, select, textarea { font-family: inherit; font-size: inherit; }
button { cursor: pointer; }
ul, ol { list-style: none; }

/* ─── Layout ─────────────────────────────────────────────────────────────── */
/* Heights divide by --app-zoom (set by the app display-scale control, default 1) so that after CSS `zoom`
   multiplies them back up they stay exactly one screen tall — no overflow / clipped bottom nav on scale-up. */
#app { display: flex; height: 100vh; height: 100dvh; min-height: 100vh; min-height: 100dvh;
  height: calc(100dvh / var(--app-zoom, 1)); min-height: calc(100dvh / var(--app-zoom, 1));
  width: 100%; overflow: hidden; }

/* Sidebar */
#sidebar {
  width: var(--sidebar-w);
  min-width: var(--sidebar-w);
  background: var(--surface);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  overflow: hidden;                 /* the nav scrolls; logo + footer stay fixed */
  transition: width .2s, min-width .2s;
  z-index: 10;
  /* Sidebar-only scale (installed-app control): `zoom` scales the whole sidebar; the height divides by the
     same factor (and --app-zoom) so it stays exactly one screen tall instead of overflowing. Both vars
     default to 1, so a normal browser / unadjusted app is unaffected. */
  zoom: var(--sidebar-zoom, 1);
  height: calc(100dvh / var(--app-zoom, 1) / var(--sidebar-zoom, 1));
}
#sidebar.collapsed { width: 52px; min-width: 52px; }
#sidebar.collapsed .nav-label,
#sidebar.collapsed .nav-section-title,
#sidebar.collapsed #logo-text { display: none; }
#sidebar.collapsed .nav-item { justify-content: center; padding: 10px; }
#sidebar.collapsed .nav-icon { margin: 0; }

/* Installed-app view sidebar tuning lives inside the <=1024 media query below (that's where the app runs,
   as an off-canvas drawer). It shrinks the +50% touch text to a medium size and narrows the wide drawer. */

#logo {
  display: flex; align-items: center; gap: 10px;
  padding: 14px 16px; border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
#logo-icon { width: 28px; height: 28px; flex-shrink: 0; border-radius: 6px; object-fit: cover; }
#logo-text { font-weight: 700; font-size: 1.02rem; color: var(--text); white-space: nowrap; }
#logo-text span { color: var(--accent); }

nav { flex: 1 1 auto; padding: 8px 0; overflow-y: auto; overflow-x: hidden; min-height: 0; }
.nav-section { margin-bottom: 4px; }
.nav-section-title {
  font-size: .72rem; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--green);
  padding: 8px 16px 2px;
  margin-top: 6px; border-top: 1px solid var(--border);
  white-space: nowrap;
}
.nav-section-title:first-child { margin-top: 0; border-top: 0; }   /* no divider above the first section */
.nav-item {
  display: flex; align-items: center; gap: 10px;
  padding: 4px 16px; border-radius: 0;
  color: var(--text); font-size: .92rem;
  transition: background .15s, color .15s;
  white-space: nowrap; cursor: pointer; user-select: none;
}
.nav-item:hover { background: var(--surface-2); color: var(--head); }
.nav-item.active { background: var(--accent-dim); color: var(--accent); }
.nav-item.active .nav-icon { color: var(--accent); }
.nav-icon { width: 18px; height: 18px; flex-shrink: 0; color: var(--text-muted); font-size: 18px; line-height: 1; }
.nav-item.active .nav-icon { color: var(--accent); }
.nav-badge {
  margin-left: auto; background: var(--danger); color: #fff;
  border-radius: 10px; padding: 1px 6px; font-size: .65rem; font-weight: 600;
}

.sidebar-footer {
  padding: 12px; border-top: 1px solid var(--border);
  display: flex; flex-direction: column; align-items: stretch; gap: 10px;
  flex-shrink: 0;
}
.sidebar-footer-row { display: flex; align-items: center; gap: 8px; }
/* Desktop-app install (staff-only, sidebar footer) */
.sidebar-install {
  display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%;
  padding: 7px 10px; border-radius: 8px; cursor: pointer;
  font-size: .82rem; font-weight: 600; color: var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 45%, transparent);
  transition: background .15s;
}
.sidebar-install:hover { background: color-mix(in srgb, var(--accent) 22%, transparent); }
.sidebar-install-icon { font-size: 1rem; line-height: 1; }
/* Collapsed mini-rail: icon only (the .nav-label is hidden by the collapsed rule) */
#sidebar.collapsed .sidebar-install { padding: 7px; }
.sidebar-avatar {
  width: 28px; height: 28px; border-radius: 50%;
  background: var(--surface-3); flex-shrink: 0; overflow: hidden;
}
.sidebar-avatar img { width: 100%; height: 100%; object-fit: cover; }
.sidebar-user { min-width: 0; }
.sidebar-user-name { font-size: .8rem; font-weight: 600; truncate; }
.sidebar-user-role {
  font-size: .7rem; color: var(--text-muted); text-transform: capitalize;
}

/* Main content */
#main {
  flex: 1; display: flex; flex-direction: column;
  overflow: hidden; min-width: 0;
}
#topbar {
  height: var(--header-h); flex-shrink: 0;
  background: var(--surface); border-bottom: 1px solid var(--border);
  display: flex; align-items: center; padding: 0 20px; gap: 12px;
}
.topbar-title { font-size: 1rem; font-weight: 600; flex: 1; }
.topbar-actions { display: flex; align-items: center; gap: 8px; }

#content {
  flex: 1; overflow-y: auto; overflow-x: hidden;
  padding: 24px;
  background: var(--bg);
}

/* Preview mode banner */
#preview-banner {
  background: var(--warning-dim); border-bottom: 1px solid var(--warning);
  padding: 6px 20px; font-size: .8rem; color: var(--warning);
  display: flex; align-items: center; gap: 8px;
  flex-shrink: 0;
}
#preview-banner.hidden { display: none; }

/* Not-available banner */
.feature-banner {
  background: var(--warning-dim); border: 1px solid var(--warning);
  border-radius: var(--radius); padding: 12px 16px;
  color: var(--warning); font-size: .85rem;
  display: flex; align-items: center; gap: 10px; margin-bottom: 20px;
}

/* ─── Buttons ─────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 14px; border-radius: var(--radius);
  font-size: .85rem; font-weight: 500; border: 1px solid transparent;
  transition: background .15s, border-color .15s, opacity .15s;
  white-space: nowrap;
}
.btn:disabled { opacity: .4; pointer-events: none; }
.btn-primary { background: var(--accent); color: #0d1117; border-color: var(--accent); }
.btn-primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.btn-secondary {
  background: var(--surface-3); color: var(--text);
  border-color: var(--border-2);
}
.btn-secondary:hover { background: var(--surface-2); }
.btn-danger { background: var(--danger-dim); color: var(--danger); border-color: var(--danger); }
.btn-danger:hover { background: var(--danger); color: #fff; }
.btn-warning { background: var(--warning-dim); color: var(--warning); border-color: var(--warning); }
.btn-warning:hover { background: var(--warning); color: #0d1117; }
.btn-ghost { background: transparent; color: var(--text-muted); border-color: transparent; }
.btn-ghost:hover { background: var(--surface-2); color: var(--text); }
.btn-icon { padding: 6px; border-radius: var(--radius); }
.btn-sm { padding: 4px 10px; font-size: .78rem; }
.btn-lg { padding: 10px 20px; font-size: .95rem; }

/* ─── Cards ──────────────────────────────────────────────────────────────── */
.card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: 20px;
}
.card-sm { padding: 14px; }
.card-header {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 16px; gap: 12px;
}
.card-title { font-size: .9rem; font-weight: 600; color: var(--head); }
.card-body { }

.stat-card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: 16px 20px;
  display: flex; flex-direction: column; gap: 4px;
  cursor: pointer; transition: border-color .15s, background .15s;
}
.stat-card:hover { border-color: var(--border-2); background: var(--surface-2); }
.stat-label { font-size: .75rem; color: var(--text-muted); font-weight: 500; text-transform: uppercase; letter-spacing: .05em; }
.stat-value { font-size: 1.6rem; font-weight: 700; line-height: 1.2; color: var(--head); }
.stat-sub { font-size: .75rem; color: var(--text-muted); }
.stat-green  { color: var(--green); }
.stat-blue   { color: var(--blue); }
.stat-warning{ color: var(--warning); }
.stat-danger { color: var(--danger); }

/* ─── Grid utilities ─────────────────────────────────────────────────────── */
.grid { display: grid; gap: 16px; }
/* Grid children default to min-width:auto, so a wide child (e.g. a table) refuses to shrink and overflows
   its column instead of letting an inner .table-wrap scroll. min-width:0 lets them shrink to the track. */
.grid > * { min-width: 0; }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }
.grid-auto { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }

/* ─── Tables ─────────────────────────────────────────────────────────────── */
.table-wrap { overflow-x: auto; border-radius: var(--radius); border: 1px solid var(--border); }
/* Inside a scroll wrapper, size the table to its content and scroll sideways instead of squeezing columns
   until cells wrap to 2+ lines (that grew rows on mobile and pushed content off-screen). Cells stay on one
   line; the wrapper scrolls horizontally. */
.table-wrap > table { width: max-content; min-width: 100%; }
.table-wrap > table th, .table-wrap > table td { white-space: nowrap; }
table { width: 100%; border-collapse: collapse; font-size: .82rem; }
thead tr { background: var(--surface-2); }
th {
  padding: 10px 14px; text-align: left; font-size: .72rem;
  font-weight: 600; color: var(--text-muted);
  text-transform: uppercase; letter-spacing: .05em;
  border-bottom: 1px solid var(--border); white-space: nowrap;
}
td { padding: 10px 14px; border-bottom: 1px solid var(--border); vertical-align: middle; }
tbody tr:last-child td { border-bottom: none; }
tbody tr:hover { background: var(--surface-2); }
.table-empty { text-align: center; padding: 32px; color: var(--text-muted); }

/* ─── Forms ──────────────────────────────────────────────────────────────── */
.form-group { display: flex; flex-direction: column; gap: 6px; }
.form-label { font-size: .82rem; font-weight: 500; color: var(--text-muted); }
.form-input, .form-select, .form-textarea {
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 8px 12px; color: var(--text);
  font-size: .85rem; outline: none; width: 100%;
  transition: border-color .15s;
}
.form-input:focus, .form-select:focus, .form-textarea:focus {
  border-color: var(--accent);
}
.form-input::placeholder, .form-textarea::placeholder { color: var(--text-dim); }
.form-textarea { resize: vertical; min-height: 80px; font-family: var(--font-mono); }
.form-row { display: flex; gap: 12px; }
.form-row > * { flex: 1; }
.form-hint { font-size: .75rem; color: var(--text-muted); }
.form-error { font-size: .75rem; color: var(--danger); }
input[type="checkbox"] { accent-color: var(--accent); width: 15px; height: 15px; cursor: pointer; }
input[type="range"]    { accent-color: var(--accent); width: 100%; }

/* Stop mobile browsers from auto-zooming when a text field is focused: iOS zooms in whenever the focused
   input's font is < 16px. Force 16px on touch devices only (pinch-zoom still works; the focus-zoom doesn't
   fire). Include the .form-* classes so they beat their own .85rem rule above (same specificity, later). */
@media (pointer: coarse) {
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
  textarea, select,
  .form-input, .form-select, .form-textarea { font-size: 16px; }
}
.checkbox-row { display: flex; align-items: center; gap: 8px; font-size: .85rem; cursor: pointer; }

/* ─── Combobox (type-to-filter picker) ───────────────────────────────────── */
.combo { position: relative; }
.combo-list {
  position: absolute; z-index: 30; left: 0; right: 0; top: calc(100% + 2px);
  max-height: 240px; overflow-y: auto;
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: 0 6px 18px rgba(0,0,0,.35);
}
.combo-opt { padding: 7px 12px; font-size: .85rem; color: var(--text); cursor: pointer; white-space: nowrap; }
.combo-opt:hover { background: rgba(255,255,255,.06); }

/* ─── Badges ─────────────────────────────────────────────────────────────── */
.badge {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px; border-radius: 20px; font-size: .7rem; font-weight: 600;
}
.badge-green   { background: var(--green-dim);     color: var(--green);   }
.badge-blue    { background: var(--blue-dim);      color: var(--blue);    }
.badge-yellow  { background: var(--warning-dim);   color: var(--warning); }
.badge-red     { background: var(--danger-dim);    color: var(--danger);  }
.badge-purple  { background: var(--purple-dim);    color: var(--purple);  }
.badge-grey    { background: var(--surface-3);     color: var(--text-muted); }
.badge-dot::before {
  content: ''; display: inline-block;
  width: 6px; height: 6px; border-radius: 50%;
  background: currentColor;
}

/* ─── Online/Status dot ───────────────────────────────────────────────────── */
.online-dot {
  display: inline-block; width: 8px; height: 8px;
  border-radius: 50%; background: var(--text-dim);
}
.online-dot.online  { background: var(--green); box-shadow: 0 0 4px var(--green); }
.online-dot.warning { background: var(--warning); }
.online-dot.offline { background: var(--danger); }

/* ─── Modal ──────────────────────────────────────────────────────────────── */
.modal-backdrop {
  position: fixed; inset: 0; background: rgba(0,0,0,.7);
  display: flex; align-items: center; justify-content: center;
  z-index: 1000; padding: 20px;
  animation: fadeIn .15s ease;
  /* Under the app's CSS `zoom`, a fixed `inset:0` box sizes to the ZOOMED viewport (taller than the real
     screen), so a centered modal's top/bottom land off-screen. Pin the height to one real screen and let the
     backdrop scroll as a safety net. Both vars default to 1 → no effect at 100%. */
  bottom: auto; height: calc(100dvh / var(--app-zoom, 1)); overflow-y: auto;
}
.modal-backdrop.hidden { display: none; }
.modal {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); width: 100%; max-width: 520px;
  /* Cap to the real (zoom-compensated) screen minus the backdrop padding so the modal always fits and its
     body scrolls internally instead of overflowing off-screen. */
  max-height: calc(100dvh / var(--app-zoom, 1) - 40px); display: flex; flex-direction: column;
  animation: slideUp .15s ease;
}
.modal-lg { max-width: 780px; }
.modal-xl { max-width: 1000px; }
.modal-full { max-width: 96vw; width: 96vw; }
.modal-header {
  padding: 16px 20px; border-bottom: 1px solid var(--border);
  display: flex; align-items: center; justify-content: space-between;
  flex-shrink: 0;
}
.modal-title { font-size: .95rem; font-weight: 600; }
.modal-body { padding: 20px; overflow-y: auto; flex: 1; }
.modal-footer {
  padding: 14px 20px; border-top: 1px solid var(--border);
  display: flex; justify-content: flex-end; gap: 8px; flex-shrink: 0;
}

/* On phones, every modal — especially the big ones (package editor is size:'full') — becomes a full-screen
   sheet: full width/height, no rounded corners or backdrop padding, so nothing is pushed off the edges. The
   header + footer stay pinned (flex-shrink:0) and the body scrolls between them, so the Save/Cancel row is
   always reachable. Height divides by --app-zoom for the same reason #app does (installed-app display scale). */
@media (max-width: 600px) {
  /* stretch (not center) pins the sheet top-to-bottom with no centering rounding; the backdrop is already
     one viewport tall (its height:calc(100dvh/--app-zoom) above), so the modal fills the screen exactly. */
  .modal-backdrop { padding: 0; align-items: stretch; }
  .modal, .modal-lg, .modal-xl, .modal-full {
    width: 100%; max-width: 100%; max-height: none; border-radius: 0;
  }
  .modal-header, .modal-footer { padding-left: 14px; padding-right: 14px; }
  .modal-body { padding: 14px; }
  /* Inline item/control rows (e.g. the package item row) wrap instead of overflowing off the right edge. */
  .modal-body .flex.gap-8 { flex-wrap: wrap; }
}

/* ─── Toast ──────────────────────────────────────────────────────────────── */
#toast-container {
  position: fixed; bottom: 20px; right: 20px;
  display: flex; flex-direction: column; gap: 8px; z-index: 2000;
}
.toast {
  background: var(--surface-3); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 10px 16px;
  font-size: .82rem; max-width: 320px;
  display: flex; align-items: flex-start; gap: 10px;
  animation: slideIn .2s ease; box-shadow: var(--shadow);
}
.toast-success { border-color: var(--green);   color: var(--green);   }
.toast-error   { border-color: var(--danger);  color: var(--danger);  }
.toast-warning { border-color: var(--warning); color: var(--warning); }
.toast-info    { border-color: var(--blue);    color: var(--blue);    }
.toast-text    { color: var(--text); flex: 1; }

/* ─── Search & filter bar ─────────────────────────────────────────────────── */
.filter-bar {
  display: flex; gap: 8px; align-items: center;
  flex-wrap: wrap; margin-bottom: 16px;
}
.filter-bar .form-input, .filter-bar .form-select {
  width: auto; min-width: 160px;
}
.search-input { min-width: 220px !important; }

/* ─── Pagination ─────────────────────────────────────────────────────────── */
.pagination {
  display: flex; align-items: center; gap: 4px; justify-content: center;
  padding: 16px 0;
}
.page-btn {
  padding: 5px 10px; border-radius: var(--radius);
  font-size: .8rem; border: 1px solid var(--border);
  background: var(--surface-2); color: var(--text-muted);
  transition: background .15s;
}
.page-btn:hover  { background: var(--surface-3); color: var(--text); }
.page-btn.active { background: var(--accent-dim); color: var(--accent); border-color: var(--accent); }
.page-btn:disabled { opacity: .3; pointer-events: none; }

/* ─── Tabs ───────────────────────────────────────────────────────────────── */
.tabs {
  display: flex; gap: 2px; border-bottom: 1px solid var(--border); margin-bottom: 20px;
  flex-wrap: nowrap; overflow-x: auto; overflow-y: hidden;
  -webkit-overflow-scrolling: touch;            /* momentum scroll on iOS */
  scrollbar-width: thin;                         /* Firefox */
}
.tabs::-webkit-scrollbar { height: 4px; }
.tabs::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }
.tab {
  padding: 8px 16px; font-size: .82rem; font-weight: 500;
  color: var(--text-muted); border-bottom: 2px solid transparent;
  cursor: pointer; transition: color .15s, border-color .15s;
  white-space: nowrap; flex: 0 0 auto;           /* don't shrink — enables horizontal scroll */
}
.tab:hover { color: var(--text); }
.tab.active { color: var(--accent); border-bottom-color: var(--accent); }

/* Horizontal-scroll wrapper for wide content (grid lists) on small screens */
.hscroll { overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: thin; }
.hscroll::-webkit-scrollbar { height: 4px; }
.hscroll::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }

/* ─── Progress / countdown ───────────────────────────────────────────────── */
.progress-bar { height: 6px; border-radius: 3px; background: var(--surface-3); overflow: hidden; }
.progress-fill { height: 100%; border-radius: 3px; background: var(--green); transition: width .5s; }
.progress-fill.warning { background: var(--warning); }
.progress-fill.danger  { background: var(--danger);  animation: pulse-danger 1s ease-in-out infinite; }
/* Indeterminate: a sliding sweep for phases with no measurable % (copy/stop/start). */
.progress-fill.indeterminate { width: 40%; background: var(--warning); animation: indeterminate 1.2s ease-in-out infinite; }
@keyframes indeterminate { 0% { margin-left: -42%; } 100% { margin-left: 100%; } }

/* ─── INI Editor ────────────────────────────────────────────────────────── */
.ini-editor {
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 0; overflow: hidden;
}
.ini-editor textarea {
  width: 100%; background: transparent; border: none; outline: none;
  color: var(--text); font-family: var(--font-mono); font-size: .82rem;
  padding: 14px; min-height: 400px; resize: vertical;
}

/* ─── Countdown chip ─────────────────────────────────────────────────────── */
.countdown {
  font-family: var(--font-mono); font-size: .78rem;
  display: inline-flex; align-items: center; gap: 4px;
}
.countdown.urgent { color: var(--danger); font-weight: 700; animation: pulse-danger 1s ease-in-out infinite; }
.countdown.warn   { color: var(--warning); }
.countdown.ok     { color: var(--green); }

/* ─── Connection health ──────────────────────────────────────────────────── */
.health-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 10px; }
.health-item {
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 10px 14px;
  display: flex; align-items: center; gap: 10px; font-size: .82rem;
}
.health-item.ok     { border-color: var(--green-dim); }
.health-item.warn   { border-color: var(--warning-dim); }
.health-item.error  { border-color: var(--danger-dim); }
.health-label { flex: 1; min-width: 0; }
.health-name  { font-weight: 500; }
.health-sub   { font-size: .72rem; color: var(--text-muted); }

/* ─── Decay card ─────────────────────────────────────────────────────────── */
.decay-row {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); margin-bottom: 8px; overflow: hidden;
}
.decay-row-header {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px; cursor: pointer;
}
.decay-row-header:hover { background: var(--surface-2); }
.decay-tribe-name { font-weight: 600; font-size: .88rem; flex: 1; }
.decay-maps { display: flex; gap: 4px; flex-wrap: wrap; }
.map-badge {
  font-size: .65rem; padding: 2px 6px; border-radius: 3px;
  background: var(--surface-3); color: var(--text-muted);
}
.decay-expand { padding: 12px 16px; border-top: 1px solid var(--border); background: var(--surface-2); }

/* ─── Platform badges ─────────────────────────────────────────────────────── */
.platform-steam { color: #c7d5e0; font-size: .7rem; font-weight: 600; }
.platform-epic  { color: #a855f7; font-size: .7rem; font-weight: 600; }
.platform-xbox  { color: #52b043; font-size: .7rem; font-weight: 600; }

/* ─── Role badge ──────────────────────────────────────────────────────────── */
.role-owner     { color: #ff9500; }
.role-developer { color: var(--purple); }
.role-admin     { color: var(--danger); }
.role-mod       { color: var(--blue); }
.role-survivor  { color: var(--accent); }

/* ─── Animations ─────────────────────────────────────────────────────────── */
@keyframes fadeIn  { from { opacity: 0 } to { opacity: 1 } }
@keyframes slideUp { from { transform: translateY(10px); opacity: 0 } to { transform: translateY(0); opacity: 1 } }
@keyframes slideIn { from { transform: translateX(20px); opacity: 0 } to { transform: translateX(0); opacity: 1 } }
@keyframes pulse-danger { 0%,100% { opacity: 1 } 50% { opacity: .5 } }
@keyframes spin { to { transform: rotate(360deg) } }
.spin { animation: spin .8s linear infinite; }

/* ─── Loading states ─────────────────────────────────────────────────────── */
.skeleton {
  background: linear-gradient(90deg, var(--surface-2) 25%, var(--surface-3) 50%, var(--surface-2) 75%);
  background-size: 200% 100%;
  animation: shimmer 1.2s infinite;
  border-radius: var(--radius);
}
@keyframes shimmer { from { background-position: 200% 0 } to { background-position: -200% 0 } }

.loading-spinner {
  width: 20px; height: 20px; border-radius: 50%;
  border: 2px solid var(--border); border-top-color: var(--accent);
  animation: spin .6s linear infinite; display: inline-block;
}
.page-loading {
  display: flex; align-items: center; justify-content: center;
  height: 200px; color: var(--text-muted); gap: 12px; font-size: .85rem;
}

/* ─── Code / mono ────────────────────────────────────────────────────────── */
code {
  font-family: var(--font-mono); font-size: .82em;
  background: var(--surface-3); padding: 1px 5px;
  border-radius: 3px; color: var(--teal);
}
pre {
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 14px;
  font-family: var(--font-mono); font-size: .8rem;
  overflow-x: auto; color: var(--text);
}

/* ─── Divider ────────────────────────────────────────────────────────────── */
.divider { border: none; border-top: 1px solid var(--border); margin: 16px 0; }
.section-title {
  font-size: .7rem; font-weight: 700; letter-spacing: .1em;
  text-transform: uppercase; color: var(--text-dim);
  margin-bottom: 12px;
}

/* ─── Empty state ────────────────────────────────────────────────────────── */
.empty-state {
  text-align: center; padding: 48px 24px;
  color: var(--text-muted); font-size: .85rem;
}
.empty-state-icon { font-size: 2.5rem; margin-bottom: 12px; opacity: .4; }
.empty-state-title { font-size: .95rem; font-weight: 600; color: var(--text); margin-bottom: 6px; }

/* ─── Confirmation chip ──────────────────────────────────────────────────── */
.confirm-danger {
  border-top: 1px solid var(--border); padding-top: 14px; margin-top: 14px;
}
.confirm-input {
  border-color: var(--danger) !important;
}

/* ─── Responsive ──────────────────────────────────────────────────────────── */
#mobile-overlay { position: fixed; inset: 0; background: rgba(0,0,0,.5); z-index: 99; }
/* Mobile + tablet (≤1024px): the sidebar is OFF-CANVAS by default so the content takes the full width
   (larger on phones), and the ☰ slides it in as an OVERLAY on top of the content. Desktop (≥1025px)
   keeps the persistent sidebar. The JS ☰ handler uses the same 1024px cutoff. */
@media (max-width: 1024px) {
  /* Cap the drawer to the viewport so a wide --sidebar-w doesn't overflow a phone; leave a strip of
     overlay to tap-close. left:-100% keeps it fully off-canvas regardless of the capped width. */
  #sidebar { position: fixed; top: 0; left: -100%; width: min(var(--sidebar-w-mobile), 88vw); min-width: 0;
             transition: left .25s; z-index: 100; height: 100vh; height: 100dvh;
             height: calc(100dvh / var(--app-zoom, 1) / var(--sidebar-zoom, 1)); }
  #sidebar.mobile-open { left: 0; box-shadow: 4px 0 20px rgba(0,0,0,.5); }
  /* +50% sidebar text on mobile for readability (nav items, icons, section titles, logo). */
  #sidebar .nav-item { font-size: 1.58rem; padding: 16px 24px; gap: 18px; }
  #sidebar .nav-icon { width: 33px; height: 33px; font-size: 33px; }
  #sidebar .nav-section-title { font-size: 1.17rem; padding: 14px 24px 5px; }
  #sidebar #logo-text { font-size: 1.73rem; }
  #sidebar .sidebar-user-name { font-size: 1.2rem; }
  #sidebar .sidebar-user-role { font-size: 1.05rem; }

  /* Installed-app view: the touch drawer above is sized for a phone browser; in the app it reads too big.
     Narrow it and step the text down to a medium size (still touch-friendly, not desktop-tiny). */
  #sidebar.app-compact { width: min(320px, 82vw); }
  #sidebar.app-compact .nav-item { font-size: 1.08rem; padding: 9px 16px; gap: 12px; }
  #sidebar.app-compact .nav-icon { width: 22px; height: 22px; font-size: 22px; }
  #sidebar.app-compact .nav-section-title { font-size: .86rem; padding: 8px 16px 3px; }
  #sidebar.app-compact #logo { padding: 12px 16px; }
  #sidebar.app-compact #logo-text { font-size: 1.2rem; }
  #sidebar.app-compact .sidebar-user-name { font-size: .92rem; }
  #sidebar.app-compact .sidebar-user-role { font-size: .8rem; }
}
@media (min-width: 1025px) { #mobile-overlay { display: none !important; } }   /* overlay never shown on desktop */

/* "Desktop layout on a touch device" (admin Desktop-site mode on a phone): the fixed-width viewport makes
   innerWidth wide, so the ≤1024 drawer rules don't apply — replicate them here. Keep the DESKTOP sidebar
   width/text (the whole page is already scaled down), hide it off-canvas, and slide it in via the ☰ / edge
   swipe. #main takes full width since the sidebar is position:fixed (out of flow). */
html.force-drawer #sidebar {
  position: fixed; top: 0; left: -100%; width: var(--sidebar-w); min-width: 0;
  transition: left .25s; z-index: 100;
  height: calc(100dvh / var(--app-zoom, 1) / var(--sidebar-zoom, 1));
}
html.force-drawer #sidebar.mobile-open { left: 0; box-shadow: 4px 0 20px rgba(0,0,0,.5); }
html.force-drawer #mobile-overlay:not(.hidden) { display: block !important; }   /* beat the ≥1025 hide */
@media (max-width: 768px) {
  .grid-4 { grid-template-columns: repeat(2, 1fr); }
  .grid-3 { grid-template-columns: repeat(2, 1fr); }
  #content { padding: 16px; }
}
@media (max-width: 480px) {
  .grid-4, .grid-3, .grid-2 { grid-template-columns: 1fr; }
  .form-row { flex-direction: column; }
}

/* ─── Survivor shell (mobile-first) ─────────────────────────────────────── */
/* #app is a row flex container (built for the admin sidebar+main). The survivor shell is a lone child,
   so it must grow to fill both axes — flex:1 + width:100% claim the full width, and 100dvh/stretch the
   full height — otherwise on a wide (tablet/app) viewport it collapses to content width on the left. */
#survivor-shell {
  display: flex; flex-direction: column;
  flex: 1 1 auto; width: 100%; min-width: 0;
  height: 100vh; height: 100dvh;
  height: calc(100dvh / var(--app-zoom, 1)); overflow: hidden;
}
#sv-header {
  display: flex; align-items: center;
  padding: 12px 16px; background: var(--surface);
  border-bottom: 1px solid var(--border); flex-shrink: 0;
  box-shadow: 0 1px 12px -7px var(--accent);   /* subtle themed brand glow under the header */
  /* At a large display scale the header row (balance chip · ↻ · 🔔 · Aa · name · Sign out) gets wider than
     the screen. The shell is overflow:hidden, so those controls were simply CLIPPED and unreachable — you
     couldn't even get back to the "Aa" control to scale back down. Let the header scroll horizontally, same
     as the bottom nav. NB: `justify-content: space-between` is deliberately gone — it fights the scroll
     origin once the content overflows; `margin-left:auto` on .sv-user gives the identical logo-left /
     user-right layout while it still fits. */
  overflow-x: auto; overflow-y: hidden;
  overscroll-behavior-x: contain;          /* don't let the swipe trigger browser back-navigation */
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
#sv-header::-webkit-scrollbar { display: none; }
.sv-logo { font-size: 1.2rem; font-weight: 800; flex: 0 0 auto; display: flex; align-items: center; gap: 7px; }
.sv-logo-icon { width: 24px; height: 24px; border-radius: 6px; object-fit: cover; flex: 0 0 auto; }
.sv-logo-text span { color: var(--accent); }
.sv-user { display: flex; align-items: center; gap: 12px; flex: 0 0 auto; margin-left: auto; }
.sv-user > * { flex: 0 0 auto; }           /* never squash the controls — overflow and scroll instead */
.sv-balance {
  font-weight: 800; font-size: 0.9rem; color: var(--green);
  background: color-mix(in srgb, var(--green) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--green) 40%, transparent);
  padding: 4px 10px; border-radius: 999px; white-space: nowrap;
}
#sv-refresh { font-size: 1.15rem; line-height: 1; }
#sv-refresh.spinning { animation: spin 0.6s linear infinite; }
/* On narrow phones the username can crowd the balance out — hide the name, keep the balance. */
@media (max-width: 420px) { .sv-username { display: none; } }
#sv-content {
  flex: 1; overflow-y: auto; padding: 16px 16px 24px;
}
/* #sv-content is already a bounded flex scroll container, so it needs no big over-scroll spacer (a small
   padding-bottom above gives comfortable breathing room). The admin #content on mobile keeps a modest
   over-scroll buffer where a real scroll gap existed. */
@media (max-width: 1024px) { #content::after { content: ''; display: block; height: 120px; } }
/* The viewport is `viewport-fit=cover` (edge-to-edge) and the shell is a full 100dvh, so the last flex
   child lands UNDER the device's system navigation bar / gesture pill / tablet taskbar — the bottom nav
   was being hidden behind it. Reserve the OS inset as padding: the button row stays 64px and sits above
   the system bar, while the nav's background still extends behind it (no ugly gap). env() falls back to
   0px on devices/browsers without an inset, so nothing changes there. */
#sv-bottom-nav {
  display: flex; border-top: 1px solid var(--border);
  background: var(--surface); flex: 0 0 auto;
  height: calc(64px + env(safe-area-inset-bottom, 0px));
  padding-bottom: env(safe-area-inset-bottom, 0px);
  box-sizing: border-box;
  /* Swipe/slide the tabs when they don't fit — many tabs and/or a large display scale. Each tab keeps a
     comfortable tap size and the bar scrolls horizontally instead of crushing every label into a sliver.
     When they DO fit, flex-grow still spreads them across the full width exactly as before. */
  overflow-x: auto; overflow-y: hidden;
  scroll-snap-type: x proximity;
  overscroll-behavior-x: contain;          /* don't let the swipe trigger browser back-navigation */
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;                   /* hide the scrollbar (it's a touch surface, not a list) */
}
#sv-bottom-nav::-webkit-scrollbar { display: none; }
.sv-nav-btn {
  /* grow to fill when there's room, but never shrink below a readable/tappable width → overflow → swipe */
  flex: 1 0 auto; min-width: 72px; scroll-snap-align: center;
  display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 4px; padding: 8px 4px;
  background: none; border: none;
  color: var(--text-muted); font-size: .75rem; font-weight: 500;
  cursor: pointer; transition: color .15s;
}
.sv-nav-btn:hover, .sv-nav-btn.active { color: var(--accent); }
.sv-nav-btn.active { border-top: 2px solid var(--accent); }
.sv-nav-icon { font-size: 1.3rem; line-height: 1; }
.sv-nav-label { font-size: .7rem; }

/* ─── App display-scale control ("Aa", installed-app only) ─────────────────── */
.scale-ctl { position: relative; display: inline-flex; }
.scale-btn { letter-spacing: -1px; display: inline-flex; align-items: baseline; }
/* Absolute inside .scale-ctl (not fixed) so it stays anchored to the button under CSS `zoom`.
   right:0 opens leftward from the button's right edge — keeps it on-screen for a top-right header button. */
.scale-pop {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 300; min-width: 172px;
  background: var(--surface-2, var(--surface)); border: 1px solid var(--border);
  border-radius: 12px; padding: 10px 12px 12px; box-shadow: 0 10px 30px rgba(0,0,0,.45);
  display: flex; flex-direction: column; gap: 8px;
}
.scale-pop-title {
  font-size: .68rem; color: var(--text-muted);
  text-transform: uppercase; letter-spacing: .6px; font-weight: 700;
}
.scale-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.scale-row .btn { font-size: 1.35rem; line-height: 1; padding: 2px 16px; min-width: 46px; }
.scale-row .btn:disabled { opacity: .35; cursor: default; }
.scale-val { font-weight: 800; font-size: 1rem; min-width: 58px; text-align: center; }
.scale-reset { align-self: stretch; text-align: center; }

/* ─── Survivor restore confirmation screen ─────────────────────────────────── */
.restore-confirm {
  position: fixed; inset: 0; z-index: 400; display: flex; align-items: center; justify-content: center;
  padding: 20px; background: rgba(0,0,0,.72);
  /* Same zoom fix as .modal-backdrop: pin to one real screen so the card stays reachable under CSS `zoom`. */
  bottom: auto; height: calc(100dvh / var(--app-zoom, 1)); overflow-y: auto;
}
.restore-confirm-card {
  width: 100%; max-width: 440px; background: var(--surface); border: 1px solid var(--border);
  border-radius: 16px; padding: 20px; box-shadow: 0 20px 60px rgba(0,0,0,.5);
  max-height: calc(100dvh / var(--app-zoom, 1) - 40px); overflow-y: auto;
}
.restore-confirm-head { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
.restore-confirm-icon { font-size: 1.8rem; line-height: 1; }
.restore-confirm-title { font-size: 1.2rem; font-weight: 800; }
.restore-confirm-row {
  display: flex; justify-content: space-between; gap: 12px; padding: 9px 0;
  border-bottom: 1px solid var(--border); font-size: .9rem;
}
.restore-confirm-row > span:first-child { color: var(--text-muted); }
.restore-confirm-warn {
  margin-top: 14px; padding: 12px 14px; border-radius: 10px; font-size: .85rem; line-height: 1.5;
  color: var(--warning); background: color-mix(in srgb, var(--warning) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--warning) 35%, transparent);
}
.restore-confirm-actions { margin-top: 18px; display: flex; gap: 10px; }
.restore-confirm-actions .btn { flex: 1; }

/* ─── Shop: inline item pick menu (survivor-selects) ───────────────────────── */
.shop-pick-label { font-size: .78rem; color: var(--text-muted); margin: 8px 0 4px; }
.shop-pick { width: 100%; margin-bottom: 4px; }
.shop-pick-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 4px; }
.shop-pick-chip {
  padding: 6px 10px; border-radius: 999px; cursor: pointer; font-size: .82rem;
  background: var(--surface-2, var(--bg)); border: 1px solid var(--border); color: var(--text);
  transition: border-color .12s, background .12s;
}
.shop-pick-chip.selected { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 16%, transparent); color: var(--accent); }
/* Highlight Buy/Confirm once a valid choice is made */
.shop-buy-ready { box-shadow: 0 0 0 2px var(--accent), 0 0 14px color-mix(in srgb, var(--accent) 55%, transparent); }
.shop-card-pending { border-color: color-mix(in srgb, var(--accent) 45%, var(--border)); }

/* ─── Survivor "Online" view ───────────────────────────────────────────────── */
/* Survivor "What's new" changelog feed */
.sv-news-head { font-size: 1.05rem; font-weight: 800; margin-bottom: 12px; }
.sv-news-card {
  background: var(--surface-2); border: 1px solid var(--border); border-left: 3px solid var(--accent);
  border-radius: 10px; padding: 12px 14px; margin-bottom: 12px;
}
.sv-news-top { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 4px; }
.sv-news-cat {
  font-size: .7rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  color: var(--accent); background: color-mix(in srgb, var(--accent) 15%, transparent);
  padding: 2px 8px; border-radius: 999px;
}
.sv-news-ver { font-size: .72rem; font-family: var(--mono, monospace); color: var(--text-muted); }
.sv-news-date { font-size: .72rem; color: var(--text-dim); margin-left: auto; }
.sv-news-title { font-weight: 700; color: var(--head); }
.sv-news-body { margin-top: 6px; font-size: .9rem; color: var(--text); line-height: 1.5; word-break: break-word; }

.online-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
.online-title { font-size: 1.05rem; font-weight: 800; }
.online-count {
  display: inline-flex; align-items: center; justify-content: center; min-width: 24px; height: 22px;
  padding: 0 7px; margin-left: 6px; border-radius: 999px; font-size: .8rem; font-weight: 700;
  background: color-mix(in srgb, var(--green) 18%, transparent); color: var(--green);
}
.online-server { margin-bottom: 16px; }
.online-server-name {
  display: flex; align-items: center; gap: 8px; font-weight: 700; color: var(--green);
  text-transform: uppercase; font-size: .74rem; letter-spacing: .05em;
  padding: 6px 2px; border-bottom: 1px solid var(--border); margin-bottom: 2px;
}
.online-server-count { margin-left: auto; color: var(--text-muted); font-weight: 600; }
.online-player {
  display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 9px 4px;
  border-bottom: 1px solid color-mix(in srgb, var(--border) 55%, transparent);
}
.online-player:last-child { border-bottom: 0; }
.online-player-name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.online-admin { font-size: .85em; }
.online-tribe { font-size: .85rem; flex-shrink: 0; max-width: 45%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ── Shop (survivor-facing, mobile-first) ─────────────────────────────── */
.shop-balance-bar {
  position: sticky; top: -16px; z-index: 5; margin: -4px 0 14px;
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 16px; background: var(--surface-2); border: 1px solid var(--border);
  border-radius: 12px;
}
.shop-balance-amt { font-size: 1.35rem; font-weight: 800; color: var(--green); }
.shop-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 12px; }
.shop-card {
  display: flex; flex-direction: column; gap: 8px;
  padding: 14px; background: var(--surface); border: 1px solid var(--border);
  border-radius: 12px; transition: border-color .15s;
}
.shop-card:hover { border-color: var(--border-2, var(--accent)); }
/* Fixed BANNER SHAPE, not just a height cap. With `max-height` alone the box took the image's own ratio and
   only clamped TALL images: a square preset hit the cap and cropped, while a wide (3:1) upload came out
   ~113px — under the cap, so it never cropped and rendered visibly smaller than the presets next to it.
   aspect-ratio pins the box, so EVERY image (square preset or wide upload) fills the same banner and
   object-fit:cover crops it centrally. max-height stops it growing silly on a wide desktop card. */
.shop-img { width: 100%; aspect-ratio: 3 / 2; max-height: 260px; object-fit: cover; border-radius: 8px; display: block; margin: -4px 0 4px; background: var(--surface-2, #0f1520); }
.shop-card-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.shop-name { font-weight: 700; font-size: 1.02rem; }
.shop-tag { font-size: .68rem; font-weight: 600; color: var(--purple); white-space: nowrap; }
.shop-price { font-weight: 800; color: var(--accent); white-space: nowrap; }
.shop-desc { font-size: .82rem; color: var(--text-muted); }
.shop-items { display: flex; flex-wrap: wrap; gap: 5px; }
.shop-chip {
  font-size: .72rem; padding: 2px 8px; border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--border); color: var(--text);
}
.shop-chip-q { color: var(--warning); font-weight: 700; }
.shop-actions { display: flex; align-items: center; gap: 8px; margin-top: 4px; flex-wrap: wrap; }
.shop-qty { display: flex; align-items: center; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
.shop-step {
  width: 38px; height: 38px; background: var(--surface-2); border: none; color: var(--text);
  font-size: 1.2rem; font-weight: 700; cursor: pointer;
}
.shop-step:active { background: var(--surface-3); }
.shop-qty-in {
  width: 52px; height: 38px; text-align: center; border: none; border-left: 1px solid var(--border);
  border-right: 1px solid var(--border); background: var(--surface); color: var(--text);
  font-size: 1rem; font-weight: 700; -moz-appearance: textfield;
}
.shop-qty-in::-webkit-outer-spin-button, .shop-qty-in::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.shop-total { font-size: .82rem; font-weight: 700; color: var(--text-muted); flex: 1; }
.shop-buy { min-height: 40px; padding: 0 18px; min-width: 88px; }
.shop-limit { font-size: .72rem; color: var(--text-muted); }
@media (max-width: 480px) { .shop-grid { grid-template-columns: 1fr; } }

/* Donator landing page (survivor Donators tab) */
.sv-kofi-card { background: var(--surface-2, #0f1520); border: 1px solid var(--border, #243550); border-radius: 12px; padding: 14px; margin: 12px 0; }
.sv-kofi-title { font-weight: 800; font-size: 1.05rem; margin-bottom: 6px; }
.sv-kofi-row { font-size: .85rem; }
.sv-kofi-code { display: inline-block; font-family: monospace; font-weight: 700; letter-spacing: 1px; background: var(--surface); border: 1px dashed var(--accent); border-radius: 6px; padding: 2px 8px; margin-left: 4px; cursor: pointer; color: var(--head, var(--text)); }
.sv-donate-hero { background: var(--surface-2, #0f1520); border: 1px solid var(--border, #243550); border-radius: 12px; padding: 18px; margin-bottom: 4px; }
.sv-donate-hero .sv-page-title { margin: 0 0 8px; }
.sv-donate-body { color: var(--text, #b8d0e2); font-size: .92rem; line-height: 1.5; }
.sv-donate-body a { color: var(--accent, #00e5ff); }
.sv-donate-links { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 14px; }
.sv-donate-link { min-height: 42px; display: inline-flex; align-items: center; }

/* Leaderboards (survivor Leaderboards tab) */
.lb-tabs { display: flex; gap: 6px; flex-wrap: wrap; }
.lb-tab { flex: 1 1 auto; min-height: 40px; padding: 6px 10px; border: 1px solid var(--border, #243550); background: var(--surface-2, #0f1520); color: var(--text, #b8d0e2); border-radius: 8px; font-size: .88rem; cursor: pointer; }
.lb-tab.active { background: var(--accent, #00e5ff); color: #04222b; border-color: var(--accent, #00e5ff); font-weight: 600; }
.lb-windows { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; }
.lb-win { min-height: 34px; padding: 4px 12px; border: 1px solid var(--border, #243550); background: transparent; color: var(--text-muted); border-radius: 999px; font-size: .8rem; cursor: pointer; }
.lb-win.active { background: var(--surface-3, #131d2a); color: var(--head, #e0f4ff); border-color: var(--accent, #00e5ff); }
.lb-list { display: flex; flex-direction: column; gap: 6px; }
.lb-row { display: flex; align-items: center; gap: 10px; padding: 9px 12px; background: var(--surface-2, #0f1520); border: 1px solid var(--border, #243550); border-radius: 8px; }
.lb-rank { flex: none; width: 34px; text-align: center; font-size: 1rem; }
.lb-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.lb-metric { flex: none; font-size: .9rem; }
.lb-base-table { width: 100%; border-collapse: collapse; }
.lb-base-table th, .lb-base-table td { padding: 8px 10px; border-bottom: 1px solid var(--border, #243550); text-align: left; }
.lb-base-table th { font-size: .72rem; text-transform: uppercase; color: var(--text-muted); }

/* Discord Posts — collapsible cards */
.dp-card.dp-collapsed { margin-bottom: 8px; }
.dp-card.dp-collapsed .dp-bodywrap { display: none; }
.dp-card:not(.dp-collapsed) .dp-collapsed-title { display: none; }
.dp-toggle { min-width: 26px; padding: 2px 6px; font-size: .8rem; }
.dp-collapsed-title { flex: 1; min-width: 0; }

/* ── Survivor tribe log viewer ─────────────────────────────────────────── */
.tl-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
.tl-tribe { font-size: 1.1rem; font-weight: 800; }
.tl-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
.tl-chip {
  font-size: .78rem; padding: 6px 12px; border-radius: 999px; cursor: pointer;
  background: var(--surface); border: 1px solid var(--border); color: var(--text-muted);
  min-height: 34px; white-space: nowrap;
}
.tl-chip.active { background: color-mix(in srgb, var(--accent) 18%, transparent); border-color: var(--accent); color: var(--head, var(--text)); font-weight: 700; }
.tl-alerts { background: var(--surface-2); border: 1px solid var(--border); border-radius: 10px; padding: 12px; margin-bottom: 12px; }
.tl-alert-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 16px; }
.tl-alert-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; font-size: .85rem; }
.tl-list { display: flex; flex-direction: column; gap: 8px; }
.tl-row {
  display: flex; gap: 10px; align-items: flex-start; padding: 10px 12px;
  background: var(--surface); border: 1px solid var(--border); border-radius: 10px;
}
.tl-icon { font-size: 1.1rem; line-height: 1.3; flex: none; width: 22px; text-align: center; }
.tl-body { min-width: 0; flex: 1; }
.tl-msg { font-size: .88rem; word-break: break-word; }
.tl-meta { font-size: .7rem; color: var(--text-muted); margin-top: 2px; }
.tl-map { color: var(--accent); font-weight: 600; }
@media (max-width: 480px) { .tl-alert-grid { grid-template-columns: 1fr; } }

/* ── Survivor Breeding library ─────────────────────────────────────────── */
.br-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 10px; flex-wrap: wrap; }
.br-title { font-size: 1.1rem; font-weight: 800; }
.br-actions { display: flex; gap: 6px; }
.br-filters { display: flex; gap: 8px; align-items: center; margin-bottom: 12px; flex-wrap: wrap; }
.br-scope { display: flex; gap: 6px; }
.br-chip {
  font-size: .78rem; padding: 6px 12px; border-radius: 999px; cursor: pointer; min-height: 34px; white-space: nowrap;
  background: var(--surface); border: 1px solid var(--border); color: var(--text-muted);
}
.br-chip.active { background: color-mix(in srgb, var(--accent) 18%, transparent); border-color: var(--accent); color: var(--head, var(--text)); font-weight: 700; }
.br-search { flex: 1; min-width: 120px; padding: 8px 12px; border-radius: 8px; background: var(--surface); border: 1px solid var(--border); color: var(--text); font-size: .85rem; }
.br-fsel { padding: 8px 10px; border-radius: 8px; background: var(--surface); border: 1px solid var(--border); color: var(--text); font-size: .8rem; max-width: 48%; }
/* calc */
.br-calc { background: var(--surface-2); border: 1px solid var(--border); border-radius: 10px; padding: 10px 12px; }
.br-calc-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-weight: 700; font-size: .85rem; margin-bottom: 8px; }
.br-calc-cfg { flex: 1; min-width: 120px; font-size: .8rem; padding: 6px 8px; }
.br-calc-imp { font-size: .75rem; color: var(--text-muted); display: flex; align-items: center; gap: 4px; }
.br-calc-imp input { width: 56px; padding: 5px 6px; border-radius: 6px; background: var(--surface); border: 1px solid var(--border); color: var(--text); }
/* line manager */
.grp-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 8px 6px; border-bottom: 1px solid var(--border); }
.grp-name { font-size: .88rem; }
.grp-actions { display: flex; gap: 2px; }
.br-group { margin-bottom: 16px; }
.br-group-title { font-size: .8rem; font-weight: 700; color: var(--head, var(--text)); margin-bottom: 8px; text-transform: uppercase; letter-spacing: .04em; }
.br-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 220px), 1fr)); gap: 8px; }
.br-card {
  text-align: left; padding: 10px 12px; border-radius: 10px; cursor: pointer; width: 100%;
  background: var(--surface); border: 1px solid var(--border); color: var(--text); display: flex; flex-direction: column; gap: 4px;
}
.br-card:hover { border-color: var(--accent); }
/* Auto-adopted into its breeding line since this member last looked — a per-viewer "new" highlight. */
.br-card-new { border-color: var(--green, var(--accent)); box-shadow: 0 0 0 1px var(--green, var(--accent)) inset; }
/* Breeding-line entry mode: two tappable cards (Manual only / Automatic), one always selected. */
.br-modes { display: flex; flex-direction: column; gap: 6px; }
.br-mode {
  display: flex; gap: 8px; align-items: flex-start; cursor: pointer;
  padding: 8px 10px; border-radius: 8px; border: 1px solid var(--border); background: var(--surface);
}
.br-mode:hover { border-color: var(--border-2); }
.br-mode-on { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset; }
.br-mode input { margin-top: 2px; flex: 0 0 auto; }
/* Breeding settings page: grouped cards + a label/input row that stays readable on a phone. */
.br-set-card { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 12px; margin-bottom: 12px; }
.br-set-title { font-weight: 700; color: var(--head); margin-bottom: 4px; }
.br-set-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px 10px; }
.br-set-row { display: flex; align-items: center; gap: 8px; }
.br-set-row label { flex: 1; font-size: .78rem; color: var(--text-muted); }
.br-set-row input { width: 86px; }
@media (max-width: 420px) { .br-set-grid { grid-template-columns: 1fr; } }
/* Species spreadsheet: dense, horizontally scrollable, sticky species column so the row stays identifiable. */
.br-sheet { border-collapse: collapse; font-size: .74rem; min-width: 100%; }
.br-sheet th, .br-sheet td { padding: 4px 7px; text-align: right; white-space: nowrap; border-bottom: 1px solid var(--border); }
.br-sheet th { color: var(--text-muted); font-weight: 600; position: sticky; top: 0; background: var(--surface); }
.br-sheet tbody tr:hover { background: var(--surface-2); }
.br-sheet td:first-child, .br-sheet th:first-child { position: sticky; left: 0; background: var(--surface); }
.br-sheet tbody tr:hover td:first-child { background: var(--surface-2); }
.br-sheet-cell b { color: var(--green, var(--accent)); }
.br-sheet-who { font-size: .62rem; color: var(--text-dim, var(--text-muted)); max-width: 90px; overflow: hidden; text-overflow: ellipsis; }
/* Library grouped by breeding LINE: a one-line label per line, tapped to reveal its dinos. */
.br-line { margin-bottom: 6px; }
.br-line-head {
  width: 100%; display: flex; align-items: center; gap: 8px; text-align: left; cursor: pointer;
  padding: 9px 11px; border-radius: 9px; background: var(--surface); border: 1px solid var(--border); color: var(--text);
}
.br-line-head:hover { border-color: var(--accent); }
.br-line-head.open { border-color: var(--border-2); background: var(--surface-2); }
.br-line-caret { color: var(--text-dim, var(--text-muted)); flex: 0 0 auto; }
.br-line-name { font-weight: 700; font-size: .9rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.br-line-meta { color: var(--text-muted); font-size: .72rem; margin-left: auto; text-align: right; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.br-line-body { padding: 8px 2px 4px; }
.br-line-row { display: flex; align-items: stretch; gap: 6px; }
.br-line-row .br-line-head { flex: 1; min-width: 0; }
/* Name row: name (truncates) · level pill · badges. margin-right:auto on the name keeps the badges right-aligned
   while the level sits immediately after the name rather than floating away from it. */
.br-card-top { display: flex; align-items: center; gap: 6px; }
.br-name { font-weight: 700; font-size: .92rem; margin-right: auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.br-lv { flex: none; font-size: .72rem; font-weight: 700; color: var(--head, var(--text)); background: var(--surface-2); border: 1px solid var(--border-2, var(--border)); border-radius: 6px; padding: 1px 6px; }
.br-line-lv { color: var(--head, var(--text)); }
.br-species { font-size: .8rem; color: var(--text-muted); }
.br-sex { font-weight: 800; margin-right: 3px; }
.br-male { color: var(--blue, #38a8ff); }
.br-female { color: var(--purple, #d500f9); }
.br-shared { font-size: .62rem; text-transform: uppercase; letter-spacing: .05em; color: var(--text-muted); border: 1px solid var(--border); border-radius: 6px; padding: 1px 5px; }
.br-tags { display: flex; flex-wrap: wrap; gap: 4px; }
.br-tag { font-size: .68rem; background: var(--surface-2); border: 1px solid var(--border); border-radius: 6px; padding: 1px 6px; color: var(--text-muted); white-space: nowrap; }
/* Stats read as separate values, not one run-on string — each chip is boxed with real gaps between them. */
.br-stats-row { display: flex; flex-wrap: wrap; gap: 3px 5px; margin-top: 4px; }
.br-stat { font-size: .66rem; color: var(--text-muted); background: var(--surface-2); border-radius: 5px; padding: 1px 5px; white-space: nowrap; }
.br-stat b { color: var(--green, var(--accent)); }
.br-mut { color: var(--purple, #d500f9); font-weight: 700; margin-left: 1px; }
.br-mut-cell { color: var(--purple, #d500f9); }
.br-colors { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 3px; align-items: center; }
.br-col { font-size: .64rem; color: var(--text-muted); background: var(--surface-2); border: 1px solid var(--border); border-radius: 5px; padding: 1px 5px 1px 3px; display: inline-flex; align-items: center; gap: 3px; }
.br-col b { color: var(--head, var(--text)); }
.br-sw { display: inline-block; width: 11px; height: 11px; border-radius: 3px; border: 1px solid rgba(255,255,255,.35); flex: none; }
.br-sw-unknown { background: repeating-linear-gradient(45deg, #444 0 3px, #666 3px 6px); }
.br-colors-inputs { display: grid; grid-template-columns: repeat(6, 1fr); gap: 5px; }
.br-col-input { display: flex; flex-direction: column; gap: 2px; }
.br-col-input label { font-size: .66rem; color: var(--text-muted); text-align: center; }
.br-col-field { display: flex; align-items: center; gap: 3px; background: var(--surface); border: 1px solid var(--border); border-radius: 6px; padding: 0 3px; }
.br-col-field .br-sw { width: 13px; height: 13px; }
.br-col-field input { padding: 6px 2px; border: none; background: transparent; color: var(--text); font-size: .8rem; width: 100%; text-align: center; min-width: 0; }
@media (max-width: 380px) { .br-colors-inputs { grid-template-columns: repeat(3, 1fr); } }
/* detail */
.br-detail { display: flex; flex-direction: column; gap: 12px; }
.br-d-name { font-size: 1.25rem; font-weight: 800; }
.br-d-species { color: var(--text-muted); font-size: .9rem; }
.br-d-tags { display: flex; flex-wrap: wrap; gap: 6px; }
.br-pedigree { }
.br-parents { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.br-mini {
  text-align: left; padding: 8px 10px; border-radius: 10px; background: var(--surface); border: 1px solid var(--border);
  color: var(--text); display: flex; flex-direction: column; gap: 2px; cursor: pointer;
}
.br-mini[data-id]:hover { border-color: var(--accent); }
.br-mini-empty { cursor: default; opacity: .7; }
.br-mini-role { font-size: .66rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: .04em; }
.br-mini-name { font-weight: 700; font-size: .85rem; }
.br-mini-sp { font-size: .72rem; color: var(--text-muted); }
.br-stats-table { width: 100%; border-collapse: collapse; font-size: .85rem; }
.br-stats-table th, .br-stats-table td { text-align: left; padding: 5px 8px; border-bottom: 1px solid var(--border); }
.br-stats-table th { color: var(--text-muted); font-weight: 600; font-size: .75rem; }
.br-num { text-align: right; font-variant-numeric: tabular-nums; }
.br-notes { background: var(--surface-2); border: 1px solid var(--border); border-radius: 8px; padding: 10px; font-size: .85rem; white-space: pre-wrap; }
.br-d-actions { display: flex; flex-wrap: wrap; gap: 6px; }
/* form + modal */
.br-modal-wrap { position: fixed; inset: 0; background: rgba(0,0,0,.6); display: flex; align-items: flex-start; justify-content: center; padding: 24px 12px; z-index: 3000; overflow-y: auto; }
.br-modal { background: var(--surface-2, var(--surface)); border: 1px solid var(--border); border-radius: 12px; width: 100%; max-width: 460px; }
.br-modal-head { display: flex; align-items: center; justify-content: space-between; padding: 12px 14px; border-bottom: 1px solid var(--border); font-weight: 700; }
.br-modal-x { background: none; border: none; color: var(--text-muted); font-size: 1rem; cursor: pointer; }
.br-modal-body { padding: 14px; }
.br-form { display: flex; flex-direction: column; gap: 10px; }
.br-f-row { display: flex; flex-direction: column; gap: 4px; }
.br-f-row label, .br-f-grid label, .br-stat-input label { font-size: .72rem; color: var(--text-muted); }
.br-f-grid { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px; }
.br-f-grid > div { display: flex; flex-direction: column; gap: 4px; }
.br-f-label { font-size: .72rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: .04em; margin-top: 4px; }
.br-input { width: 100%; padding: 8px 10px; border-radius: 8px; background: var(--surface); border: 1px solid var(--border); color: var(--text); font-size: .85rem; }
.br-stats-inputs { display: grid; grid-template-columns: 1fr 1fr; gap: 6px 10px; }
.br-stat-input { display: grid; grid-template-columns: 1.1fr .8fr .8fr 1fr; align-items: center; gap: 4px; }
.br-val-cell { color: var(--green, var(--accent)); }
.br-stat-input input { padding: 6px 6px; border-radius: 6px; background: var(--surface); border: 1px solid var(--border); color: var(--text); font-size: .8rem; width: 100%; }
.br-f-buttons { display: flex; justify-content: flex-end; gap: 8px; margin-top: 6px; }
@media (max-width: 480px) { .br-f-grid { grid-template-columns: 1fr 1fr; } .br-parents { grid-template-columns: 1fr; } }

/* ── Game Server Config — responsive card list (replaces a wide action-button table) ── */
.gc-toolbar { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; flex-wrap: wrap; }
.gc-toolbar .btn-primary { margin-left: auto; }
.gc-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 420px), 1fr)); gap: 12px; }
.gc-card { padding: 12px; display: flex; flex-direction: column; gap: 8px; }
.gc-card-head { display: flex; align-items: center; gap: 8px; justify-content: space-between; }
.gc-meta { word-break: break-word; }
.gc-actions { display: flex; flex-wrap: wrap; gap: 6px; }
.gc-actions .btn { flex: 0 1 auto; }
@media (max-width: 480px) {
  .gc-grid { grid-template-columns: 1fr; }
  .gc-toolbar .btn-primary { margin-left: 0; width: 100%; }
}

/* Toggle switch (used in notification prefs) */
.toggle { position: relative; display: inline-block; width: 40px; height: 22px; }
.toggle input { opacity: 0; width: 0; height: 0; }
.toggle-slider {
  position: absolute; inset: 0; background: var(--surface-3);
  border: 1px solid var(--border-2); border-radius: 22px;
  cursor: pointer; transition: background .15s;
}
.toggle-slider::before {
  content: ''; position: absolute; width: 16px; height: 16px;
  left: 2px; top: 2px; background: var(--text-muted);
  border-radius: 50%; transition: transform .15s, background .15s;
}
.toggle input:checked + .toggle-slider { background: var(--accent-dim); border-color: var(--accent); }
.toggle input:checked + .toggle-slider::before { transform: translateX(18px); background: var(--accent); }

/* ─── Login page ─────────────────────────────────────────────────────────── */
#login-page {
  display: flex; align-items: center; justify-content: center;
  min-height: 100vh; min-height: calc(100dvh / var(--app-zoom, 1)); width: 100%;
  padding: 24px;
  /* Themed navy backdrop with a neon-cyan glow behind the card. */
  background:
    radial-gradient(1100px 620px at 50% 4%, rgba(0, 229, 255, 0.11), transparent 62%),
    radial-gradient(900px 520px at 50% 118%, rgba(56, 168, 255, 0.09), transparent 60%),
    var(--bg);
}
.login-card {
  position: relative;
  background: linear-gradient(180deg, var(--surface-2, #0f1520), var(--surface));
  border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: 40px 40px 34px;
  text-align: center; width: 100%; max-width: 400px;
  box-shadow: 0 0 0 1px rgba(0, 229, 255, 0.08), 0 22px 60px rgba(0, 0, 0, 0.55), 0 0 46px rgba(0, 229, 255, 0.07);
}
.login-logo-img {
  display: block; margin: 0 auto 16px; width: 76px; height: 76px;
  border-radius: 20px; object-fit: cover;
  box-shadow: 0 0 0 1px rgba(0, 229, 255, 0.28), 0 10px 28px rgba(0, 229, 255, 0.20);
}
.login-logo { font-size: 2.1rem; font-weight: 800; letter-spacing: -0.01em; margin-bottom: 6px; color: var(--head, #e0f4ff); }
.login-logo span { color: var(--accent); }
.login-sub { color: var(--text); font-size: .9rem; margin-bottom: 4px; }
.login-game {
  color: var(--text-muted); font-size: .68rem; letter-spacing: .14em;
  text-transform: uppercase; opacity: .72; margin-bottom: 28px;
}
.discord-btn {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  width: 100%; padding: 12px 20px; border-radius: var(--radius);
  background: #5865F2; color: #fff; font-weight: 600; font-size: .9rem;
  border: none; cursor: pointer; transition: background .15s;
}
.discord-btn:hover { background: #4752c4; }

/* ─── Misc utilities ─────────────────────────────────────────────────────── */
.flex { display: flex; }
.flex-center { display: flex; align-items: center; }
.flex-between { display: flex; align-items: center; justify-content: space-between; }
.gap-4 { gap: 4px; } .gap-8 { gap: 8px; } .gap-12 { gap: 12px; } .gap-16 { gap: 16px; }
.mt-8 { margin-top: 8px; } .mt-12 { margin-top: 12px; } .mt-16 { margin-top: 16px; } .mt-20 { margin-top: 20px; }
.mb-8 { margin-bottom: 8px; } .mb-12 { margin-bottom: 12px; } .mb-16 { margin-bottom: 16px; } .mb-20 { margin-bottom: 20px; }
.divider { height: 1px; background: var(--border); margin: 4px 0; }
.text-muted { color: var(--text-muted); }
.text-danger { color: var(--danger); }
.text-accent { color: var(--accent); }
.text-warning { color: var(--warning); }
.text-sm { font-size: .8rem; }
.text-xs { font-size: .72rem; }
.font-mono { font-family: var(--font-mono); }
.font-bold { font-weight: 700; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hidden { display: none !important; }
.full-width { width: 100%; }
