/* ==========================================================================
   Custom shell theme: slim horizontal topbar + dark surface palette.
   Loaded after argon-dashboard.css so these rules win.
   ========================================================================== */

:root {
  --cx-bg:            #000000;
  --cx-bg-elev:       #0c1017;
  --cx-surface:       #10264dfa;
  --cx-surface-2:     #141b26;
  --cx-border:        rgba(255, 255, 255, 0.07);
  --cx-border-strong: rgba(255, 255, 255, 0.14);
  --cx-text:          #e6e9ef;
  --cx-text-dim:      #9aa4b2;
  --cx-topbar-h:      56px;
  --cx-radius:        12px;

  /* One surface vocabulary for the whole shell. Every panel is one of these
     three, so a card, a home tile and a module page all read as the same
     material instead of each picking its own grey. */
  --cx-panel:         rgba(0, 16, 135, 0.23);      /* top level: .card       */
  --cx-panel-bd:      rgba(130, 175, 255, 0.16);
  --cx-panel-2:       rgba(90, 130, 220, 0.07);    /* nested inside a panel  */
  --cx-panel-2-bd:    rgba(120, 160, 255, 0.10);
  --cx-panel-3:       rgba(255, 255, 255, 0.045);  /* smallest tiles / wells */
  --cx-panel-3-bd:    rgba(255, 255, 255, 0.08);
}

/* ---------- base surface ---------- */

body.g-sidenav-show,
body {
  background: var(--cx-bg) !important;
  color: var(--cx-text);
}

/* Kill the tall coloured banner the old layout painted behind everything. */
body > .min-height-300 {
  display: none !important;
}

/* No left sidenav any more: reclaim the horizontal space at every breakpoint. */
.main-content {
  margin-left: 0 !important;
  padding-top: calc(var(--cx-topbar-h) + 16px);
}
@media (min-width: 1200px) {
  .main-content { margin-left: 0 !important; }
}
body.g-sidenav-pinned .main-content { margin-left: 0 !important; }

/* ---------- slim topbar ---------- */

.cx-topbar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: var(--cx-topbar-h);
  z-index: 1040;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 16px;
  background: rgba(10, 18, 40, 0.55);
  backdrop-filter: saturate(160%) blur(12px);
  -webkit-backdrop-filter: saturate(160%) blur(12px);
  border-bottom: 1px solid var(--cx-border);
}

.cx-brand {
  display: flex;
  align-items: center;
  gap: 9px;
  text-decoration: none;
  color: var(--cx-text);
  font-weight: 700;
  font-size: 0.95rem;
  white-space: nowrap;
  padding-right: 6px;
}
.cx-brand img {
  height: 28px;
  width: 28px;
  border-radius: 8px;
  object-fit: cover;
}
.cx-brand:hover { color: var(--cx-text); }

/* nav links */
.cx-nav {
  display: flex;
  align-items: center;
  gap: 2px;
  margin: 0;
  padding: 0 0 0 8px;
  list-style: none;
  overflow-x: auto;
  scrollbar-width: none;
}
.cx-nav::-webkit-scrollbar { display: none; }

.cx-nav a {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 6px 11px;
  border-radius: 8px;
  color: var(--cx-text-dim);
  font-size: 0.83rem;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  transition: background 0.15s ease, color 0.15s ease;
}
.cx-nav a i { font-size: 0.9rem; opacity: 0.85; }
.cx-nav a:hover {
  background: var(--cx-surface-2);
  color: var(--cx-text);
}
.cx-nav a.active {
  background: var(--cx-surface-2);
  color: #fff;
  box-shadow: inset 0 -2px 0 0 currentColor;
}

.cx-spacer { flex: 1 1 auto; }

/* right cluster: search + user + gear, merged in from the old top-right bar */
.cx-right {
  display: flex;
  align-items: center;
  gap: 8px;
}

.cx-search {
  position: relative;
  display: flex;
  align-items: center;
}
.cx-search i {
  position: absolute;
  left: 10px;
  font-size: 0.78rem;
  color: var(--cx-text-dim);
  pointer-events: none;
}
.cx-search input {
  height: 34px;
  width: 190px;
  padding: 0 10px 0 29px;
  border-radius: 8px;
  border: 1px solid var(--cx-border);
  background: var(--cx-bg-elev);
  color: var(--cx-text);
  font-size: 0.82rem;
  outline: none;
  transition: border-color 0.15s ease, width 0.15s ease;
}
.cx-search input::placeholder { color: var(--cx-text-dim); }
.cx-search input:focus {
  border-color: var(--cx-border-strong);
  width: 230px;
}

.cx-user {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 4px 9px 4px 4px;
  border-radius: 999px;
  background: var(--cx-bg-elev);
  border: 1px solid var(--cx-border);
  color: var(--cx-text);
  font-size: 0.82rem;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
}
.cx-user:hover { background: var(--cx-surface-2); color: var(--cx-text); }
/* Direct child only. The avatar is wrapped in .cx-av now, and this rule was
   also catching the decoration inside it - forcing the frame to 26px and
   rounding it off, which is what made it render as a second blob over the
   face. The component sizes its own parts. */
.cx-user > img {
  height: 26px;
  width: 26px;
  border-radius: 50%;
  object-fit: cover;
}

.cx-icon-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 34px;
  width: 34px;
  border-radius: 8px;
  background: var(--cx-bg-elev);
  border: 1px solid var(--cx-border);
  color: var(--cx-text-dim);
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.cx-icon-btn:hover { background: var(--cx-surface-2); color: var(--cx-text); }

/* mobile: collapse the nav into a scroll strip, shrink search */
@media (max-width: 991px) {
  .cx-search input { width: 130px; }
  .cx-search input:focus { width: 160px; }
  .cx-brand span { display: none; }
}
@media (max-width: 767px) {
  .cx-search { display: none; }
  .cx-nav a span { display: none; }
  .cx-nav a { padding: 6px 9px; }
}

/* ---------- cards & surfaces ---------- */

.card {
  background: var(--cx-surface) !important;
  border: 1px solid var(--cx-border) !important;
  border-radius: var(--cx-radius) !important;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3) !important;
}
.card .card {
  background: var(--cx-surface-2) !important;
}
.card-header {
  background: transparent !important;
  border-bottom: 1px solid var(--cx-border) !important;
}

h1, h2, h3, h4, h5, h6, .card-title { color: var(--cx-text); }
.text-secondary, .text-muted { color: var(--cx-text-dim) !important; }
hr.horizontal.dark { background-color: var(--cx-border); }

/* ---------- form controls ---------- */

.form-control,
.form-select,
textarea.form-control {
  background-color: var(--cx-bg-elev) !important;
  border: 1px solid var(--cx-border) !important;
  color: var(--cx-text) !important;
}
.form-control::placeholder { color: var(--cx-text-dim) !important; }
.form-control:focus,
.form-select:focus {
  border-color: var(--cx-border-strong) !important;
  background-color: var(--cx-bg-elev) !important;
  color: var(--cx-text) !important;
}
.form-control option,
.form-select option {
  background-color: var(--cx-surface);
  color: var(--cx-text);
}
label, .form-check-label, .form-group-label { color: var(--cx-text-dim); }

/* ---------- pill tabs (guild page, cog management) ---------- */

.nav-pills {
  background: transparent !important;
  gap: 4px;
}
.nav-pills .nav-link {
  background: var(--cx-surface) !important;
  border: 1px solid var(--cx-border) !important;
  border-radius: 8px !important;
  color: var(--cx-text-dim) !important;
  font-size: 0.85rem;
  font-weight: 600;
  padding: 7px 14px;
}
.nav-pills .nav-link:hover { color: var(--cx-text) !important; }
.nav-pills .nav-link.active {
  background: var(--cx-surface-2) !important;
  border-color: var(--cx-border-strong) !important;
  color: #fff !important;
}

/* ---------- tables ---------- */

.table { color: var(--cx-text); }
.table thead th {
  border-bottom: 1px solid var(--cx-border) !important;
  color: var(--cx-text-dim);
}
.table td, .table th { border-color: var(--cx-border) !important; }

/* ---------- dropdowns ---------- */

.dropdown-menu {
  background: #10264dfa !important;
  border: 1px solid var(--cx-border-strong) !important;
  border-radius: 10px !important;
}
.dropdown-item { color: var(--cx-text) !important; }
.dropdown-item:hover { background: var(--cx-surface-2) !important; }

/* ---------- footer ---------- */

.footer {
  border-top: 1px solid var(--cx-border);
  margin-top: 32px;
  padding-top: 14px !important;
}
.footer .nav-link { font-size: 0.78rem; }

/* One centred line for CUBIX, the attributions smaller underneath. The strip
   is full width because the footer sits outside .main-content. */
.footer.text-center { text-align: center; padding-bottom: 18px !important; }
.footer .cx-footer-line {
  margin: 0;
  font-size: 0.86rem;
  color: var(--cx-text);
}
.footer .cx-footer-line .cx-footer-name { font-weight: 700; letter-spacing: 0.02em; }
.footer .cx-footer-line .fa-code { opacity: 0.65; margin: 0 2px; font-size: 0.82rem; }
.footer .cx-footer-line a { font-weight: 600; }
.footer .cx-footer-links {
  margin: 5px 0 0;
  font-size: 0.78rem;
}
.footer .cx-footer-links a { color: var(--cx-text); opacity: 0.78; }
.footer .cx-footer-links a:hover { opacity: 1; text-decoration: underline; }
.footer .cx-footer-thanks {
  margin: 4px 0 0;
  font-size: 0.74rem;
  opacity: 0.6;
}
.footer .cx-footer-thanks a { color: inherit; }
.footer .cx-footer-thanks a:hover { opacity: 0.9; text-decoration: underline; }
.footer .cx-footer-dot { margin: 0 5px; opacity: 0.45; }

/* The credit under a module's description: quieter than the body text, but a
   line of its own rather than something tucked into the paragraph. */
.cx-card-credit {
  margin-top: 10px;
  padding-top: 8px;
  border-top: 1px solid var(--cx-border);
  font-size: 0.72rem;
  letter-spacing: 0.01em;
  opacity: 0.62;
}
.cx-card-credit a { color: inherit; font-weight: 600; }
.cx-card-credit a:hover { opacity: 1; text-decoration: underline; }

/* ==========================================================================
   Home page
   ========================================================================== */

.cx-hero {
  background:
    radial-gradient(1200px 300px at 12% -40%, rgba(255, 255, 255, 0.06), transparent 70%),
    var(--cx-surface) !important;
}
.cx-hero-avatar {
  height: 132px;
  width: 132px;
  border-radius: 24px;
  object-fit: cover;
  border: 1px solid var(--cx-border-strong);
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.45);
}
.cx-hero h1 {
  font-size: 1.9rem;
  font-weight: 800;
  letter-spacing: -0.02em;
}
.cx-hero-desc p:last-child { margin-bottom: 0; }

.cx-badge-soft {
  background: var(--cx-surface-2);
  border: 1px solid var(--cx-border);
  color: var(--cx-text-dim);
  font-weight: 600;
}

.cx-prefix {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 6px;
  background: var(--cx-bg-elev);
  border: 1px solid var(--cx-border);
  color: var(--cx-text);
  font-size: 0.8rem;
  cursor: pointer;
  transition: border-color 0.15s ease;
}
.cx-prefix:hover { border-color: var(--cx-border-strong); }

/* key/value rows */
.cx-kv {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 9px 12px;
  border-radius: 9px;
  background: var(--cx-bg-elev);
  border: 1px solid var(--cx-border);
}
.cx-kv-label {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  font-weight: 700;
  color: var(--cx-text-dim);
}
.cx-kv-value {
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--cx-text);
  text-align: right;
}

/* stat card icons keep their accent colour but sit flatter in the dark shell */
.icon.icon-shape { box-shadow: none !important; }

.btn-outline-secondary {
  border-color: var(--cx-border-strong) !important;
  color: var(--cx-text-dim) !important;
}
.btn-outline-secondary:hover {
  background: var(--cx-surface-2) !important;
  color: var(--cx-text) !important;
}

/* ==========================================================================
   Animated background + colour-scheme corrections
   ========================================================================== */

/* Everything real sits above the canvas. The canvas is position:fixed, so it
   paints above any static in-flow element no matter the DOM order - anything
   that has to be seen needs a position and a z-index of its own. The footer
   lives outside .main-content, so it needs its own. */
.cx-topbar { z-index: 1040; }
.main-content { position: relative; z-index: 1; }
.footer { position: relative; z-index: 1; }

/* Let the background layer show through the page surface. */
body,
body.g-sidenav-show {
  /* Transparent so the fixed .cx-circuit canvas underneath stays visible. */
  background: transparent !important;
}

/* Cards: same colour family as the backdrop, translucent, but noticeably more
   opaque than the background layer so text stays readable over moving traces. */
.card {
  background: rgba(0, 16, 135, 0.23) !important;
  border: 1px solid rgba(130, 175, 255, 0.16) !important;
}
.card .card { background: rgba(34, 62, 125, 0.09) !important; }
.cx-hero {
  background: rgba(0, 16, 135, 0.23) !important;
}

/* --- colour glitch fixes --- */

/* Argon injects a .moving-tab div into every .nav-pills; against the dark
   shell it rendered as a pale floating block behind the active tab. */
.nav-pills .moving-tab { display: none !important; }

/* Argon's leftover light-theme surfaces. */
.bg-gray-100, .bg-white { background-color: transparent !important; }
.card.card-chart { background: rgba(0, 16, 135, 0.23) !important; }

/* Inputs inside cards were picking up the light default. */
.input-group-text {
  background: var(--cx-bg-elev) !important;
  border: 1px solid var(--cx-border) !important;
  color: var(--cx-text-dim) !important;
}

/* Secondary buttons rendered near-white on near-white. */
.btn-secondary {
  background: var(--cx-surface-2) !important;
  border: 1px solid var(--cx-border-strong) !important;
  color: var(--cx-text) !important;
}

/* Guild header stat cluster: keep it from colliding on mid widths. */
#profile .cx-kv-label { white-space: nowrap; }

/* Links inherit the accent rather than Bootstrap's default blue-on-dark. */
a { color: #6ea8fe; }
a:hover { color: #9ec5fe; }


/* ---------- surface corrections against the star backdrop ---------- */

.cx-kv {
  background: rgba(90, 130, 220, 0.07) !important;
  border: 1px solid rgba(120, 160, 255, 0.09) !important;
}
.cx-prefix,
.cx-badge-soft {
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.08);
}
.form-control,
.form-select,
textarea.form-control,
.input-group-text {
  background-color: rgba(255, 255, 255, 0.04) !important;
  border: 1px solid rgba(255, 255, 255, 0.08) !important;
}
.nav-pills .nav-link {
  background: rgba(255, 255, 255, 0.04) !important;
  border: 1px solid rgba(255, 255, 255, 0.07) !important;
}
.nav-pills .nav-link.active {
  background: rgba(255, 255, 255, 0.10) !important;
  border-color: rgba(255, 255, 255, 0.16) !important;
}
.cx-user,
.cx-icon-btn,
.cx-search input {
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.09);
}

/* ==========================================================================
   Specificity guard

   themes/background_theme_dark.css targets cards as `div.card:not(.sidenav, ...)`,
   which outranks a bare `.card` even when both use !important. These selectors
   match that specificity so our surface colours reliably win, regardless of
   which background/sidenav theme the bot has configured.
   ========================================================================== */

div.card:not(.sidenav, .sidenav *) {
  background: rgba(0, 16, 135, 0.23) !important;
  border: 1px solid rgba(130, 175, 255, 0.16) !important;
}
div.card:not(.sidenav, .sidenav *) div.card:not(.sidenav, .sidenav *) {
  background: rgba(34, 62, 125, 0.09) !important;
}
div.card.cx-hero:not(.sidenav, .sidenav *) {
  background: rgba(0, 16, 135, 0.23) !important;
}
/* Card internals stay transparent so the parent's translucency shows through. */
div.card:not(.sidenav, .sidenav *) > div.card-body,
div.card:not(.sidenav, .sidenav *) > div.card-header,
div.card:not(.sidenav, .sidenav *) > div.card-footer {
  background-color: transparent !important;
}
body:not(.sidenav) {
  background: transparent !important;
}

/* ==========================================================================
   Third-party widget theming

   choices.min.css, easymde.min.css, flatpickr and dropzone are all loaded AFTER
   our stylesheet in base.html and ship light-theme defaults, which is why these
   controls rendered as white boxes. Choices and EasyMDE both expose CSS custom
   properties, so we retint them at the variable level where possible instead of
   fighting every internal selector.
   ========================================================================== */

/* ---------- Choices.js (multi-selects: prefixes, roles, disabled commands) ---------- */

.choices {
  --choices-bg-color: rgba(255, 255, 255, 0.04);
  --choices-bg-color-disabled: rgba(255, 255, 255, 0.02);
  --choices-bg-color-dropdown: #0d1420;
  --choices-text-color: var(--cx-text);
  --choices-keyline-color: rgba(255, 255, 255, 0.10);
  --choices-primary-color: rgba(90, 130, 220, 0.35);
  --choices-disabled-color: var(--cx-text-dim);
  margin-bottom: 0;
}

.choices__inner {
  background-color: rgba(255, 255, 255, 0.04) !important;
  border: 1px solid rgba(255, 255, 255, 0.10) !important;
  color: var(--cx-text) !important;
  border-radius: 8px !important;
}
.choices.is-focused .choices__inner,
.choices.is-open .choices__inner {
  border-color: rgba(130, 175, 255, 0.35) !important;
}
.choices__input,
.choices__input.choices__input--cloned {
  background-color: transparent !important;
  color: var(--cx-text) !important;
}
.choices__list--dropdown,
.choices__list[aria-expanded] {
  background-color: #0d1420 !important;
  border: 1px solid rgba(255, 255, 255, 0.14) !important;
  color: var(--cx-text) !important;
}
.choices__list--dropdown .choices__item,
.choices__list[aria-expanded] .choices__item {
  color: var(--cx-text) !important;
}
.choices__list--dropdown .choices__item--selectable.is-highlighted,
.choices__list[aria-expanded] .choices__item--selectable.is-highlighted {
  background-color: rgba(90, 130, 220, 0.22) !important;
}
/* Selected chips */
.choices__list--multiple .choices__item {
  background-color: rgba(90, 130, 220, 0.30) !important;
  border: 1px solid rgba(130, 175, 255, 0.30) !important;
  color: #fff !important;
}
.choices[data-type*="select-one"]::after {
  border-color: var(--cx-text-dim) transparent transparent !important;
}
.choices__placeholder { color: var(--cx-text-dim) !important; opacity: 1; }

/* The dark background theme forces .choices items to black text; undo that so
   options stay readable on the dark dropdown. */
.choices__item--choice,
.choices[data-type=select-one] .choices__item {
  color: var(--cx-text) !important;
}

/* ---------- EasyMDE / CodeMirror (Description, Custom Info) ---------- */

.EasyMDEContainer .CodeMirror {
  background: rgba(255, 255, 255, 0.04) !important;
  border: 1px solid rgba(255, 255, 255, 0.10) !important;
  color: var(--cx-text) !important;
  border-radius: 0 0 8px 8px !important;
}
.EasyMDEContainer .CodeMirror-cursor { border-left-color: var(--cx-text) !important; }
.EasyMDEContainer .CodeMirror-selected { background: rgba(90, 130, 220, 0.30) !important; }
.EasyMDEContainer .editor-toolbar {
  background: rgba(255, 255, 255, 0.05) !important;
  border: 1px solid rgba(255, 255, 255, 0.10) !important;
  border-bottom: none !important;
  border-radius: 8px 8px 0 0 !important;
}
.EasyMDEContainer .editor-toolbar button {
  color: var(--cx-text) !important;
}
.EasyMDEContainer .editor-toolbar button:hover,
.EasyMDEContainer .editor-toolbar button.active {
  background: rgba(255, 255, 255, 0.10) !important;
  border-color: rgba(255, 255, 255, 0.16) !important;
}
.EasyMDEContainer .editor-toolbar i.separator { border-color: rgba(255, 255, 255, 0.12) !important; }
.EasyMDEContainer .editor-statusbar { color: var(--cx-text-dim) !important; }
.EasyMDEContainer .editor-preview,
.EasyMDEContainer .editor-preview-side {
  background: #0d1420 !important;
  color: var(--cx-text) !important;
}

/* ---------- flatpickr (date pickers) ---------- */

.flatpickr-calendar {
  background: #0d1420 !important;
  border: 1px solid rgba(255, 255, 255, 0.14) !important;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.5) !important;
  color: var(--cx-text) !important;
}
.flatpickr-months .flatpickr-month,
.flatpickr-weekdays,
span.flatpickr-weekday {
  background: transparent !important;
  color: var(--cx-text-dim) !important;
  fill: var(--cx-text-dim) !important;
}
.flatpickr-day { color: var(--cx-text) !important; }
.flatpickr-day:hover { background: rgba(255, 255, 255, 0.08) !important; }
.flatpickr-day.selected { background: rgba(90, 130, 220, 0.45) !important; border-color: transparent !important; }
.flatpickr-day.flatpickr-disabled { color: rgba(255, 255, 255, 0.25) !important; }

/* ---------- dropzone ---------- */

.dropzone {
  background: rgba(255, 255, 255, 0.03) !important;
  border: 1px dashed rgba(255, 255, 255, 0.18) !important;
  color: var(--cx-text-dim) !important;
}

/* ---------- SweetAlert2 modals ---------- */

.swal2-popup {
  background: #0d1420 !important;
  color: var(--cx-text) !important;
  border: 1px solid rgba(255, 255, 255, 0.12);
}
.swal2-title, .swal2-html-container { color: var(--cx-text) !important; }

/* ==========================================================================
   Guild Overview tab
   ========================================================================== */

.cx-ov-banner {
  height: 150px;
  border-radius: 12px;
  background-size: cover;
  background-position: center;
  border: 1px solid rgba(255, 255, 255, 0.08);
}

.cx-ov-grid {
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
}
.cx-ov-stat {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  border-radius: 12px;
  background: rgba(90, 130, 220, 0.07);
  border: 1px solid rgba(120, 160, 255, 0.10);
}
.cx-ov-ico { font-size: 1.4rem; opacity: 0.95; }
.cx-ov-num {
  display: block;
  font-size: 1.4rem;
  font-weight: 800;
  line-height: 1.1;
  color: var(--cx-text);
}
.cx-ov-cap {
  display: block;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-weight: 700;
  color: var(--cx-text-dim);
}

.cx-ov-panel {
  padding: 16px;
  border-radius: 12px;
  background: rgba(90, 130, 220, 0.05);
  border: 1px solid rgba(120, 160, 255, 0.10);
}
.cx-ov-panel-head {
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 800;
  color: var(--cx-text-dim);
  margin-bottom: 12px;
}

.cx-ov-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 0;
  font-size: 0.9rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
.cx-ov-row:last-child { border-bottom: none; }
.cx-ov-row > span:first-child { color: var(--cx-text-dim); }
.cx-ov-row b { color: var(--cx-text); font-weight: 700; }

/* presence bar */
.cx-ov-bar {
  display: flex;
  height: 9px;
  width: 100%;
  border-radius: 999px;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.06);
}
.cx-ov-bar span { display: block; height: 100%; }
.cx-ov-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  margin-top: 12px;
  font-size: 0.82rem;
  color: var(--cx-text-dim);
}
.cx-ov-legend b { color: var(--cx-text); margin-left: 4px; }
.cx-dot {
  display: inline-block;
  height: 9px;
  width: 9px;
  border-radius: 50%;
  margin-right: 7px;
  vertical-align: 0px;
}

/* Merged guild hero.
   The hero card also wraps the tab panes, so anything painted on its own
   background sits behind the entire page, not just the header strip. The
   server banner used to be layered in here as a ::before, which is why every
   settings form and module page was reading through a picture of the server.
   The banner belongs to the Overview tab (`.cx-ov-banner`), where it is a
   deliberate element rather than wallpaper. */
/* No `overflow: hidden` here: it would clip the server-switcher dropdown to
   the height of the card, which on a module page is a single row. z-index
   lifts the card above the ones that follow it, or an open menu paints
   underneath them. */
.cx-guild-hero { position: relative; z-index: 5; }
.cx-guild-hero > * { position: relative; z-index: 1; }
.cx-guild-hero .card-body { background: transparent !important; }

/* ---------- merged guild hero: header + tabs + content in one card ---------- */

.cx-hero-tabs { flex: 0 0 auto; }
.cx-hero-tabs .nav-pills {
  margin: 0;
  flex-wrap: nowrap;
  justify-content: flex-start;
}
@media (max-width: 1400px) {
  .cx-hero-tabs { order: 3; width: 100%; margin-top: 10px; }
}

/* Panes are no longer individually carded - they're sections of the hero card. */
.cx-pane-body {
  padding: 20px 24px 24px;
  border-top: 1px solid rgba(255, 255, 255, 0.07);
}

/* The Modules pane pulls in third_parties_list.html, which brings its own card.
   Neutralise it so it doesn't nest a card inside the hero card. */
#third-parties > .card,
#third-parties > .card.card-chart {
  background: transparent !important;
  border: none !important;
  box-shadow: none !important;
  border-top: 1px solid rgba(255, 255, 255, 0.07) !important;
  border-radius: 0 !important;
}

/* Hero tabs sit next to the stat cluster, separated by a hairline rule. */
.cx-hero-tabs {
  flex: 0 0 auto;
  margin-left: auto;
  padding-right: 18px;
  margin-right: 4px;
  border-right: 1px solid rgba(255, 255, 255, 0.12);
}
@media (max-width: 1500px) {
  .cx-hero-tabs {
    order: 3;
    width: 100%;
    margin: 10px 0 0;
    padding: 10px 0 0;
    border-right: none;
    border-top: 1px solid rgba(255, 255, 255, 0.10);
  }
}

/* The Modules pane hosts third-party content; give it back a card surface so it
   reads as a panel rather than floating loose on the page. */
#third-parties > .card,
#third-parties > .card.card-chart {
  background: rgba(0, 16, 135, 0.23) !important;
  border: 1px solid rgba(130, 175, 255, 0.16) !important;
  border-radius: 14px !important;
  box-shadow: none !important;
  margin: 20px 24px 24px;
}

/* ==========================================================================
   Third-party module content

   `source_content` is whatever HTML a cog hands us. Cogs are written against
   stock Argon (or against nothing at all), so they arrive with light or flat
   grey surfaces and, often, a narrow centred column sized for a page that had
   a sidenav. Both look wrong in this shell: a grey slab in a blue translucent
   stack, floating in the middle of a 1900px page.

   These rules are deliberately broad. They are the shell asserting its own
   palette and page width over markup it does not control, so a module that
   nobody has themed still lands on-design.
   ========================================================================== */

/* Width. Bootstrap's `.container*` caps and any hand-rolled centred wrapper
   get released, so a module fills the page the way our own tabs do. The
   horizontal padding stays: `.row` inside a container relies on it to absorb
   its own negative margins. */
#third-party-content .container,
#third-party-content .container-sm,
#third-party-content .container-md,
#third-party-content .container-lg,
#third-party-content .container-xl,
#third-party-content .container-xxl,
#third-party-content .container-fluid {
  max-width: none !important;
  width: 100% !important;
  margin-left: 0 !important;
  margin-right: 0 !important;
}

/* The EmbedUtils editor is inlined here as a self-contained stylesheet scoped
   to #eu-editor. Its `.container` is a grid cell inside the embed preview, not
   a Bootstrap page wrapper, so the width release above would stretch the
   preview. Higher specificity, same !important, so this wins. */
#third-party-content #eu-editor .container {
  width: auto !important;
  max-width: none !important;
}

/* Surfaces. Anything a cog paints as grey/white/dark gets the nested-panel
   material instead. `.card` is already handled by the specificity guard
   above; these are the utility classes and generic panel names cogs reach
   for when they are not using a card. */
#third-party-content .panel,
#third-party-content .well,
#third-party-content .bg-light,
#third-party-content .bg-white,
#third-party-content .bg-dark,
#third-party-content .bg-secondary,
#third-party-content .bg-gray,
#third-party-content .bg-gray-100,
#third-party-content .bg-gray-200,
#third-party-content .bg-gray-300,
#third-party-content .list-group-item {
  background: var(--cx-panel-2) !important;
  border-color: var(--cx-panel-2-bd) !important;
  color: var(--cx-text) !important;
}

/* Card headers inside a module: hairline, not a filled grey band. */
#third-party-content .card > .card-header,
#third-party-content .card > .card-footer {
  background: transparent !important;
  border-color: var(--cx-panel-2-bd) !important;
}

/* Read-only text blocks (prompt bodies, transcripts, JSON dumps) are the
   usual source of a flat grey rectangle. */
#third-party-content pre,
#third-party-content code:not(.cx-prefix),
#third-party-content .form-control[readonly],
#third-party-content textarea[readonly] {
  background: var(--cx-panel-3) !important;
  border: 1px solid var(--cx-panel-3-bd) !important;
  color: var(--cx-text) !important;
}
#third-party-content pre {
  border-radius: 10px;
  padding: 12px 14px;
}

/* Tables ship light striping and light borders. */
#third-party-content .table {
  color: var(--cx-text) !important;
  --bs-table-bg: transparent;
  --bs-table-striped-bg: rgba(255, 255, 255, .03);
  --bs-table-striped-color: var(--cx-text);
  --bs-table-hover-bg: rgba(255, 255, 255, .05);
  --bs-table-hover-color: var(--cx-text);
}
#third-party-content .table > :not(caption) > * > * {
  border-bottom-color: var(--cx-panel-2-bd) !important;
  background-color: transparent;
}
#third-party-content .table thead th {
  color: var(--cx-text-dim) !important;
  border-bottom-color: var(--cx-panel-bd) !important;
}

/* Modules that lay their own sections out in one column get to use the width
   they were just handed, on screens wide enough to want it. */
@media (min-width: 1500px) {
  #third-party-content .cx-tp-cols {
    column-count: 2;
    column-gap: 20px;
  }
  #third-party-content .cx-tp-cols > * {
    break-inside: avoid;
    -webkit-column-break-inside: avoid;
  }
}

/* ==========================================================================
   Owner-only log console (/admin/logs)
   ========================================================================== */

.cx-log-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 10px 12px;
  margin-bottom: 10px;
  border-radius: 12px;
  background: var(--cx-panel-2);
  border: 1px solid var(--cx-panel-2-bd);
}
.cx-log-levels { display: flex; gap: 4px; flex-wrap: wrap; }
.cx-log-lvl {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 0;
  padding: 4px 10px;
  border-radius: 8px;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .04em;
  cursor: pointer;
  color: var(--cx-text-dim);
  background: var(--cx-panel-3);
  border: 1px solid var(--cx-panel-3-bd);
  user-select: none;
}
.cx-log-lvl input { accent-color: #5aa9ff; margin: 0; }
.cx-log-lvl:hover { color: var(--cx-text); }
/* The level a row carries is the fastest thing to scan for, so each keeps its
   colour in the filter bar as well as in the stream. */
.cx-log-lvl[data-level="WARNING"] { color: #f0aa3c; }
.cx-log-lvl[data-level="ERROR"],
.cx-log-lvl[data-level="CRITICAL"] { color: #ff8b8b; }
.cx-log-search { flex: 1 1 220px; min-width: 160px; max-width: 460px; }

.cx-log-view {
  height: min(760px, calc(100vh - 330px));
  min-height: 320px;
  overflow-y: auto;
  overflow-x: auto;
  padding: 8px 0;
  border-radius: 12px;
  background: rgba(2, 5, 16, .55);
  border: 1px solid var(--cx-panel-2-bd);
  font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
  font-size: .76rem;
  line-height: 1.5;
}
.cx-log-empty { padding: 18px; text-align: center; color: var(--cx-text-dim); }

.cx-log-row {
  display: grid;
  grid-template-columns: 74px 68px minmax(90px, 210px) minmax(0, 1fr);
  gap: 10px;
  padding: 2px 12px;
  border-left: 2px solid transparent;
  white-space: pre-wrap;
  word-break: break-word;
}
.cx-log-row:hover { background: rgba(255, 255, 255, .04); }
.cx-log-time { color: var(--cx-text-dim); opacity: .7; }
.cx-log-level { font-weight: 700; letter-spacing: .03em; }
.cx-log-name { color: #8ea6ff; opacity: .85; overflow: hidden; text-overflow: ellipsis; }
.cx-log-msg { color: var(--cx-text); }

.cx-log-row.lvl-DEBUG    { color: var(--cx-text-dim); }
.cx-log-row.lvl-DEBUG .cx-log-level { color: #7f8da3; }
.cx-log-row.lvl-INFO .cx-log-level { color: #5aa9ff; }
.cx-log-row.lvl-WARNING  { border-left-color: rgba(240, 170, 60, .7);
                           background: rgba(240, 170, 60, .05); }
.cx-log-row.lvl-WARNING .cx-log-level { color: #f0aa3c; }
.cx-log-row.lvl-ERROR,
.cx-log-row.lvl-CRITICAL { border-left-color: rgba(255, 90, 90, .75);
                           background: rgba(255, 90, 90, .07); }
.cx-log-row.lvl-ERROR .cx-log-level,
.cx-log-row.lvl-CRITICAL .cx-log-level { color: #ff8b8b; }

/* Tracebacks are folded away: an unfolded one is 20+ lines and would bury the
   surrounding context, which is usually what you are actually reading. */
.cx-log-tb { grid-column: 4; margin: 3px 0 5px; }
.cx-log-tb summary {
  cursor: pointer;
  color: #ff8b8b;
  font-size: .72rem;
  opacity: .85;
  list-style: none;
}
.cx-log-tb summary::-webkit-details-marker { display: none; }
.cx-log-tb summary::before { content: "▸ "; }
.cx-log-tb[open] summary::before { content: "▾ "; }
.cx-log-tb pre {
  margin: 5px 0 0;
  padding: 9px 11px;
  border-radius: 8px;
  background: rgba(0, 0, 0, .38);
  border: 1px solid rgba(255, 90, 90, .22);
  color: #ffb3b3;
  font-size: .72rem;
  overflow-x: auto;
  white-space: pre;
}

/* A break in the stream: the buffer rolled past where this page had got to. */
.cx-log-gap {
  margin: 6px 12px;
  padding: 4px 10px;
  border-radius: 7px;
  text-align: center;
  font-size: .7rem;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: #f0aa3c;
  background: rgba(240, 170, 60, .09);
  border: 1px dashed rgba(240, 170, 60, .38);
}

@media (max-width: 900px) {
  /* Four columns do not fit; the logger name is the one worth dropping. */
  .cx-log-row { grid-template-columns: 66px 60px minmax(0, 1fr); }
  .cx-log-name { display: none; }
  .cx-log-tb { grid-column: 3; }
}

/* Proper back button (replaces the 🔙 emoji in third-party page headings). */
/* Module page switcher.

   A module with more than one page renders this row so its pages read as one
   thing. The same rules live in `dashboard_helpers.BASE_CSS` for cogs that
   emit it, but several (LevelUp) ship their own templates and never include
   it - navigation chrome is the shell's job, so it is defined here too and
   works regardless. */
.dz-subnav {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 16px;
}
.dz-subnav-item {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 14px;
  border-radius: 10px;
  font-size: .84rem;
  font-weight: 600;
  text-decoration: none;
  color: var(--cx-text) !important;
  opacity: .68;
  background: var(--cx-panel-3);
  border: 1px solid var(--cx-panel-3-bd);
}
.dz-subnav-item:hover {
  opacity: 1;
  background: rgba(255, 255, 255, .09);
  color: var(--cx-text) !important;
}
.dz-subnav-item.active {
  opacity: 1;
  background: rgba(108, 140, 255, .22);
  border-color: rgba(130, 175, 255, .40);
}
.dz-subnav-item i { opacity: .75; }

/* Module breadcrumb.

   The back arrow is a control; the path beside it is text. Previously the
   module name lived *inside* the back button, so a sub-page read as a button
   welded to a heading, with `/ Settings` trailing off it at the heading's own
   (much larger) size. Splitting them means one affordance to go back and one
   plain path that says where you are. */
.cx-crumb {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 9px;
  margin: 0;
  font-size: 1.02rem;
  font-weight: 700;
  line-height: 1.4;
}

/* Square, icon-only: it is the only thing on the line that does something. */
.cx-back {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 30px;
  height: 30px;
  border-radius: 9px;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.12);
  color: var(--cx-text) !important;
  text-decoration: none;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.cx-back:hover {
  background: rgba(255, 255, 255, 0.11);
  border-color: rgba(130, 175, 255, 0.35);
  color: var(--cx-text) !important;
}
.cx-back i { font-size: 1.05rem; opacity: 0.85; }

/* Ancestors are dimmed links, the current page is plain and full strength. */
.cx-crumb-link {
  color: var(--cx-text-dim) !important;
  text-decoration: none;
}
.cx-crumb-link:hover { color: var(--cx-text) !important; }
.cx-crumb-guild {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}
.cx-crumb-guild img {
  height: 24px;
  width: 24px;
  border-radius: 50%;
  object-fit: cover;
}
.cx-crumb-sep {
  color: var(--cx-text-dim);
  opacity: 0.5;
  font-weight: 400;
}
.cx-crumb-now { color: var(--cx-text); }

/* ==========================================================================
   Mobile fixes
   ========================================================================== */

@media (max-width: 991px) {
  /* Wide tables (commands, queue, search results) must scroll rather than
     force the page wider than the viewport, which caused the overlapping
     columns and the cog sidebar bleeding over the content. */
  .table-responsive,
  .card-body > .table,
  .plc-q,
  #commands-container table {
    display: block;
    width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }

  /* The commands page puts the cog list in a fixed-width column that overlapped
     the table on narrow screens; stack it instead. */
  #commands-container .col-md-3,
  #commands-container .col-md-9,
  #commands-container .col-lg-2,
  #commands-container .col-lg-10 {
    width: 100% !important;
    max-width: 100% !important;
    flex: 0 0 100% !important;
  }

  /* Long command names / descriptions should wrap instead of stretching a cell. */
  td, th { word-break: break-word; }

  /* Guild hero: stack cleanly instead of squeezing four clusters onto one line. */
  .cx-guild-hero .card-body > .d-flex { gap: 12px !important; }
  .cx-guild-hero .d-flex.align-items-center.gap-4 { gap: 14px !important; }

  /* Player: full-width controls, no horizontal overflow. */
  .plc-controls .plc-btn { flex: 0 0 auto; }
  .plc-seek { flex-wrap: wrap; }
  .plc-seek input[type=range] { flex: 1 1 100%; order: 3; }
}

@media (max-width: 575px) {
  .cx-topbar { padding: 0 10px; gap: 4px; }
  .main-content { padding-left: 4px; padding-right: 4px; }
  .container-fluid { padding-left: 10px; padding-right: 10px; }
  .cx-ov-grid { grid-template-columns: 1fr 1fr; }
  .plc-now { padding: 14px; }
  .plc-art { height: 84px; width: 84px; }
}

/* Module pages: match the hero card's horizontal extent so the header and the
   content panel line up instead of the panel sitting inset. */
#third-parties > .card,
#third-parties > .card.card-chart {
  margin-left: 0 !important;
  margin-right: 0 !important;
}
#third-party-content { width: 100%; }

/* Give the player room to breathe on wide screens rather than leaving a
   centred column with dead space either side. */
.plc { max-width: 1500px; margin: 0 auto; }
.plc-panels { grid-template-columns: 1fr; }
@media (min-width: 1200px) {
  .plc-panels { grid-template-columns: 1fr 1fr 1fr; }
}

/* ---------- server switcher in the guild header ----------
   Deliberately owns none of Bootstrap's dropdown classes. The theme puts
   `will-change: animation, box-shadow` and `backface-visibility: hidden` on
   every `.dropdown-menu`, which promotes it to its own GPU layer; on this menu
   that composited layer rendered see-through even though its computed opacity
   was 1 and its background fully opaque. Own markup, own classes, own toggle. */
.cx-gs { position: relative; display: inline-block; }
.cx-guild-switch-toggle {
  color: inherit;
  text-decoration: none;
  display: block;
  cursor: pointer;
}
.cx-guild-switch-toggle:hover { color: inherit; }
.cx-guild-switch-toggle:hover .cx-guild-switch-caret { opacity: 1; }
.cx-guild-switch-caret {
  font-size: .8em;
  margin-left: 6px;
  opacity: .45;
  vertical-align: 1px;
  transition: opacity .15s ease;
}

.cx-gs-menu {
  display: none;
  /* Fixed, and reparented to <body> when opened. Every ancestor here is a
     stacking context of some kind - the hero card sets one, `.card-body` sets
     another - and the cards below are translucent glass
     (`.card { background: rgba(24, 48, 105, .10) }`), so a menu trapped behind
     one is visible *through* it with the card's own text painted on top. That
     is the "transparent menu". With no ancestors, there is nothing to trap it. */
  position: fixed;
  top: 0;
  left: 0;
  min-width: 260px;
  max-width: 320px;
  padding: 5px 0;
  z-index: 1080;
  background: #10264dfa;
  border: 1px solid rgba(255, 255, 255, .14);
  border-radius: 10px;
  box-shadow: 0 14px 38px rgba(0, 0, 0, .6);
  text-align: left;
  font-size: .875rem;
  font-weight: 400;
}
/* The menu is moved out to <body>, so it can no longer be selected as a
   child of its trigger; it carries the open state itself. */
.cx-gs-menu.open { display: block; }

.cx-guild-switch-list { max-height: 320px; overflow-y: auto; overflow-x: hidden; }

.cx-gs-item {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 7px 14px;
  color: var(--cx-text, #e6ebf5);
  text-decoration: none;
  white-space: nowrap;
  line-height: 1.3;
}
.cx-gs-item:hover { background: rgba(255, 255, 255, .07); color: inherit; }
.cx-gs-item.active { background: rgba(90, 169, 255, .16); font-weight: 600; }
.cx-gs-item .text-truncate { max-width: 200px; overflow: hidden; text-overflow: ellipsis; }
.cx-gs-all { font-size: .82rem; opacity: .85; }
.cx-gs-sep { height: 1px; margin: 5px 0; background: rgba(255, 255, 255, .10); }

.cx-gs-search {
  width: calc(100% - 24px);
  margin: 2px 12px 6px;
  padding: 5px 9px;
  font-size: .8rem;
  color: var(--cx-text, #e6ebf5);
  background: rgba(0, 0, 0, .35);
  border: 1px solid rgba(255, 255, 255, .14);
  border-radius: 7px;
}
.cx-gs-search:focus { outline: none; border-color: rgba(130, 175, 255, .5); }


/* ==========================================================================
   Notifications (toastr)
   Loaded after toastr.min.css so these win. toastr paints its own palette and
   a base64 icon per level; both are replaced here so a notification looks
   like the rest of the shell instead of like the library's defaults.
   ========================================================================== */

#toast-container {
  top: 16px;
  right: 16px;
  width: min(380px, calc(100vw - 32px));
}
#toast-container > div,
#toast-container > div:hover {
  position: relative;
  width: 100%;
  max-width: 100%;
  padding: 12px 34px 12px 42px;
  margin: 0 0 9px;
  border: 1px solid var(--cx-border-strong, rgba(255, 255, 255, .14));
  border-left: 3px solid #6c8cff;
  border-radius: var(--cx-radius, 12px);
  background-color: #151a30;
  background-position: 14px center;
  background-size: 17px;
  background-repeat: no-repeat;
  color: var(--cx-text, #e6e9ef);
  font-size: .85rem;
  line-height: 1.4;
  opacity: 1;
  box-shadow: 0 14px 38px rgba(0, 0, 0, .55);
}
#toast-container > div:hover { box-shadow: 0 16px 42px rgba(0, 0, 0, .65); }

/* The library ships the level icons as background images; recolour by
   swapping them for ones that match this palette. */
#toast-container > .toast-success {
  border-left-color: #38d39f;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%2338d39f'%3E%3Cpath d='M12 2a10 10 0 100 20 10 10 0 000-20zm-1.2 14.4l-4.2-4.2 1.7-1.7 2.5 2.5 5.4-5.4 1.7 1.7-7.1 7.1z'/%3E%3C/svg%3E");
}
#toast-container > .toast-error,
#toast-container > .toast-danger {
  border-left-color: #ff6b6b;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23ff6b6b'%3E%3Cpath d='M12 2a10 10 0 100 20 10 10 0 000-20zm5 13.6L15.6 17 12 13.4 8.4 17 7 15.6 10.6 12 7 8.4 8.4 7 12 10.6 15.6 7 17 8.4 13.4 12 17 15.6z'/%3E%3C/svg%3E");
}
#toast-container > .toast-warning {
  border-left-color: #ffb454;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23ffb454'%3E%3Cpath d='M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z'/%3E%3C/svg%3E");
}
#toast-container > .toast-info {
  border-left-color: #6c8cff;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%236c8cff'%3E%3Cpath d='M12 2a10 10 0 100 20 10 10 0 000-20zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z'/%3E%3C/svg%3E");
}

#toast-container .toast-title { font-weight: 700; margin-bottom: 2px; }
#toast-container .toast-message { word-break: break-word; }
#toast-container .toast-message a { color: #b7c6ff; }

#toast-container .toast-close-button {
  position: absolute;
  top: 8px;
  right: 9px;
  width: 22px;
  height: 22px;
  padding: 0;
  border-radius: 6px;
  color: var(--cx-text, #e6e9ef);
  font-size: 1rem;
  font-weight: 400;
  line-height: 20px;
  text-align: center;
  text-shadow: none;
  opacity: .45;
}
#toast-container .toast-close-button:hover,
#toast-container .toast-close-button:focus {
  opacity: 1;
  color: inherit;
  background: rgba(255, 255, 255, .10);
}

#toast-container .toast-progress {
  height: 2px;
  background-color: currentColor;
  opacity: .35;
  border-radius: 0 0 var(--cx-radius, 12px) var(--cx-radius, 12px);
}

/* Full width on a phone, where a 380px card would hang off the edge. */
@media (max-width: 480px) {
  #toast-container {
    top: 10px;
    right: 10px;
    left: 10px;
    width: auto;
  }
  #toast-container > div,
  #toast-container > div:hover { width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  #toast-container > div { transition: none !important; }
}


/* ==========================================================================
   Profile
   ========================================================================== */

/* Tall enough that the banner keeps a sane aspect. At 170px against ~1900
   wide it was 11:1, so `cover` zoomed a 2.5:1 banner nearly 2x and showed a
   sliver; this brings it back to roughly 6:1. The content sits at the bottom,
   so the top of the card is clean banner. */
.cx-profile {
  position: relative;
  overflow: hidden;
  min-height: 320px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}
@media (max-width: 900px) { .cx-profile { min-height: 0; } }

/* The banner is the card's background. It goes on a pseudo-element because
   `.card` sets `background` with !important, and that shorthand would wipe out
   a background-image set on the element itself. */
.cx-profile.cx-has-banner::before,
.cx-profile.cx-has-banner::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
}
.cx-profile.cx-has-banner::before {
  z-index: 0;
  background-image: var(--cx-banner);
  background-size: cover;
  background-position: center;
}
/* Just enough to keep the text readable over any picture. */
.cx-profile.cx-has-banner::after {
  z-index: 1;
  background: linear-gradient(to bottom,
              rgba(14, 19, 28, .28) 0%,
              rgba(14, 19, 28, .62) 55%,
              rgba(14, 19, 28, .90) 100%);
}
.cx-profile > .cx-profile-body { position: relative; z-index: 2; }

/* One row: avatar, identity, badges, joined date, activity - all level with
   each other. Everything used to stack into a column beside the avatar, which
   is what made this card so tall. */
.cx-profile-body {
  display: flex;
  align-items: center;
  gap: 22px;
  flex-wrap: wrap;
  padding: 22px 28px;
}
@media (max-width: 900px) {
  .cx-profile-body { padding: 18px; gap: 16px; }
}

.cx-profile-avatar { position: relative; flex: none; width: 124px; height: 124px; }
@media (max-width: 640px) { .cx-profile-avatar { width: 92px; height: 92px; } }
.cx-profile-avatar > img:first-child {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
  border: 5px solid var(--cx-bg-elev, #0c1017);
  background: var(--cx-bg-elev, #0c1017);
  box-shadow: 0 12px 30px rgba(0, 0, 0, .55);
}
/* Sized to its content so the things after it sit right alongside, rather
   than being pushed to the far edge by a greedy column. */
.cx-profile-id { min-width: 0; flex: 0 1 auto; display: flex; flex-direction: column; gap: 4px; }
/* Each line is its own baseline: name/pills/badges on one, handle/date/id on
   the other, so everything on the left reads as aligned columns of text. */
.cx-id-line { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.cx-id-sub { gap: 14px; }
.cx-profile-id h1 { font-size: 1.65rem; line-height: 1.2; }
@media (max-width: 640px) { .cx-profile-id h1 { font-size: 1.3rem; } }

.cx-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 11px;
  border-radius: 999px;
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .02em;
}
.cx-pill-owner {
  color: #ffd97a;
  background: rgba(251, 191, 36, .14);
  border: 1px solid rgba(251, 191, 36, .38);
}

.cx-badges { display: inline-flex; gap: 7px; flex-wrap: wrap; flex: 0 0 auto; }
.cx-badge-ico {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 9px;
  font-size: .92rem;
  background: rgba(255, 255, 255, .06);
  border: 1px solid var(--cx-border, rgba(255, 255, 255, .07));
}

.cx-profile-meta {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  flex: 0 0 auto;
  font-size: .78rem;
  color: var(--cx-text-dim, #9aa4b2);
}
.cx-profile-meta i { margin-right: 5px; opacity: .8; }

.cx-count {
  font-size: .68rem;
  font-weight: 800;
  padding: 2px 9px;
  border-radius: 999px;
  color: var(--cx-text-dim, #9aa4b2);
  background: rgba(255, 255, 255, .07);
  border: 1px solid var(--cx-border, rgba(255, 255, 255, .07));
}

/* ---------- server cards ---------- */

.cx-guild-grid {
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 320px), 1fr));
}

.cx-guild-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 0;
  padding: 14px 16px;
  border-radius: var(--cx-radius, 12px);
  background: #10264d69;
  border: 1px solid var(--cx-border, rgba(255, 255, 255, .07));
  /* The role colour reads down the left edge, so scanning the list for the
     servers you actually run takes no reading at all. */
  border-left: 3px solid rgba(255, 255, 255, .10);
  transition: border-color .15s, background .15s, transform .08s;
}
.cx-guild-card:hover { background: var(--cx-surface-2, #141b26); transform: translateY(-1px); }
.cx-guild-card.cx-role-owner { border-left-color: #fbbf24; }
.cx-guild-card.cx-role-admin { border-left-color: #a78bfa; }
.cx-guild-card.cx-role-moderator { border-left-color: #3ba55d; }

.cx-guild-top { display: flex; align-items: center; gap: 11px; min-width: 0; }
.cx-guild-ico {
  width: 40px;
  height: 40px;
  border-radius: 11px;
  object-fit: cover;
  flex: none;
  background: rgba(255, 255, 255, .07);
}
.cx-guild-ico-ph {
  display: grid;
  place-items: center;
  font-size: 1rem;
  font-weight: 800;
  color: var(--cx-text-dim, #9aa4b2);
}
.cx-guild-name { min-width: 0; flex: 1 1 auto; }
.cx-guild-name b {
  display: block;
  font-size: .92rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cx-guild-sub {
  display: block;
  font-size: .72rem;
  color: var(--cx-text-dim, #9aa4b2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cx-role-tag {
  flex: none;
  padding: 3px 9px;
  border-radius: 999px;
  font-size: .64rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--cx-text-dim, #9aa4b2);
  background: rgba(255, 255, 255, .06);
  border: 1px solid var(--cx-border, rgba(255, 255, 255, .07));
}
.cx-role-owner .cx-role-tag { color: #ffd97a; border-color: rgba(251, 191, 36, .35); }
.cx-role-admin .cx-role-tag { color: #c7b5ff; border-color: rgba(167, 139, 250, .35); }
.cx-role-moderator .cx-role-tag { color: #86e0a8; border-color: rgba(59, 165, 93, .35); }

.cx-guild-facts { display: flex; flex-wrap: wrap; gap: 6px; }
.cx-fact {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 9px;
  border-radius: 8px;
  font-size: .72rem;
  color: var(--cx-text-dim, #9aa4b2);
  background: rgba(0, 0, 0, .28);
  border: 1px solid var(--cx-border, rgba(255, 255, 255, .07));
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cx-fact i { opacity: .85; }

.cx-guild-go {
  align-self: flex-start;
  font-size: .76rem;
  font-weight: 700;
  color: #8ea6ff;
  text-decoration: none;
}
.cx-guild-go:hover { color: #b7c6ff; text-decoration: underline; }
.cx-guild-go i { margin-left: 3px; }

/* ---------- avatar + Discord frame, reusable ---------- */

.cx-av { position: relative; display: inline-block; flex: none; line-height: 0; }
.cx-av-img {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
  background: var(--cx-bg-elev, #0c1017);
}
/* Decorations are drawn on a canvas wider than the avatar they frame, so the
   art has to overhang rather than sit inside the circle. */
.cx-av-deco {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 138%;
  height: 138%;
  transform: translate(-50%, -50%);
  pointer-events: none;
}
.cx-av-dot {
  position: absolute;
  /* The avatar is a circle inside a square box, so its lower-right corner is
     empty space - anchoring there left the dot hanging off the edge, on top
     of the decoration ring. 7% brings it back onto the circle's own rim.
     Sized with the ring included; content-box plus 30% made it a third of the
     face again in border alone. */
  right: 7%;
  bottom: 7%;
  width: 20%;
  height: 20%;
  border-radius: 50%;
  border: 2.5px solid var(--cx-surface, #0e131c);
  box-sizing: border-box;
}

/* The small size is the topbar's. A decoration overhangs its avatar, so at
   30px it spills onto the name beside it unless the box is given the room -
   hence the margin, which matches the overhang exactly. */
.cx-av-sm { width: 28px; height: 28px; margin: 0 5px; }
.cx-av-sm .cx-av-deco { width: 132%; height: 132%; }
/* Proportionally larger than on the big avatar: at 28px a 20% dot is under
   6px and reads as a smudge. */
.cx-av-sm .cx-av-dot { width: 34%; height: 34%; right: 3%; bottom: 3%; border-width: 2px; }
.cx-av-status { display: block; margin-top: 3px; font-size: .68rem; font-weight: 700; }
.cx-av-status i { font-size: .5rem; vertical-align: 2px; margin-right: 3px; }

/* ---------- presence + activity on the profile ---------- */

.cx-presence {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 3px 11px;
  border-radius: 999px;
  font-size: .72rem;
  font-weight: 700;
  background: rgba(255, 255, 255, .06);
  border: 1px solid var(--cx-border, rgba(255, 255, 255, .07));
}
.cx-presence i { font-size: .52rem; }

.cx-activity {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 14px;
  border-radius: var(--cx-radius, 12px);
  background: rgba(0, 0, 0, .28);
  border: 1px solid var(--cx-border, rgba(255, 255, 255, .07));
  max-width: 460px;
}
.cx-activity-art {
  width: 46px;
  height: 46px;
  border-radius: 9px;
  object-fit: cover;
  flex: none;
  background: rgba(255, 255, 255, .06);
}
.cx-activity-txt { min-width: 0; }
.cx-activity-verb {
  display: block;
  font-size: .64rem;
  font-weight: 800;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--cx-text-dim, #9aa4b2);
}
.cx-activity-name {
  display: block;
  font-size: .88rem;
  font-weight: 700;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cx-activity-sub {
  display: block;
  font-size: .75rem;
  color: var(--cx-text-dim, #9aa4b2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---------- per-cog activity ---------- */

.cx-mod-grid {
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 240px), 1fr));
}
.cx-mod-card {
  min-width: 0;
  padding: 14px 16px;
  border-radius: var(--cx-radius, 12px);
  background: #10264d69;
  border: 1px solid var(--cx-border, rgba(255, 255, 255, .07));
}
.cx-mod-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.cx-mod-head b { font-size: .9rem; }
.cx-mod-ico {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  flex: none;
  border-radius: 9px;
  border: 1px solid transparent;
  font-size: .88rem;
}
.cx-mod-rows { display: flex; flex-direction: column; gap: 5px; }
.cx-mod-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  font-size: .8rem;
}
.cx-mod-label { color: var(--cx-text-dim, #9aa4b2); }
.cx-mod-value { font-weight: 700; font-variant-numeric: tabular-nums; }
.cx-up { color: #38d39f; }
.cx-down { color: #ff6b6b; }

/* ---------- header stat strip ---------- */

.cx-profile-stats {
  display: flex;
  gap: 9px;
  flex-wrap: wrap;
  /* Grows into the slack rather than being pushed to the far edge by it.
     `margin-left:auto` only relocated the gap - the tiles sat hard right and
     left the middle of the banner as empty as before. */
  flex: 1 1 auto;
}
.cx-profile-stat {
  /* Each tile takes an equal share of whatever width the strip was given, so
     the row is filled instead of leaving one large hole. */
  flex: 1 1 0;
  min-width: 84px;
  padding: 8px 14px;
  border-radius: 11px;
  text-align: center;
  background: rgba(0, 0, 0, .38);
  border: 1px solid var(--cx-border, rgba(255, 255, 255, .07));
}
.cx-profile-stat b {
  display: block;
  font-size: 1.15rem;
  line-height: 1.15;
  font-variant-numeric: tabular-nums;
}
.cx-profile-stat span {
  font-size: .62rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--cx-text-dim, #9aa4b2);
}
@media (max-width: 900px) {
  .cx-profile-stat { flex: 1 1 70px; min-width: 70px; padding: 7px 11px; }
}

/* ---------- home: your servers ---------- */

/* ==========================================================================
   Server directory (landing page)

   The bot's own server list, shown to signed-out visitors too. Each entry is a
   card built around the server's banner and icon, so the grid reads as a
   directory of places rather than a table of numbers.
   ========================================================================== */

.cx-srv-sub { font-size: .74rem; color: var(--cx-text-dim); }

.cx-srv-tools { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

/* All / Mine toggle, only rendered when the viewer shares servers with the bot. */
.cx-srv-seg {
  display: inline-flex;
  padding: 2px;
  border-radius: 9px;
  background: var(--cx-panel-3);
  border: 1px solid var(--cx-panel-3-bd);
}
.cx-srv-segbtn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 12px;
  border: none;
  border-radius: 7px;
  background: transparent;
  color: var(--cx-text-dim);
  font-size: .74rem;
  font-weight: 700;
  cursor: pointer;
}
.cx-srv-segbtn:hover { color: var(--cx-text); }
.cx-srv-segbtn.active {
  color: #fff;
  background: rgba(108, 140, 255, .28);
  box-shadow: inset 0 0 0 1px rgba(130, 175, 255, .35);
}
.cx-srv-segcount { opacity: .7; font-size: .68rem; }

.cx-srv-search { position: relative; display: flex; align-items: center; }
.cx-srv-search i {
  position: absolute;
  left: 10px;
  font-size: .74rem;
  color: var(--cx-text-dim);
  pointer-events: none;
}
.cx-srv-search input {
  height: 32px;
  width: 200px;
  padding: 0 10px 0 28px;
  border-radius: 9px;
  background: var(--cx-panel-3);
  border: 1px solid var(--cx-panel-3-bd);
  color: var(--cx-text);
  font-size: .78rem;
  outline: none;
}
.cx-srv-search input:focus { border-color: var(--cx-panel-bd); }

.cx-srv-grid {
  display: grid;
  gap: 16px;
  /* Wide enough for the icon, the name and a two-up figure row to sit
     comfortably on one card; below this the name and its date wrap and the
     whole header goes crooked. */
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 390px), 1fr));
}

.cx-srv {
  display: flex;
  flex-direction: column;
  min-width: 0;
  overflow: hidden;
  border-radius: var(--cx-radius, 12px);
  background: var(--cx-panel-2);
  border: 1px solid var(--cx-panel-2-bd);
  transition: transform .1s ease, border-color .15s ease, background .15s ease;
}
.cx-srv:hover {
  transform: translateY(-2px);
  background: rgba(90, 130, 220, .12);
  border-color: var(--cx-panel-bd);
}
/* A server the viewer is already in. */
.cx-srv.is-shared { border-color: rgba(108, 140, 255, .38); }

.cx-srv-banner {
  position: relative;
  height: 76px;
  background-size: cover;
  background-position: center;
  border-bottom: 1px solid var(--cx-panel-2-bd);
}
/* Servers with no banner still need the same silhouette, or the grid jumps. */
.cx-srv-banner.is-blank {
  background-image: linear-gradient(135deg, rgba(90, 130, 220, .22), rgba(10, 18, 40, .5));
}
.cx-srv-badge,
.cx-srv-boost {
  position: absolute;
  top: 8px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 8px;
  border-radius: 999px;
  font-size: .64rem;
  font-weight: 800;
  letter-spacing: .03em;
  text-transform: uppercase;
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}
.cx-srv-badge {
  left: 8px;
  color: #c3d0ff;
  background: rgba(20, 30, 70, .72);
  border: 1px solid rgba(130, 175, 255, .45);
}
.cx-srv-boost {
  right: 8px;
  color: #ff8ae2;
  background: rgba(40, 12, 40, .66);
  border: 1px solid rgba(255, 115, 250, .38);
}

.cx-srv-head {
  display: flex;
  /* The icon is lifted over the banner, so centring the row on it dragged the
     name up with it. Align to the top and let the name sit on its own line. */
  align-items: flex-start;
  gap: 13px;
  min-width: 0;
  padding: 11px 18px 0;
}
.cx-srv-ico {
  /* `.cx-srv-banner` is positioned (it carries the badges), and a positioned
     sibling paints above a static one regardless of document order - which is
     why the avatar was disappearing behind the banner instead of sitting on
     top of it. Positioning the avatar too, with a z-index, puts it back in
     front. */
  position: relative;
  z-index: 1;
  width: 58px;
  height: 58px;
  flex: none;
  border-radius: 16px;
  object-fit: cover;
  background: #0a1020;
  /* Overlaps the lower third of the banner. */
  margin-top: -30px;
  border: 3px solid #0a1020;
}
.cx-srv-ico-ph {
  display: grid;
  place-items: center;
  font-size: 1.05rem;
  font-weight: 800;
  color: var(--cx-text-dim);
}
/* Nudged down so the name's baseline lines up with the icon's lower half
   rather than with its lifted top edge. */
.cx-srv-id { min-width: 0; flex: 1 1 auto; padding-top: 6px; }
.cx-srv-id b {
  display: block;
  font-size: .95rem;
  line-height: 1.3;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cx-srv-id span {
  display: block;
  margin-top: 2px;
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .02em;
  color: var(--cx-text-dim);
  /* One line: "Since" and the date were breaking apart on narrow cards and
     pushing the header out of square. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Two lines, so one wordy server does not make its row taller than the rest. */
.cx-srv-desc {
  margin: 10px 18px 0;
  font-size: .74rem;
  line-height: 1.45;
  color: var(--cx-text-dim);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Two labelled tiles rather than a bare "192 ● 14" line, which read as
   leftovers floating under the description. */
.cx-srv-figs {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  margin: 12px 18px 0;
}
.cx-srv-figs span {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 7px 10px;
  border-radius: 9px;
  background: var(--cx-panel-3);
  border: 1px solid var(--cx-panel-3-bd);
}
.cx-srv-figs b {
  color: var(--cx-text);
  font-size: .92rem;
  line-height: 1.2;
  font-variant-numeric: tabular-nums;
}
.cx-srv-figs em {
  font-style: normal;
  font-size: .6rem;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--cx-text-dim);
}
/* A server whose presence counts are unavailable gets one full-width tile
   instead of a lopsided pair. */
.cx-srv-figs:has(> span:only-child) { grid-template-columns: 1fr; }
.cx-srv-dot {
  display: inline-block;
  width: 7px;
  height: 7px;
  margin-right: 6px;
  vertical-align: 1px;
  border-radius: 50%;
  background: #38d39f;
  box-shadow: 0 0 0 3px rgba(56, 211, 159, .16);
}

.cx-srv-foot {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: auto;
  padding: 13px 18px 15px;
}
.cx-srv-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 12px;
  border-radius: 9px;
  font-size: .74rem;
  font-weight: 700;
  text-decoration: none;
  color: var(--cx-text) !important;
  background: var(--cx-panel-3);
  border: 1px solid var(--cx-panel-3-bd);
}
.cx-srv-btn:hover { background: rgba(255, 255, 255, .1); }
.cx-srv-btn.primary {
  color: #fff !important;
  background: rgba(108, 140, 255, .3);
  border-color: rgba(130, 175, 255, .45);
}
.cx-srv-btn.primary:hover { background: rgba(108, 140, 255, .45); }

.cx-srv-none {
  margin: 18px 0 0;
  text-align: center;
  font-size: .8rem;
  color: var(--cx-text-dim);
}

@media (max-width: 575px) {
  .cx-srv-tools { width: 100%; }
  .cx-srv-search { flex: 1 1 auto; }
  .cx-srv-search input { width: 100%; }
}

/* ---------- per-server bot appearance ---------- */

/* This sits inside the guild hero card, which already paints a surface, so it
   stays a light layer on top rather than a second opaque slab. */
.cx-botface {
  border-radius: var(--cx-radius, 12px);
  background: var(--cx-panel-2);
  border: 1px solid var(--cx-panel-2-bd);
  overflow: hidden;
  margin-bottom: 20px;
}
.cx-botface-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
  padding: 13px 18px;
  border-bottom: 1px solid var(--cx-border, rgba(255, 255, 255, .07));
}
.cx-botface-head h5 { margin: 0; font-size: .88rem; font-weight: 700; }
.cx-botface-head h5 i { margin-right: 7px; opacity: .65; }
.cx-botface-head span { font-size: .73rem; color: var(--cx-text-dim, #9aa4b2); }

.cx-botface-body {
  display: grid;
  gap: 20px;
  padding: 18px;
  align-items: start;
  grid-template-columns: minmax(0, 300px) minmax(0, 1fr);
}
@media (max-width: 900px) { .cx-botface-body { grid-template-columns: minmax(0, 1fr); } }

/* A stand-in for the profile card members see in this server. */
/* Deliberately the darkest well on the page - it stands in for a Discord
   profile popout - but tinted into the shell's blue family, not flat black. */
.cx-botface-card {
  border-radius: var(--cx-radius, 12px);
  background: rgba(4, 10, 32, .55);
  border: 1px solid var(--cx-panel-2-bd);
  overflow: hidden;
}
.cx-botface-banner {
  position: relative;
  height: 108px;
  background: rgba(255, 255, 255, .05) center/cover no-repeat;
  display: flex;
  align-items: center;
  justify-content: center;
}
.cx-botface-empty {
  font-size: .68rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--cx-text-dim, #9aa4b2);
  opacity: .5;
}
.cx-botface-face {
  position: relative;
  height: 34px;
  padding: 0 16px;
}
.cx-botface-face img {
  position: absolute;
  left: 16px;
  top: -38px;
  width: 76px;
  height: 76px;
  border-radius: 50%;
  object-fit: cover;
  border: 5px solid #0b0f16;
  background: #0b0f16;
}
.cx-botface-tag {
  position: absolute;
  right: 9px;
  top: 9px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: .6rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--cx-text-dim, #9aa4b2);
  background: rgba(0, 0, 0, .5);
  border: 1px solid var(--cx-border, rgba(255, 255, 255, .07));
}
.cx-botface-meta { padding: 4px 16px 16px; }
.cx-botface-meta strong { display: block; font-size: .98rem; font-weight: 700; }
.cx-botface-sub {
  display: block;
  font-size: .72rem;
  color: var(--cx-text-dim, #9aa4b2);
  margin-top: 1px;
}
.cx-botface-bio {
  margin: 9px 0 0;
  font-size: .76rem;
  line-height: 1.45;
  color: var(--cx-text-dim, #9aa4b2);
  white-space: pre-wrap;
  word-break: break-word;
}
.cx-botface-bio:empty { display: none; }

.cx-botface-fields { display: flex; flex-direction: column; gap: 15px; min-width: 0; }
.cx-botface-assets {
  display: grid;
  gap: 15px 22px;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
@media (max-width: 1250px) {
  .cx-botface-assets { grid-template-columns: minmax(0, 1fr); }
}
.cx-botface-row { min-width: 0; }
.cx-botface-lbl {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 7px;
}
.cx-botface-lbl span { font-size: .8rem; font-weight: 650; }
.cx-botface-lbl em {
  font-style: normal;
  font-size: .69rem;
  color: var(--cx-text-dim, #9aa4b2);
  opacity: .8;
}
.cx-botface-acts { display: flex; gap: 7px; flex-wrap: wrap; align-items: center; }
.cx-botface-file {
  font-size: .69rem;
  color: var(--cx-text-dim, #9aa4b2);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cx-botface-input {
  width: 100%;
  padding: 9px 12px;
  border-radius: 9px;
  font-size: .82rem;
  color: var(--cx-text, #e6e9ef);
  background: rgba(0, 0, 0, .3);
  border: 1px solid var(--cx-border, rgba(255, 255, 255, .07));
}
.cx-botface-input:focus {
  outline: none;
  border-color: var(--cx-border-strong, rgba(255, 255, 255, .14));
  background: rgba(0, 0, 0, .45);
}

.cx-botface-foot {
  display: flex;
  align-items: center;
  gap: 11px;
  flex-wrap: wrap;
  padding-top: 4px;
}
.cx-botface-foot span { font-size: .69rem; color: var(--cx-text-dim, #9aa4b2); opacity: .75; }
.cx-botface-save {
  padding: 8px 18px;
  border-radius: 9px;
  font-size: .8rem;
  font-weight: 700;
  cursor: pointer;
  color: var(--cx-text, #e6e9ef);
  background: rgba(255, 255, 255, .1);
  border: 1px solid var(--cx-border-strong, rgba(255, 255, 255, .14));
}
.cx-botface-save:hover { background: rgba(255, 255, 255, .17); }

/* Small pill buttons, shared with the file picker label. */
.cx-mini {
  padding: 5px 11px;
  border-radius: 8px;
  font-size: .72rem;
  font-weight: 650;
  cursor: pointer;
  color: var(--cx-text-dim, #9aa4b2);
  background: rgba(255, 255, 255, .05);
  border: 1px solid var(--cx-border, rgba(255, 255, 255, .07));
}
.cx-mini:hover { background: rgba(255, 255, 255, .12); color: var(--cx-text, #e6e9ef); }
.cx-mini-danger:hover { color: #ff9d9d; border-color: rgba(255, 107, 107, .45); }
.cx-mini-file { display: inline-flex; align-items: center; gap: 6px; margin: 0; }
.cx-mini-file i { opacity: .7; }
/* The native control is unstyleable, so the label stands in for it. */
.cx-mini-file input[type="file"] {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

/* ---------- commands page: migration notice and permission scope ----------
   Both sit above the search box. They use the same translucent surfaces as
   every other card rather than a solid alert, so they read as part of the page
   instead of something bolted on top of it. */
.cx-migrating,
.cx-scoped {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 11px 14px;
  margin-bottom: 10px;
  border-radius: 10px;
  font-size: .84rem;
  line-height: 1.5;
  color: var(--cx-text, #e6e9ef);
  background: var(--cx-panel-2, rgba(90, 130, 220, .07));
  border: 1px solid var(--cx-panel-2-bd, rgba(120, 160, 255, .10));
}
.cx-migrating i,
.cx-scoped i { margin-top: 2px; opacity: .7; flex: none; }
.cx-migrating b { font-weight: 600; }
.cx-migrating code {
  padding: .05em .35em;
  border-radius: 4px;
  background: rgba(255, 255, 255, .08);
  font-size: .92em;
}

/* The scope notice is a quieter, single-line variant with its toggle pushed
   to the far end. */
.cx-scoped {
  align-items: center;
  justify-content: space-between;
  color: var(--cx-text-dim, #93a1bd);
  font-size: .8rem;
}
.cx-scoped span { display: inline-flex; align-items: center; gap: 8px; }
.cx-scoped a {
  flex: none;
  margin-left: 12px;
  white-space: nowrap;
  color: var(--cx-text, #e6e9ef);
  text-decoration: underline;
  text-underline-offset: 2px;
  opacity: .8;
}
.cx-scoped a:hover { opacity: 1; }
