/* Unified admin chrome (body.spx-app). Applied to every staff-admin screen so CRM and
   legacy Hosting / Accounts / Products share one sidebar and page shell. Resellers keep
   the older skin. */

/* AdminLTE ships `h1,h2,h3,h4,h5,h6,.h1..{font-family:'Source Sans Pro',sans-serif}`
   and the layout only ever loads Source Sans 3 from Google. Source Sans Pro is
   not on the machine either, so every heading in the app fell through to the
   generic sans-serif -- Arial on Windows -- while the text underneath it was
   Source Sans 3. Measured on 50 of 87 rendered pages, 152 elements.
   Same specificity as AdminLTE's rule (0,0,1); this file loads after it. */
h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
  font-family: "Source Sans 3", "Segoe UI", Helvetica, Arial, sans-serif;
}

/* Bootstrap sizes these as a percentage of whatever they land in -- `small`
   and `.small` at 85%, `code` and `kbd` at 90% -- and this app sets parent
   sizes in px all over the place, so one rule produced a different size on
   every screen. Measured across 88 rendered pages: 11.05px (85% of 13) on 928
   elements, 11.9px (85% of 14) on 211, 10.2px (85% of 12) on 10, 11.7px and
   12.6px on 101 more. Pinning them in px ends the compounding; 11px is what
   85%-of-13 already rendered, so nothing visibly moves. */
small, .small {
  font-size: 11px;
}

code, kbd, samp {
  font-size: 12px;
}

body.spx-app {
  background: var(--t-tint-slate, #e7ebf2) !important;
  font-family: "Source Sans 3", "Segoe UI", Helvetica, Arial, sans-serif;
  font-size: 14px;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: var(--t-tint-blue-ink, #243041);
}

body.spx-app .wrapper,
body.spx-app .content-wrapper,
body.spx-app .content-wrapper#bgimage {
  background: var(--t-tint-slate, #e7ebf2) !important;
  background-image: none !important;
}

body.spx-app .main-footer { display: none; }

@media (min-width: 768px) {
  body.spx-app .main-header { display: none !important; }
  body.spx-app .main-sidebar,
  body.spx-app .main-sidebar.ic-sidebar { padding-top: 0 !important; }
}

/* Keep the dark IC sidebar even when unified admin chrome (spx-app) is on.
   Earlier white/purple CRM chrome overrode public/sidebar.css and washed out the portal. */
body.spx-app .main-sidebar.ic-sidebar {
  background: #111111 !important;
  box-shadow: 4px 0 24px rgba(0, 0, 0, 0.45);
  border-right: 0;
}

body.spx-app .ic-brand {
  background: #0a0a0a !important;
  border-bottom: 1px solid rgba(194, 61, 138, 0.35);
}

body.spx-app .ic-sidebar .user-panel {
  background: linear-gradient(180deg, #1a1a1a 0%, #111111 100%) !important;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}

body.spx-app .ic-sidebar .user-panel .info p,
body.spx-app .ic-sidebar .user-panel .info a {
  color: #c9d4e3 !important;
}

body.spx-app .ic-sidebar .user-panel .info a:hover {
  color: #fff !important;
}

body.spx-app .sidebar-menu > li.header {
  color: var(--t-tint-slate-ink, #6f7c90) !important;
  background: transparent !important;
}

body.spx-app .sidebar-menu > li > a {
  color: #c5d0de !important;
  border-left: 0 !important;
}

body.spx-app .sidebar-menu > li > a > .fa {
  color: var(--t-tint-blue-ink, #8aa0b8) !important;
}

body.spx-app .sidebar-menu > li.active > a,
body.spx-app .sidebar-menu > li:hover > a,
body.spx-app .sidebar-menu > li.menu-open > a {
  background: rgba(255, 255, 255, 0.08) !important;
  color: #fff !important;
  border-left: 0 !important;
}

body.spx-app .sidebar-menu > li.active > a {
  background: rgba(255, 255, 255, 0.12) !important;
  box-shadow: inset 3px 0 0 #7b4bb0;
}

body.spx-app .sidebar-menu > li:hover > a > .fa,
body.spx-app .sidebar-menu > li.active > a > .fa,
body.spx-app .sidebar-menu > li.menu-open > a > .fa {
  color: #fff !important;
}

body.spx-app .sidebar-menu .treeview-menu {
  background: #0d0d0d !important;
}

body.spx-app .sidebar-menu .treeview-menu > li > a {
  color: var(--t-tint-blue-ink, #9aa8bb) !important;
}

body.spx-app .sidebar-menu .treeview-menu > li.active > a,
body.spx-app .sidebar-menu .treeview-menu > li > a:hover {
  background: rgba(255, 255, 255, 0.10) !important;
  color: #fff !important;
  border-radius: 6px;
}

body.spx-app .sidebar-menu .treeview-menu .treeview > a {
  font-weight: 600;
}

body.spx-app .sidebar-menu .treeview-menu .treeview-menu {
  padding-left: 8px;
  background: #0a0a0a !important;
}

body.spx-app .sidebar-search input.form-control {
  background: #1c1c1c !important;
  border: 0 !important;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.06);
  color: #e6edf5 !important;
}

body.spx-app .sidebar-search input.form-control:focus {
  background: #242424 !important;
  box-shadow: inset 0 0 0 1px #3c8dbc;
}

.spx-page {
  padding: 18px 22px 40px;
}

.spx-page-head {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 18px;
}

.spx-page-head h1 {
  margin: 0;
  font-size: 32px;
  font-weight: 700;
  color: var(--t-ink, #2c3340);
  letter-spacing: 0.02em;
}

.spx-kicker {
  color: var(--t-faint, #8a96a6);
  font-size: 13px;
}

.spx-page-glyph {
  width: 34px;
  height: 34px;
  border-radius: 6px;
  background: #6b2d8b;
  color: #fff;
  text-align: center;
  line-height: 34px;
}

.spx-page-actions { margin-left: auto; }

.spx-btn-primary,
body.spx-app .btn.spx-btn-primary {
  background: #5b2c86;
  border-color: #5b2c86;
  color: #fff;
  font-weight: 600;
  border-radius: 6px;
  padding: 8px 16px;
}

body.spx-app .btn.spx-btn-primary:hover {
  background: #4a216e;
  color: #fff;
}

.spx-kpi-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 18px;
}

/* One tile definition for every KPI strip (helpdesk, leads, billing). Splynx tiles are
   compact: a small grey caption and a large count, no dead space below. */
.spx-kpi {
  flex: 1 1 170px;
  display: block;
  background: var(--t-surface, #fff);
  border: 1px solid var(--t-line, #e2e8f0);
  border-radius: 4px;
  padding: 12px 14px;
  color: var(--t-ink, #2c3340);
  position: relative;
}

.spx-kpi:hover { text-decoration: none; color: var(--t-ink, #2c3340); box-shadow: 0 4px 14px rgba(30,40,60,0.08); }

/* A strip of one does not stretch.
   flex-grow shares the leftover width between the tiles, which is right for
   every strip that has some: the dashboard has 7, billing 13, the IPv4 pages 4,
   and they land near 200-380px each. Down 24h carries a single tile, so that
   one tile took the entire row -- measured at 1564px on a 1620px window, with
   the caption and the count in the left corner and the icon (position: absolute;
   right: 12px) pinned 1533px away from them: a page-wide card holding one
   number. Sizing a lone tile to its own content is the whole fix.
   Left to grow on a phone, where one card filling the column is what every
   other pane does and 260px would just leave a gap beside it. */
@media (min-width: 768px) {
  .spx-kpi-row > .spx-kpi:only-child {
    flex: 0 1 260px;
  }
}

/* Pinned to the corner rather than floated: a floated icon sits in the text flow and
   pushes the caption onto a second line, which clips it in a narrow tile. */
.spx-kpi i {
  position: absolute;
  top: 12px;
  right: 12px;
  font-size: 18px;
  opacity: 0.85;
}
.spx-kpi span.spx-kpi-label, .spx-kpi span.spx-kpi-head { padding-right: 24px; }

.spx-kpi span {
  display: block;
  color: var(--t-muted, #6b7789);
  font-size: 13px;
  margin-bottom: 6px;
}

.spx-kpi b {
  display: block;
  font-size: 34px;
  line-height: 1.1;
  font-weight: 700;
}

.spx-kpi em {
  display: block;
  margin-top: 10px;
  font-style: normal;
  color: var(--t-accent-text, #2f80ed);
  font-size: 13px;
}

.spx-kpi-ok b, .spx-kpi-ok i { color: var(--t-tint-green-ink, #27ae60); }
.spx-kpi-info b, .spx-kpi-info i { color: var(--t-accent-text, #2f80ed); }
.spx-kpi-warn b, .spx-kpi-warn i { color: var(--t-tint-amber-ink, #e67e22); }
.spx-kpi-lead b, .spx-kpi-lead i { color: var(--t-tint-purple-ink, #8e44ad); }
.spx-kpi-bad b, .spx-kpi-bad i { color: var(--t-danger-text, #c0392b); }

/* The em on every other tile is a "View" link, so it is painted accent blue. The
   supplier-credit tile does not link anywhere -- its em is the working, and blue
   would read as clickable. */
.spx-kpi-credit em { color: var(--t-muted, #6b7789); }
.spx-kpi-tile { margin-bottom: 12px; }

/* Caption + count, used by the helpdesk and leads strips. Both are spans inside
   .spx-kpi, so they have to out-specify the `.spx-kpi span` rule above or the count
   renders at caption size. */
.spx-kpi span.spx-kpi-label, .spx-kpi span.spx-kpi-head {
  display: block;
  color: var(--t-muted, #6b7789);
  font-size: 12px;
  font-weight: 600;
  margin-bottom: 4px;
}
.spx-kpi span.spx-kpi-value {
  display: block;
  font-size: 30px;
  line-height: 1.1;
  font-weight: 700;
  color: var(--t-ink, #1f1f2e);
  margin-bottom: 0;
}

/* Ticket status colours match the pills used in the list. */
.spx-kpi-new span.spx-kpi-value { color: var(--t-accent-text, #2f80ed); }
.spx-kpi-work_in_progress span.spx-kpi-value { color: var(--t-tint-amber-ink, #e67e22); }
.spx-kpi-resolved span.spx-kpi-value { color: var(--t-tint-green-ink, #27ae60); }
.spx-kpi-waiting_customer span.spx-kpi-value,
.spx-kpi-waiting_agent span.spx-kpi-value { color: var(--t-tint-purple-ink, #8e44ad); }
.spx-kpi-process_cancellation span.spx-kpi-value { color: var(--t-muted, #6b7789); }
.spx-kpi-vhost span.spx-kpi-value { color: var(--t-brand-text, #5b2c86); }
.spx-kpi-unlinked span.spx-kpi-value { color: var(--t-tint-amber-ink, #b45309); }
.spx-kpi-open span.spx-kpi-value { color: var(--t-ink, #1f1f2e); }
.spx-kpi-attention span.spx-kpi-value { color: var(--t-danger-text, #c0392b); }
.spx-kpi-me span.spx-kpi-value { color: var(--t-brand-text, #5b2c86); }
.spx-kpi-watching span.spx-kpi-value { color: var(--t-muted, #6b7789); }
.spx-kpi-age-hot span.spx-kpi-value { color: var(--t-danger-text, #c0392b); }

.spx-section-label {
  margin: 0 0 8px;
  color: var(--t-muted, #6b7789);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.spx-age-row .spx-kpi,
.spx-status-row .spx-kpi {
  flex: 1 1 140px;
}

.spx-age-row span.spx-kpi-value,
.spx-status-row span.spx-kpi-value {
  font-size: 24px;
}

.spx-age-hot { color: var(--t-danger-text, #c0392b); font-weight: 600; }
.spx-age-warn { color: var(--t-tint-amber-ink, #d35400); font-weight: 600; }
.spx-age-warm { color: var(--t-tint-amber-ink, #e67e22); }

.spx-dash-tickets td:nth-child(1) { white-space: nowrap; }
.spx-dash-tickets .spx-sub { margin-top: 2px; }

.spx-inline-period { display: inline-flex; align-items: center; margin: 0 12px 0 0; }
.spx-inline-period label { margin: 0; font-weight: 600; color: var(--t-muted, #6b7789); }

.spx-title .spx-sub { font-size: 14px; font-weight: 600; margin-left: 8px; text-transform: none; letter-spacing: 0; }

.spx-shortcuts {
  background: var(--t-surface, #fff);
  border: 1px solid var(--t-line, #e2e8f0);
  border-radius: 4px;
  padding: 12px 16px 16px;
  margin-bottom: 18px;
}

.spx-shortcuts h3 {
  margin: 0 0 10px;
  font-size: 14px;
  font-weight: 700;
  color: var(--t-ink, #2c3340);
}

.spx-shortcut-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 8px 16px;
}

.spx-shortcut-grid a {
  color: var(--t-accent-text, #2f80ed);
  font-size: 13px;
}

.spx-shortcut-grid a i {
  color: var(--t-tint-purple-ink, #7b3fa8);
  width: 18px;
}

.spx-widget {
  background: var(--t-surface, #fff);
  border: 1px solid var(--t-line, #e2e8f0);
  border-radius: 4px;
  margin-bottom: 18px;
}

.spx-widget-head {
  padding: 10px 14px;
  border-bottom: 1px solid #eef2f6;
  font-weight: 700;
  color: var(--t-ink, #2c3340);
}

.spx-widget-head i { color: var(--t-tint-purple-ink, #7b3fa8); margin-right: 6px; }

.spx-widget-link {
  float: right;
  font-weight: 600;
  font-size: 13px;
  color: var(--t-accent-text, #2f80ed);
}

.spx-widget-foot { padding: 8px 14px 12px; }

.spx-widget-count {
  display: inline-block;
  margin-left: 8px;
  padding: 1px 8px;
  border-radius: 10px;
  background: var(--t-tint-slate, #f3eafb);
  color: var(--t-tint-purple-ink, #7b3fa8);
  font-size: 12px;
  font-weight: 700;
}

.spx-widget-body {
  overflow: auto;
  max-height: 420px;
}

.spx-widget-body .table {
  margin-bottom: 0;
}

.spx-widget-empty {
  padding: 16px 14px;
  color: var(--t-muted, #6b7789);
  font-size: 13px;
}

.spx-kv {
  width: 100%;
  margin: 0;
}

.spx-kv td {
  padding: 8px 14px;
  border-bottom: 1px solid #f1f4f8;
  font-size: 13px;
}

.spx-kv tr:last-child td { border-bottom: 0; }

.spx-kv td:last-child {
  text-align: right;
  font-weight: 700;
  color: var(--t-ink, #2c3340);
}

.spx-kv a { color: var(--t-accent-text, #2f80ed); }

.spx-activity {
  list-style: none;
  margin: 0;
  padding: 8px 0;
  max-height: 420px;
  overflow: auto;
}

.spx-activity li {
  display: flex;
  gap: 10px;
  padding: 8px 14px;
  border-bottom: 1px solid #f1f4f8;
}

.spx-activity a { color: var(--t-accent-text, #2f80ed); font-weight: 600; }

body.spx-app .content-wrapper .box.spx-card,
body.spx-app .content-wrapper .spx-widget {
  border: 1px solid var(--t-line, #e2e8f0) !important;
  box-shadow: none !important;
  border-radius: 4px !important;
}

/* Splynx renders record titles in normal case at a modest size. */
body.spx-app .spx-title {
  font-size: 22px;
  letter-spacing: 0;
  text-transform: none;
  font-weight: 700;
  margin: 2px 0 0;
}

body.spx-app .spx-pill {
  border-radius: 3px;
  padding: 3px 8px;
}

body.spx-app .content-header {
  background: transparent;
  padding: 16px 22px 0;
}

body.spx-app .content-header > .breadcrumb { display: none; }

body.spx-app .nav-tabs.spx-customer-tabs {
  background: var(--t-surface, #fff);
  border: 1px solid var(--t-line, #e2e8f0);
  border-bottom: 0;
  padding: 0 8px;
  margin: 0 15px;
}

body.spx-app .nav-tabs.spx-customer-tabs > li > a {
  border: 0;
  margin: 0;
  padding: 14px 16px;
  color: var(--t-muted, #5b6b7c);
}

body.spx-app .nav-tabs.spx-customer-tabs > li.active > a {
  color: var(--t-brand-text, #5b2c86);
  border: 0;
  border-bottom: 3px solid var(--t-brand, #5b2c86);
  background: transparent;
  border-top: 0;
}

body.spx-app .tab-content {
  background: var(--t-surface, #fff);
  border: 1px solid var(--t-line, #e2e8f0);
  margin: 0 15px 20px;
  padding: 16px;
}

.spx-profile-bar {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 16px;
  margin-bottom: 0;
  background: var(--t-surface, #fff);
  border: 1px solid var(--t-line, #e2e8f0);
  border-bottom: 0;
  padding: 16px 18px 10px;
}
.spx-profile-bar h1 {
  margin: 0;
  font-size: 26px;
  font-weight: 700;
}
.spx-profile-bar h1 small { color: var(--t-faint, #8a96a6); font-size: 16px; font-weight: 500; }
.spx-profile-actions { display: flex; gap: 8px; }
.spx-profile-tabs {
  background: var(--t-surface, #fff);
  border: 1px solid var(--t-line, #e2e8f0);
  border-top: 0;
  margin: 0 0 0;
  padding: 0 8px;
}
.spx-profile-tabs > li > a {
  border: 0 !important;
  color: var(--t-muted, #5b6b7c);
  padding: 12px 14px;
  font-weight: 600;
}
.spx-profile-tabs > li.active > a {
  color: var(--t-brand-text, #5b2c86) !important;
  background: transparent !important;
  border: 0 !important;
  border-bottom: 3px solid var(--t-brand, #5b2c86) !important;
}
.spx-profile-body {
  background: var(--t-tint-slate, #e8edf3);
  padding-top: 16px;
}

/* ---------- Helpdesk: ticket view ---------- */

.spx-ticket-bar {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid #e6ebf3;
  background: var(--t-surface-2, #fbfcfe);
  flex-wrap: wrap;
}
.spx-ticket-actions { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.spx-sub { color: var(--t-faint, #8a96a6); font-size: 12px; }

.spx-thread { padding: 12px 16px 16px; }
.spx-thread-filters {
  display: flex;
  gap: 6px;
  margin: 0 0 12px;
  flex-wrap: wrap;
}
/* Only .is-active was ever styled, so Notes and All fell through to Bootstrap's
   bare .btn -- which carries color:#333 and a near-white background. Measured in
   dark mode at 1.05:1: the labels were there, and invisible. */
.spx-thread-filters .js-spx-thread-filter {
  background: var(--t-surface-2, #fbfcfe);
  border: 1px solid var(--t-line, #d9e0ea);
  color: var(--t-ink-2, #334155);
}
.spx-thread-filters .js-spx-thread-filter:hover,
.spx-thread-filters .js-spx-thread-filter:focus {
  background: var(--t-tint-slate, #eef2f6);
  color: var(--t-ink, #1f2937);
}
.spx-thread-filters .js-spx-thread-filter.is-active {
  background: var(--t-brand, #5b2c86);
  border-color: var(--t-brand, #5b2c86);
  color: #fff;
}
.spx-ticket-status-form { margin: 0; }
.spx-ticket-status-select {
  min-width: 170px;
  height: 32px;
}
.spx-commit-status { width: auto; min-width: 180px; display: inline-block; }
.spx-msg {
  border: 1px solid var(--t-line, #e6ebf3);
  border-radius: 4px;
  margin-bottom: 8px;
  background: var(--t-surface, #fff);
}
.spx-msg-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  border-bottom: 1px solid var(--t-line-soft, #f0f3f8);
  background: var(--t-surface-2, #fbfcfe);
  flex-wrap: wrap;
}
.spx-msg-head strong { margin-left: 4px; }
.spx-msg-tools { display: flex; align-items: center; gap: 10px; }
.spx-msg-tools a { color: var(--t-faint, #8a96a6); }
.spx-msg-tools a:hover { color: var(--t-brand-text, #5b2c86); }
.spx-msg-body { padding: 8px 12px; overflow-x: auto; line-height: 1.45; }
.spx-msg-body p { margin: 0 0 6px; }
.spx-msg-body p:last-child { margin-bottom: 0; }
.spx-msg-agent { border-left: 3px solid var(--t-brand, #5b2c86); }
.spx-msg-note { border-left: 3px solid #f0ad4e; background: var(--t-tint-slate, #fffdf6); }
.spx-msg-note .spx-msg-body { padding: 6px 12px; font-size: 13px; }
.spx-msg-edit { padding: 12px; border-top: 1px solid var(--t-line-soft, #f0f3f8); }
.spx-msg-edit-actions { margin-top: 8px; display: flex; gap: 8px; }

.spx-composer {
  border: 1px solid #d9e0ea;
  border-radius: 4px;
  background: var(--t-surface, #fff);
  padding: 12px;
}
.spx-composer-tabs { display: flex; gap: 6px; margin-bottom: 10px; }
.spx-composer-tab {
  background: var(--t-tint-slate, #f1f4f9);
  border: 1px solid #dde4ee;
  color: var(--t-muted, #5b6b7c);
  font-weight: 600;
}
.spx-composer-tab.is-active { background: #5b2c86; border-color: #5b2c86; color: #fff; }
.spx-composer-actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.spx-menu-btn {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: 0;
  padding: 6px 20px;
  color: var(--t-tint-slate-ink, #333);
}
.spx-menu-btn:hover { background: var(--t-tint-slate, #f5f5f5); color: var(--t-brand-text, #5b2c86); }

.spx-requester-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.spx-user-tickets { margin-top: 10px; }
.spx-user-ticket { padding: 6px 0; border-bottom: 1px dashed var(--t-line-soft, #eef1f6); }
.spx-link { color: var(--t-brand-text, #5b2c86); font-weight: 600; cursor: pointer; }

.spx-ticket-services .box-title { font-size: 14px; }
.spx-ticket-services .box-body { padding-top: 8px; }
.spx-staff-notes .box-title { font-size: 14px; }
.spx-staff-notes .box-body { padding-top: 8px; }
.spx-staff-note-list { max-height: 360px; overflow-y: auto; margin: 8px 0 0; }
.spx-staff-note {
  border: 1px solid #e6ebf3;
  border-left: 3px solid #f0ad4e;
  border-radius: 4px;
  padding: 8px 10px;
  margin-bottom: 8px;
  background: var(--t-tint-slate, #fffdf6);
}
.spx-staff-note.is-target {
  box-shadow: 0 0 0 2px #5b2c86;
  background: var(--t-tint-slate, #faf7fd);
}
.spx-staff-note-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  margin-bottom: 4px;
}
.spx-staff-note-head strong { margin-left: 4px; }
.spx-staff-note-snippet {
  margin: 0;
  font-size: 13px;
  color: var(--t-ink, #243447);
  line-height: 1.4;
}
.spx-staff-note .js-spx-staff-note-toggle {
  padding-left: 0;
  font-weight: 600;
}
.spx-staff-note-full {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px dashed #ead9a8;
  font-size: 13px;
}
.spx-staff-note-composer {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--t-line-soft, #eef1f6);
}
.spx-msg-note-marker {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  padding: 4px 2px;
  margin: 0 0 6px;
  font-size: 12px;
  color: var(--t-tint-amber-ink, #7a5b12);
}
.spx-msg-note-marker-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}
.spx-msg-note-marker .js-spx-jump-staff-note {
  padding: 0;
  font-weight: 600;
  color: var(--t-brand-text, #5b2c86);
}
.spx-svc-alert {
  margin: 0 0 10px;
  padding: 8px 10px;
  background: var(--t-tint-amber, #fff6e5);
  border: 1px solid #f0d9a8;
  border-radius: 4px;
  color: var(--t-tint-amber-ink, #7a5b12);
  font-size: 12px;
  line-height: 1.35;
}
.spx-svc-empty { margin: 8px 0 0; font-size: 12px; }
.spx-svc-list { max-height: 420px; overflow-y: auto; margin-top: 8px; }
.spx-svc-row {
  display: flex;
  gap: 8px;
  padding: 8px 0;
  border-top: 1px solid var(--t-line-soft, #eef1f6);
}
.spx-svc-row:first-child { border-top: 0; padding-top: 0; }
.spx-svc-row.is-scheduled { background: var(--t-tint-slate, #fffaf0); margin: 0 -12px; padding-left: 12px; padding-right: 12px; }
.spx-svc-row.is-deleted { opacity: 0.78; }
.spx-svc-kind {
  flex: 0 0 72px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--t-faint, #8a96a6);
  padding-top: 2px;
}
.spx-svc-main { min-width: 0; flex: 1; }
.spx-svc-title { font-weight: 600; color: var(--t-ink, #243447); font-size: 13px; line-height: 1.25; }
.spx-svc-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: 4px; }
.spx-svc-deletes { background: var(--t-tint-amber, #f4e4c4); color: var(--t-tint-amber-ink, #7a4b00); }
/* When the line was last up. Its own row in the meta flex line rather than a
   fourth chip on a 300px sidebar, where it wrapped into the Open link. */
.spx-svc-meta .spx-svc-seen { flex: 0 0 100%; margin-top: 2px; }
/* A customer recovered from the sender address rather than linked by a person.
   Shares the alert's shape but not its amber: this is context, not something to
   action. The border stays neutral so the dark palette does not put a bright
   blue outline around a quiet note. */
.spx-svc-alert.spx-svc-inferred {
  background: var(--t-tint-blue, #e8f4fb);
  border-color: var(--t-line, #e4ebf2);
  color: var(--t-tint-blue-ink, #1d6fa5);
}
.spx-svc-alert.spx-svc-inferred a { color: inherit; text-decoration: underline; }
.spx-svc-actions { margin-top: 6px; font-size: 12px; }
.spx-svc-actions a { margin-right: 10px; }

.spx-sidebar-form .form-group { margin-bottom: 10px; }
.spx-sidebar-form label { font-size: 12px; color: var(--t-tint-slate-ink, #6b7a8d); margin-bottom: 3px; }
.spx-multi { min-height: 90px; }

/* ---------- Helpdesk: list ---------- */

.spx-inline .spx-pill { cursor: pointer; border: 0; background-clip: padding-box; }
.spx-inline button.spx-pill {
  font: inherit;
  line-height: 1.2;
  display: inline-block;
}
.spx-inline .caret { margin-left: 4px; opacity: 0.6; }
.spx-inline .dropdown-menu { min-width: 200px; }
/* Status and priority read on one line, as in Splynx. Wrapping "Waiting on customer"
   over three lines is what makes these rows twice as tall as they should be. */
.spx-inline, .spx-inline .spx-pill { white-space: nowrap; }
.spx-check { width: 32px; }

/* Toolbar above the list: bulk actions on the left, page size and search on the right. */
.spx-table-tools {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 10px;
}
.spx-search {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-left: auto;
  color: var(--t-muted, #6b7789);
  font-size: 13px;
}
.spx-search select, .spx-search input { width: auto; }
.spx-search input[type="search"] { min-width: 190px; }

/* Requester cell: avatar beside the name, name and address stacked. */
.spx-customer { display: flex; align-items: flex-start; gap: 8px; }
.spx-customer > span:last-child { min-width: 0; }
.spx-labels { margin-top: 4px; }
.spx-label-pill { background: var(--t-tint-slate, #eef0f6); color: var(--t-tint-slate-ink, #566); }
.spx-type { background: var(--t-tint-slate, #eef4ff); color: var(--t-tint-slate-ink, #3d5a80); }
.spx-group { background: var(--t-tint-purple, #f2eefb); color: var(--t-brand-text, #5b2c86); }
/* Assignee column: must read as a control, not plain body text (Unassigned especially). */
.spx-assignee {
  background: var(--t-tint-slate, #eef4ff) !important;
  color: var(--t-tint-slate-ink, #3d5a80) !important;
  border: 1px solid #c5d4ef !important;
}
.spx-assignee-none {
  background: var(--t-tint-purple, #f3eefb) !important;
  color: var(--t-brand-text, #5b2c86) !important;
  border: 1px dashed #9b7bb8 !important;
}
.spx-inline .spx-assignee .caret { opacity: 0.85; }
/* Keep the assignee picker above neighbouring cells; table-responsive otherwise clips it. */
.spx-table .spx-inline.open { position: relative; z-index: 20; }
.spx-table .spx-inline .dropdown-menu {
  max-height: 280px;
  overflow-y: auto;
  z-index: 30;
}
.spx-bulk-panel {
  display: flex;
  gap: 12px;
  align-items: flex-end;
  flex-wrap: wrap;
  padding: 10px 12px;
  margin: 8px 0;
  background: var(--t-surface-2, #f7f9fc);
  border: 1px solid #e3e9f2;
  border-radius: 4px;
}
.spx-bulk-panel label { font-size: 12px; color: var(--t-tint-slate-ink, #6b7a8d); font-weight: 600; margin: 0; }
.spx-filter-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 12px;
  align-items: end;
}
.spx-filter-grid label { font-size: 12px; color: var(--t-tint-slate-ink, #6b7a8d); font-weight: 600; width: 100%; }
.spx-filter-actions { display: flex; gap: 8px; }
.spx-signature-img { max-height: 44px; max-width: 200px; }

/* The service detail Splynx reveals under a row: a plain label/value list, indented so it
   reads as belonging to the row above rather than as another table. */
.spx-detail-table {
  width: 100%;
  max-width: 100%;
  table-layout: fixed;
  margin: 0 0 0 18px;
}
.spx-detail-table th {
  width: 210px;
  padding: 3px 10px 3px 0;
  font-weight: 600;
  color: var(--t-muted, #6b7789);
  vertical-align: top;
}
.spx-detail-table td { padding: 3px 0; }

/* Free-text columns (address, company, reseller) otherwise wrap to four lines and
   every row ends up a different height. Splynx clips them to one line. */
.spx-table td.spx-clip {
  max-width: 170px;
  overflow: hidden !important;
  text-overflow: ellipsis;
  white-space: nowrap;
  clip-path: inset(0);
}

/* Account / internet lists: username + Copy must share one line without overlapping.
   Copy is absolutely positioned so hover never widens the cell (that caused jumps). */
body.spx-app .content-wrapper table td.ic-username-cell,
.spx-internet-table td.ic-username-cell {
  position: relative;
  max-width: 220px;
  width: 12rem;
  padding-right: 28px !important;
  overflow: hidden;
}
body.spx-app .content-wrapper table .ic-copy-row,
.spx-internet-table .ic-copy-row,
.js-column-visibility .ic-copy-row {
  display: block;
  max-width: 100%;
  width: 100%;
  min-width: 0;
  overflow: hidden;
}
body.spx-app .content-wrapper table .ic-copy-row > a,
body.spx-app .content-wrapper table .ic-copy-row > span,
.spx-internet-table .ic-copy-row > a,
.spx-internet-table .ic-copy-row > span,
.js-column-visibility .ic-copy-row > a,
.js-column-visibility .ic-copy-row > span {
  display: block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  overflow-wrap: normal;
}
body.spx-app .content-wrapper table .ic-copy-btn,
.spx-internet-table .ic-copy-btn,
.js-column-visibility .ic-copy-btn {
  position: absolute;
  top: 50%;
  right: 6px;
  margin-top: -11px;
  padding: 2px 5px;
  opacity: 0;
  pointer-events: none;
}
body.spx-app .content-wrapper table .ic-copy-btn .ic-copy-label,
.spx-internet-table .ic-copy-btn .ic-copy-label,
.js-column-visibility .ic-copy-btn .ic-copy-label {
  display: none;
}
body.spx-app .content-wrapper table tr:hover .ic-copy-btn,
body.spx-app .content-wrapper table .ic-copy-btn:focus,
.spx-internet-table tr:hover .ic-copy-btn,
.spx-internet-table .ic-copy-btn:focus,
.js-column-visibility tr:hover .ic-copy-btn,
.js-column-visibility .ic-copy-btn:focus {
  opacity: 1;
  pointer-events: auto;
}
body.spx-app .content-wrapper table td.spx-clip,
.spx-internet-table td.spx-clip {
  max-width: 220px;
}

/* Name over email, both clipped to one line each. */
.spx-table td.spx-name-cell { max-width: 210px; }
.spx-table td.spx-name-cell > a,
.spx-table td.spx-name-cell > .spx-sub {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Subjects run long. Splynx keeps them to one line and clips, so every row is the
   same height and the columns after it stay on screen. Full text is in the title. */
.spx-table td.spx-subject { max-width: 360px; }
.spx-table td.spx-subject > a {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Splynx keeps the row icons on one line; wrapping them makes rows uneven. */
.spx-row-actions { white-space: nowrap; }
.spx-row-actions a { color: var(--t-faint, #8a96a6); margin-right: 8px; }
.spx-row-actions a:hover { color: var(--t-brand-text, #5b2c86); }

/* ---------- Leads: stage bar, tabs, board ---------- */

.spx-tabs {
  list-style: none;
  display: flex;
  gap: 2px;
  margin: 0 0 12px;
  padding: 0;
  border-bottom: 1px solid var(--t-line, #e2e8f0);
  flex-wrap: wrap;
}
.spx-tabs li a {
  display: block;
  padding: 10px 14px;
  color: var(--t-muted, #5b6b7c);
  font-weight: 600;
}
.spx-tabs li.active a {
  color: var(--t-brand-text, #5b2c86);
  border-bottom: 3px solid var(--t-brand, #5b2c86);
}

.spx-lead-head-row {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 12px;
}
.spx-lead-identity { display: flex; align-items: center; gap: 10px; }
.spx-lead-head-actions { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.spx-inline-owner { display: flex; align-items: center; gap: 6px; }
.spx-deal { color: var(--t-tint-red-ink, #d9534f); font-weight: 700; font-size: 16px; white-space: nowrap; }
.spx-deal-input { width: 110px; }

.spx-stagebar { display: flex; flex-wrap: wrap; gap: 2px; }
.spx-stage {
  display: block;
  padding: 6px 12px 6px 20px;
  background: var(--t-surface-3, #eef1f6);
  color: var(--t-tint-blue-ink, #606d7f) !important;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.3px;
  clip-path: polygon(0 0, calc(100% - 10px) 0, 100% 50%, calc(100% - 10px) 100%, 0 100%, 10px 50%);
  text-decoration: none !important;
}
.spx-stage.is-done { background: var(--t-tint-purple, #d7c9ea); color: var(--t-tint-purple-ink, #4a2470) !important; }
.spx-stage.is-current { background: #5b2c86; color: #fff !important; }
.spx-stage.is-won.is-current { background: #1b8363; }
.spx-stage.is-lost.is-current { background: #d43c38; }
.spx-stage:hover { filter: brightness(0.95); }

.spx-comment { padding: 8px 0; border-bottom: 1px dashed var(--t-line-soft, #eef1f6); }
.spx-comment.is-done { opacity: 0.65; }
.spx-comment-head { display: flex; justify-content: space-between; gap: 8px; }
.spx-more-fields { border-top: 1px dashed #e3e9f2; margin-top: 10px; padding-top: 10px; }
.spx-form-actions { display: flex; gap: 8px; margin-top: 10px; }

.spx-board {
  display: flex;
  gap: 10px;
  overflow-x: auto;
  padding-bottom: 12px;
}
.spx-board-col {
  min-width: 220px;
  flex: 0 0 220px;
  background: var(--t-tint-slate, #f4f6fa);
  border: 1px solid #e3e9f2;
  border-radius: 4px;
}
.spx-board-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 10px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  color: #fff;
  background: #5b2c86;
  border-radius: 4px 4px 0 0;
}
.spx-board-body { padding: 8px; max-height: 70vh; overflow-y: auto; }
.spx-board-card {
  background: var(--t-surface, #fff);
  border: 1px solid #e3e9f2;
  border-radius: 4px;
  padding: 8px;
  margin-bottom: 8px;
}
.spx-board-card-head { display: flex; justify-content: space-between; gap: 6px; font-weight: 600; }
.spx-board-card-foot { display: flex; gap: 6px; margin-top: 6px; }
.spx-board-empty { padding: 8px; }

/* Pipeline colours. Splynx fills the stage badge solid with white text — a tinted pill
   reads as coloured link text in a dense list, which is what ours looked like. Blue at
   the top of the funnel, amber in flight, black awaiting paper, green won, red lost. */
.spx-pill[class*="spx-lead-"] { color: #fff; border: 0; font-weight: 600; }
.spx-pill.spx-lead-new_enquiry { background: #1272e5; }
.spx-pill.spx-lead-contacted_follow_up { background: #f0932b; color: #1b2433 }
.spx-pill.spx-lead-quoted { background: #e6a817; color: #1b2433; }
.spx-pill.spx-lead-waiting_quote_signature { background: #d98c1f; color: #1b2433 }
.spx-pill.spx-lead-generate_contract { background: #69758a; }
.spx-pill.spx-lead-waiting_signed_contract { background: #1f2430; }
.spx-pill.spx-lead-contract_received_upstream { background: #2f3b4d; }
.spx-pill.spx-lead-waiting_installation { background: #267d9c; }
.spx-pill.spx-lead-error_with_installation { background: #d63b3b; }
.spx-pill.spx-lead-won { background: #1b844b; }
.spx-pill.spx-lead-lost { background: #6b7280; }

/* Quote statuses use the same solid treatment; Splynx's filter legend is New blue, Sent
   navy, On review amber, Accepted green, Denied red. */
.spx-pill[class*="spx-quote-"] { color: #fff; border: 0; font-weight: 600; }
.spx-pill.spx-quote-new { background: #1272e5; }
.spx-pill.spx-quote-sent { background: #2f3b4d; }
.spx-pill.spx-quote-on_review { background: #e6a817; color: #1b2433; }
.spx-pill.spx-quote-accepted { background: #1b844b; }
.spx-pill.spx-quote-denied { background: #d63b3b; }

/* Column headers keep the Splynx purple bar; the count sits on the right. */
.spx-board-head .spx-count { background: rgba(255, 255, 255, 0.22); color: #fff; }

/* ---------- Quotes ---------- */

.spx-items .form-control { padding: 4px 8px; height: 32px; }
.spx-items .spx-col-sm { width: 90px; }
.spx-items .spx-col-md { width: 150px; }
.spx-line-total { white-space: nowrap; font-weight: 600; }
.spx-remove { font-size: 11px; color: var(--t-tint-red-ink, #d9534f); font-weight: 600; }
.spx-items-foot {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 12px;
}
.spx-quote-totals { text-align: right; font-size: 13px; }
.spx-quote-grand { font-size: 18px; margin-top: 6px; }
.spx-grand-row td { border-top: 2px solid var(--t-brand, #5b2c86); }
.spx-quote-new { background: var(--t-tint-slate, #eef4ff); color: var(--t-tint-slate-ink, #3d5a80); }
.spx-quote-sent { background: var(--t-tint-purple, #d7c9ea); color: var(--t-tint-purple-ink, #4a2470); }
.spx-quote-on_review { background: #f0ad4e; color: #1b2433; }
.spx-quote-accepted { background: #1b8363; color: #fff; }
.spx-quote-denied { background: #d43c38; color: #fff; }

.spx-pri-urgent { background: #d43c38; color: #fff; }
.spx-pri-high { background: #f0ad4e; color: #1b2433; }
.spx-pri-medium { background: var(--t-tint-slate, #eef4ff); color: var(--t-tint-slate-ink, #3d5a80); }
.spx-pri-low { background: var(--t-surface-3, #eef1f6); color: var(--t-tint-blue-ink, #606d7f); }

/* Splynx-style thread: system audit lines read as compact log rows */
.spx-msg-system { background: var(--t-tint-slate, #fbfbfd); border-left: 3px solid #d5d5e0; }
.spx-msg-system .spx-msg-body { color: var(--t-tint-slate-ink, #6b6b7b); font-size: 12px; }
.spx-msg-system .spx-msg-body ul { margin: 0; padding-left: 18px; }
.spx-msg-system-line {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  padding: 4px 2px;
  margin: 0 0 6px;
  font-size: 12px;
  color: var(--t-tint-slate-ink, #6b6b7b);
}
.spx-quoted {
  margin-top: 8px;
  padding-top: 6px;
  border-top: 1px dashed var(--t-line, #e2e8f0);
}
.spx-quoted summary {
  cursor: pointer;
  color: var(--t-brand-text, #5b2c86);
  font-weight: 600;
  font-size: 12px;
}
.spx-msg-body img,
.spx-photo {
  max-width: min(100%, 720px);
  height: auto;
  border-radius: 6px;
  border: 1px solid #e1e5ee;
  background: var(--t-tint-slate, #f7f8fb);
  display: block;
}
.spx-photo-link { display: inline-block; max-width: 100%; }
.spx-photo-wrap { margin: 10px 0; }
.spx-photo-caption { margin-top: 4px; font-size: 12px; color: var(--t-tint-blue-ink, #6b7c93); }
.spx-photo-missing {
  margin: 8px 0;
  padding: 10px 12px;
  border: 1px dashed #c5cddd;
  border-radius: 6px;
  background: var(--t-tint-slate, #f7f8fb);
  color: var(--t-tint-blue-ink, #4a5568);
  font-size: 13px;
}
.spx-msg-body table { width: 100%; border-collapse: collapse; margin: 8px 0; }
.spx-msg-body table td, .spx-msg-body table th { border: 1px solid var(--t-line, #e6e6ef); padding: 4px 6px; font-size: 12px; }
.spx-msg-body blockquote { border-left: 3px solid #e6e6ef; margin: 8px 0; padding: 4px 10px; color: var(--t-tint-slate-ink, #777); }
.spx-attach { margin-top: 8px; font-size: 12px; color: var(--t-brand-text, #6f42c1); }
.spx-attach-file { margin: 4px 0; }
.spx-hidden-pill { background: var(--t-tint-purple, #f3e8ff); color: var(--t-brand-text, #6f42c1); }
.spx-note-pill { background: var(--t-tint-amber, #fff4d6); color: var(--t-tint-amber-ink, #926500); }
.spx-msg-count { display: inline-block; margin-left: 6px; padding: 0 6px; border-radius: 9px; background: var(--t-tint-purple, #ececf5); color: var(--t-muted, #55556b); font-size: 11px; }

/* ---- Customer record: Splynx tabbed layout ---- */
.spx-record-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; margin-bottom: 14px; }
.spx-record-title { display: flex; align-items: flex-start; gap: 12px; }
.spx-record-icon { width: 40px; height: 40px; border-radius: 8px; background: #6f42c1; color: #fff; display: inline-flex; align-items: center; justify-content: center; font-size: 18px; }
.spx-record-nav { display: flex; gap: 4px; align-items: center; }
/* The prev/next arrows are icon-only squares; a text button beside them needs a
   little air so the row does not read as three arrows. */
.spx-record-nav .spx-record-add { margin-right: 8px; white-space: nowrap; }
.spx-record-nav .btn.disabled { opacity: .45; }
/* Tabs wrap onto a second line rather than scrolling inside their own strip: a nested
   scrollbar under the tabs is the clearest sign this is not Splynx. */
.spx-record-tabs { border-bottom: 1px solid #e6e6ef; margin-bottom: 0; background: var(--t-surface, #fff); border-radius: 8px 8px 0 0; padding: 0 8px; display: flex; flex-wrap: wrap; }
.spx-record-tabs > li { float: none; white-space: nowrap; }
.spx-record-tabs > li > a { border: none !important; color: var(--t-muted, #55556b); font-weight: 600; padding: 12px 14px; background: transparent !important; font-size: 14px; }
.spx-reveal { padding-left: 0; color: var(--t-tint-blue-ink, #337ab7); }
.spx-record-tabs > li.active > a { color: var(--t-ink, #1f1f2e); border-bottom: 2px solid #6f42c1 !important; }
.spx-record-tabs > li > a:hover { color: var(--t-brand-text, #6f42c1); }
/* Without this, a tab you visited earlier keeps the purple :visited colour and reads
   as a second selected tab. */
.spx-record-tabs > li:not(.active) > a:visited { color: var(--t-muted, #55556b); }
.spx-record-body { background: var(--t-surface, #fff); border-radius: 0 0 8px 8px; padding: 16px; }
.spx-record-bar { display: flex; justify-content: space-between; align-items: center; gap: 12px; background: var(--t-tint-slate, #f4f4f8); border-radius: 6px; padding: 12px 14px; margin-bottom: 16px; flex-wrap: wrap; }
.spx-record-bar-left { display: flex; align-items: center; gap: 18px; }
.spx-record-bar-actions { display: flex; gap: 6px; align-items: center; }
.spx-balance { color: var(--t-muted, #55556b); }
.spx-arrears { color: var(--t-tint-red-ink, #d9534f); }
.spx-tab-toolbar { display: flex; justify-content: flex-end; align-items: center; gap: 10px; margin-bottom: 12px; flex-wrap: wrap; }
.spx-tab-toolbar .spx-sub { margin-right: auto; }

/* Read-only Splynx-style field rows */
.spx-form-table { width: 100%; }
.spx-form-table th { width: 190px; text-align: right; padding: 6px 14px 6px 0; font-weight: 600; color: var(--t-muted, #55556b); vertical-align: middle; font-size: 13px; }
.spx-form-table td { padding: 6px 0; }
.spx-form-table td.spx-static { color: var(--t-ink, #1f1f2e); font-size: 13px; }
.spx-form-table input[readonly] { background: var(--t-surface, #fff); }
.spx-input-action { display: flex; gap: 6px; align-items: center; }
.spx-input-action .form-control { flex: 1; }
.spx-mini-row { display: flex; justify-content: space-between; align-items: center; gap: 8px; padding: 5px 0; border-bottom: 1px solid #f0f0f5; }
.spx-mini-row:last-child { border-bottom: none; }

/* Status pills — Splynx: Active blue, Online green, last 24h orange */
.spx-status-online { background: #21c07a; color: #1b2433; }
.spx-status-online-24h { background: #e67e22; color: #1b2433; }
.spx-status-active { background: #207ab7; color: #fff; }
.spx-status-offline { background: var(--t-tint-purple, #ececf5); color: var(--t-tint-slate-ink, #696978); }
.spx-status-blocked { background: #f0ad4e; color: #1b2433; }
.spx-status-deleted { background: #d63b3b; color: #fff; }
.spx-status-inactive { background: var(--t-tint-purple, #ececf5); color: var(--t-tint-slate-ink, #696978); }
.spx-pill-muted { background: var(--t-tint-purple, #ececf5); color: var(--t-tint-slate-ink, #696978); }

/* Row tints match the status overlay */
.spx-row-online > td { background: var(--t-tint-slate, #e8f9ef) !important; }
.spx-row-online-24h > td { background: var(--t-tint-amber, #fdebd0) !important; }
.spx-row-active > td { background: var(--t-tint-blue, #d6eaf8) !important; }

/* List controls */
.spx-list-controls { display: flex; justify-content: space-between; align-items: center; gap: 12px; margin-bottom: 10px; flex-wrap: wrap; }
.spx-list-controls-right { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.spx-show-entries, .spx-table-search { display: flex; align-items: center; gap: 6px; color: var(--t-muted, #55556b); font-size: 13px; }
/* "90,251 notifications" beside the filters. Same weight as the label above
   it, not .spx-count -- that one is a purple pill badge and a five-figure
   number reads as an alert in it. */
.spx-list-count { color: var(--t-muted, #55556b); font-size: 13px; white-space: nowrap; }
.spx-show-entries select { width: auto; }
.spx-col-x { width: 28px; }

.spx-col-toggle { position: relative; display: inline-block; }
.spx-col-toggle-btn { height: 32px; }
.spx-col-toggle-menu {
  display: none;
  position: absolute;
  right: 0;
  top: 100%;
  z-index: 1060;
  min-width: 230px;
  max-height: 320px;
  overflow-y: auto;
  margin: 4px 0 0;
  padding: 6px 0;
  background: var(--t-surface, #fff);
  border: 1px solid #d0d7de;
  border-radius: 4px;
  box-shadow: 0 8px 18px rgba(0,0,0,.12);
  text-align: left;
}
.spx-col-toggle-menu.is-open { display: block; }
.spx-col-toggle-item {
  display: block;
  font-weight: normal;
  margin: 0;
  padding: 6px 14px;
  cursor: pointer;
  white-space: nowrap;
  color: var(--t-tint-slate-ink, #333);
}
.spx-col-toggle-item:hover { background: var(--t-tint-slate, #f4f7fa); }
.spx-col-toggle-item input { margin: 0 8px 0 0; vertical-align: middle; }

/* Move controls in the Columns menu.
   The row is a <label> wrapping a checkbox, so these have to be real buttons
   that stop the click -- anything else toggles the column on its way past. */
.spx-col-toggle-item { display: flex; align-items: center; }
.spx-col-move { margin-left: auto; display: inline-flex; gap: 2px; padding-left: 10px; }
.spx-col-move-btn {
  border: 1px solid var(--t-line, #d8dee8);
  background: transparent;
  color: var(--t-faint, #5b6b7c);
  border-radius: 3px;
  line-height: 1;
  font-size: 11px;
  padding: 3px 5px;
  cursor: pointer;
}
.spx-col-move-btn:hover { color: var(--t-ink, #1b2433); border-color: var(--t-accent, #7b4bb0); }
.spx-col-move-btn:focus-visible { outline: 2px solid var(--t-accent, #7b4bb0); outline-offset: 1px; }
.spx-col-toggle-actions {
  border-top: 1px solid #eee;
  margin-top: 4px;
  padding: 6px 12px;
}
.spx-col-toggle-actions a { display: inline-block; margin-right: 12px; }

/* Customer list: fit the viewport. Global nowrap + 100% width was dumping leftover
   space between Start date and Street and shoving Name off-screen. */
.spx-customers-table {
  table-layout: fixed;
  width: 100%;
}
.spx-customers-table.spx-has-extra-cols {
  table-layout: auto;
  min-width: 1400px;
}
.spx-customers-table .spx-c-x { width: 28px; }
.spx-customers-table .spx-c-status { width: 9.75rem; }
.spx-customers-table .spx-c-id { width: 4.25rem; }
.spx-customers-table .spx-c-name { width: 16%; }
.spx-customers-table .spx-c-login { width: 16%; }
.spx-customers-table .spx-c-start { width: 7rem; }
.spx-customers-table .spx-c-street { width: 14%; }
.spx-customers-table .spx-c-added { width: 6.5rem; }
.spx-customers-table .spx-c-seen { width: 8.25rem; }

/* Internet / service lists: fit the pane, never scroll sideways. Auto layout plus
   the global nowrap sized every column to its longest string, so a handful of long
   product names or one extra Columns toggle pushed the table past the viewport and
   raised a horizontal scrollbar. Fixed layout makes width:100% binding, and the
   percentages below are ratios — the browser rescales whatever set of columns is
   currently visible to fill exactly 100%, so toggling columns still fits. */
body.spx-app .content-wrapper table.spx-internet-table {
  table-layout: fixed;
  width: 100%;
}

/* Fixed layout stops long text widening the table, so it has to be clipped
   instead — otherwise it spills over the next column. Titles carry the full value. */
body.spx-app .content-wrapper table.spx-internet-table > thead > tr > th,
body.spx-app .content-wrapper table.spx-internet-table > tbody > tr > td {
  overflow: hidden;
  text-overflow: ellipsis;
}

/* On a smaller screen a column can end up narrower than a long pill ("Online last
   24h", "Month-to-Month"). Ellipsis inside the pill reads better than the cell
   slicing the word in half; the title attribute still carries the full value. */
body.spx-app .content-wrapper table.spx-internet-table > tbody > tr > td > .spx-pill {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: middle;
}

body.spx-app .content-wrapper table.spx-internet-table > thead > tr > th[data-col="username"] { width: 17.2%; }
body.spx-app .content-wrapper table.spx-internet-table > thead > tr > th[data-col="product"] { width: 18.2%; }
body.spx-app .content-wrapper table.spx-internet-table > thead > tr > th[data-col="isp"] { width: 8%; }
body.spx-app .content-wrapper table.spx-internet-table > thead > tr > th[data-col="client"] { width: 15.6%; }
body.spx-app .content-wrapper table.spx-internet-table > thead > tr > th[data-col="sage_category"] { width: 8%; }
body.spx-app .content-wrapper table.spx-internet-table > thead > tr > th[data-col="online"] { width: 7.3%; }
body.spx-app .content-wrapper table.spx-internet-table > thead > tr > th[data-col="mtn_lock"] { width: 6.4%; }
body.spx-app .content-wrapper table.spx-internet-table > thead > tr > th[data-col="status"] { width: 5.2%; }
body.spx-app .content-wrapper table.spx-internet-table > thead > tr > th[data-col="activation"] { width: 6.5%; }
body.spx-app .content-wrapper table.spx-internet-table > thead > tr > th[data-col="term"] { width: 4.5%; }
body.spx-app .content-wrapper table.spx-internet-table > thead > tr > th[data-col="contract"] { width: 8.1%; }
body.spx-app .content-wrapper table.spx-internet-table > thead > tr > th[data-col="splynx_id"] { width: 6%; }
body.spx-app .content-wrapper table.spx-internet-table > thead > tr > th[data-col="installation_address"] { width: 12%; }
body.spx-app .content-wrapper table.spx-internet-table > thead > tr > th[data-col="fibre_line"] { width: 7%; }
body.spx-app .content-wrapper table.spx-internet-table > thead > tr > th[data-col="scheduled_deletion"] { width: 7%; }
body.spx-app .content-wrapper table.spx-internet-table > thead > tr > th[data-col="created"] { width: 6.5%; }
/* Only on the status-specific lists (Expired / Suspended / Pending). */
body.spx-app .content-wrapper table.spx-internet-table > thead > tr > th[data-col="expired_date"] { width: 7%; }
body.spx-app .content-wrapper table.spx-internet-table > thead > tr > th[data-col="suspension_date"] { width: 7%; }
body.spx-app .content-wrapper table.spx-internet-table > thead > tr > th[data-col="order_type"] { width: 8%; }

.spx-row-detail-services { flex: 1 1 100%; min-width: 0; }
.spx-mini-services {
  list-style: none;
  margin: 6px 0 0;
  padding: 0;
  background: var(--t-surface, #fff);
  max-width: 100%;
}
.spx-mini-services > li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 16px;
  padding: 6px 8px;
  border-bottom: 1px solid #f0f0f5;
  font-size: 12px;
}
.spx-mini-user { font-weight: 600; }
.spx-mini-product { color: var(--t-muted, #55556b); }
.spx-mini-line { color: var(--t-faint, #9a9ab0); }

body.spx-app .spx-customers-table > thead > tr > th,
body.spx-app .spx-customers-table > tbody > tr > td {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
body.spx-app .spx-customers-table > tbody > tr.spx-row-detail > td {
  overflow-x: auto;
  text-overflow: clip;
  white-space: normal;
}
body.spx-app .spx-customers-table > thead > tr > th {
  white-space: normal;
  line-height: 1.15;
  vertical-align: bottom;
}
.spx-customers-table .spx-sortable a { white-space: normal; }
.spx-customers-table .spx-pill {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  display: inline-block;
  vertical-align: middle;
}
.spx-customers-table .spx-more { color: var(--t-faint, #9a9ab0); font-size: 11px; }
.spx-last-now { color: var(--t-tint-green-ink, #1a9a5a); font-weight: 700; }
.spx-expander { color: var(--t-faint, #9a9ab0); }
.spx-row-detail > td {
  background: var(--t-tint-slate, #fafaff);
}
.spx-row-detail-body {
  display: flex;
  flex-wrap: wrap;
  gap: 18px;
  font-size: 12px;
  color: var(--t-muted, #55556b);
  padding: 6px 2px;
  box-sizing: border-box;
  max-width: 100%;
}
/* Extra-info stays a table-row. display:block on the <tr> is wrapped as one
   anonymous cell in column 1, which collapsed Clients extra-info into a sliver
   under Status. Hidden columns are handled by syncDetailColspans (colspan =
   visible header count) so a leftover colspan="16" cannot invent empty columns.
   Nested .spx-detail-table is its own table and cannot retune parent columns. */
body.spx-app table.spx-table > tbody > tr.spx-row-detail.is-open,
body.spx-app table.spx-customers-table > tbody > tr.spx-row-detail.is-open {
  display: table-row;
}
body.spx-app table.spx-table > tbody > tr.spx-row-detail.is-open > td,
body.spx-app table.spx-customers-table > tbody > tr.spx-row-detail.is-open > td {
  display: table-cell;
  box-sizing: border-box;
  overflow-x: auto;
  white-space: normal;
}
.spx-count { display: inline-block; margin-left: 6px; padding: 0 7px; border-radius: 9px; background: #6f42c1; color: #fff; font-size: 11px; }

/* Usage by day chart */
.spx-usage-chart { display: flex; align-items: flex-end; gap: 3px; height: 220px; padding: 8px 0 0; }
.spx-usage-col { flex: 1; display: flex; flex-direction: column; justify-content: flex-end; height: 100%; }
/* A day nobody wrote down. An empty column reads as "used nothing", which is
   exactly the thing this chart was fixed for -- hatch it so it reads as absent.
   No min()/max() here: this file is raw-served, but a copy under app/assets
   would meet sass 3.4 and take the site down. */
.spx-usage-col.is-unrecorded .spx-usage-stack { opacity: .55; background-image:
  repeating-linear-gradient(135deg, transparent, transparent 3px,
    rgba(127, 127, 127, .25) 3px, rgba(127, 127, 127, .25) 6px); }
.spx-usage-col.is-unrecorded .spx-usage-label { font-style: italic; opacity: .6; }
/* Per-service graphs. One strip per service, all on the same scale so they can
   be read against each other rather than each filling its own height. */
.spx-svc-graph { padding: 10px 0; border-top: 1px solid rgba(127, 127, 127, .18); }
.spx-svc-graph:first-child { border-top: 0; }
.spx-svc-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 10px;
  margin-bottom: 6px; font-size: 13px; }
.spx-svc-head .spx-sub { margin-left: auto; }
.spx-usage-chart-mini { height: 54px; }
.spx-usage-stack { flex: 1; display: flex; flex-direction: column; justify-content: flex-end; }
.spx-usage-down { background: #e0c07a; }
.spx-usage-up { background: #8fc4ea; }
.spx-usage-label { text-align: center; font-size: 11px; color: var(--t-faint, #9a9ab0); padding-top: 4px; }
.spx-legend { font-size: 12px; color: var(--t-muted, #55556b); }
.spx-legend-swatch { display: inline-block; width: 14px; height: 10px; margin: 0 4px 0 10px; }
.spx-swatch-down { background: #e0c07a; }
.spx-swatch-up { background: #8fc4ea; }

/* ---- Ticket analytics ---- */
/* Created vs closed per day, grouped columns like the Splynx helpdesk chart */
.spx-tchart { display: flex; align-items: flex-end; gap: 3px; height: 220px; padding: 8px 0 0; }
.spx-tchart-col { flex: 1; min-width: 5px; display: flex; flex-direction: column; justify-content: flex-end; height: 100%; }
.spx-tchart-pair { flex: 1; display: flex; align-items: flex-end; justify-content: center; gap: 1px; }
.spx-tchart-pair > div { width: 46%; max-width: 42px; }
.spx-tchart-created { background: var(--t-brand-2, #6f42c1); }
.spx-tchart-closed { background: #21c07a; }
/* 10px, the same documented exception as .ic-usage-axis: a chart tick label,
   not UI text, living in a 14px box with overflow:hidden. At 11px the line
   box needs about 19px and the label is clipped. */
.spx-tchart-label { height: 14px; overflow: hidden; text-align: center; font-size: 10px; color: var(--t-faint, #9a9ab0); padding-top: 4px; }
.spx-swatch-created { background: var(--t-brand-2, #6f42c1); }
.spx-swatch-closed { background: #21c07a; }

/* Agent workload bars */
.spx-agent-bar { min-width: 90px; height: 8px; border-radius: 3px; background: var(--t-tint-slate, #f0f0f5); overflow: hidden; }
.spx-agent-bar > span { display: block; height: 100%; background: var(--t-brand-2, #6f42c1); }

/* Latest activity feed */
.spx-activity-row { display: flex; gap: 10px; padding: 8px 14px; border-bottom: 1px solid #f1f4f8; }
.spx-activity-row:last-child { border-bottom: none; }
.spx-activity-body { min-width: 0; }
.spx-activity-body .spx-sub { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Sortable list headers */
.spx-sortable a { color: inherit; text-decoration: none; white-space: nowrap; }
.spx-sortable.is-sorted a { color: var(--t-brand-text, #6f42c1); }
.spx-sort-icon { color: #c4c4d2; font-size: 11px; }
.spx-sortable.is-sorted .spx-sort-icon { color: var(--t-brand-text, #6f42c1); }

/* Ticket row preview */
.spx-row-detail-msg { flex: 1 1 100%; }

/* ---- Documents + CPE ---- */
.spx-doc-upload { display: none; }
.spx-doc-upload.is-open { display: block; }
.spx-doc-form .form-group { display: inline-block; vertical-align: top; margin-right: 12px; min-width: 220px; }
.spx-doc-form label { display: block; font-size: 12px; font-weight: 600; color: var(--t-muted, #55556b); }
.spx-doc-form .spx-sub { display: block; margin-top: 8px; }
.spx-doc-flag { font-size: 11px; letter-spacing: .04em; text-transform: uppercase; color: var(--t-faint, #8a96a6); }
.spx-table td .spx-pill + .spx-pill { margin-left: 4px; }
/* Status pills stay on one line so list rows keep a single-row height. */
.spx-table .spx-pill { white-space: nowrap; }

/* ---- Quote editor ---- */
.spx-modal {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1500;
  background: rgba(31, 31, 46, .55);
  overflow-y: auto;
  padding: 24px 12px;
}
body.spx-modal-open { overflow: hidden; }
.spx-modal-dialog {
  background: var(--t-surface, #fff);
  border-radius: 8px;
  max-width: 620px;
  margin: 0 auto;
  box-shadow: 0 12px 40px rgba(0, 0, 0, .35);
}
.spx-modal-wide { max-width: 1140px; }
/* The product picker opens on top of an editor modal. */
.spx-modal-top { z-index: 1600; }
.spx-modal-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid #e6e6ef;
}
.spx-modal-head h4 { margin: 0; font-size: 16px; font-weight: 700; color: var(--t-ink, #1f1f2e); }
.spx-modal-x { border: none; background: none; font-size: 22px; line-height: 1; color: var(--t-faint, #9a9ab0); }
.spx-modal-body { padding: 16px; }

.spx-items .spx-col-flag { width: 70px; }
.spx-items .spx-with-vat { margin: 0; }
.spx-drag-cell { width: 28px; color: var(--t-faint, #9a9ab0); cursor: move; text-align: center; vertical-align: middle; }
.spx-item-row.spx-dragging { opacity: .4; }

.spx-product-list { list-style: none; margin: 12px 0 0; padding: 0; max-height: 55vh; overflow-y: auto; }
.spx-product-option {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 7px 8px;
  border-bottom: 1px solid #f0f0f5;
  cursor: pointer;
}
.spx-product-option:hover { background: var(--t-tint-slate, #f6f2fb); }
.spx-product-name { flex: 1 1 auto; font-weight: 600; color: var(--t-ink, #1f1f2e); }
.spx-product-code { color: var(--t-faint, #9a9ab0); font-size: 11px; text-transform: uppercase; }
.spx-product-price { font-weight: 700; white-space: nowrap; }
.spx-product-install { font-size: 11px; white-space: nowrap; }

/* ---- Routers ---- */
.spx-router-id { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12px; color: var(--t-ink, #1f1f2e); }
.spx-router-meta { color: var(--t-faint, #9a9ab0); font-size: 11px; margin-top: 2px; }

body.spx-app .spx-table:not(.spx-form-table):not(.spx-items) > thead > tr > th,
body.spx-app .spx-table:not(.spx-form-table):not(.spx-items) > tbody > tr > td {
  padding: 4px 8px;
  line-height: 1.2;
  vertical-align: middle;
  white-space: nowrap;
}

body.spx-app .spx-table > tbody > tr.spx-row-detail > td {
  white-space: normal;
  overflow-x: auto;
  text-overflow: clip;
}

body.spx-app .vhost-hscroll-btn {
  color: var(--t-brand-text, #5b2c86);
  border-color: #e2d6ef;
}

body.spx-app .vhost-hscroll-btn:hover:not(:disabled) {
  background: var(--t-tint-purple, #f4ecf8);
  border-color: var(--t-brand, #5b2c86);
  color: var(--t-brand-text, #5b2c86);
}

/* ---- Legacy Hosting / Accounts / Products under the unified shell ----
   These pages still use ic-record markup. Bring their cards onto the same border,
   radius and background language as spx-card so clicking a service does not feel like
   leaving the CRM. */
body.spx-app .content {
  padding: 0 28px 40px;
}

body.spx-app .ic-record,
body.spx-app .ic-form-shell,
body.spx-app .content-wrapper .box:not(.spx-card) {
  border: 1px solid var(--t-line, #e2e8f0) !important;
  border-radius: 4px !important;
  box-shadow: none !important;
  background: var(--t-surface, #fff);
}

body.spx-app .ic-record-hero {
  background: var(--t-surface, #fff);
  border-bottom: 1px solid var(--t-line-soft, #eef2f7);
  padding: 18px 20px;
}

body.spx-app .ic-record-kicker {
  color: var(--t-tint-purple-ink, #8a7a98);
  letter-spacing: 0.06em;
}

body.spx-app .ic-record-hero h2 {
  font-size: 22px;
  color: var(--t-ink, #2c3340) !important;
}

body.spx-app .ic-record-sub {
  color: var(--t-tint-slate-ink, #6b7a8d);
}

body.spx-app .ic-record-grid {
  padding: 8px 20px 4px;
}

body.spx-app .ic-kv dt {
  color: var(--t-faint, #8a96a6);
  font-weight: 600;
  font-size: 12px;
}

body.spx-app .ic-kv dd {
  color: var(--t-ink, #2c3340);
}

body.spx-app .ic-kv dd a {
  color: var(--t-accent-text, #2f80ed);
  font-weight: 600;
}

body.spx-app .ic-status {
  border-radius: 3px;
  font-weight: 600;
}

body.spx-app .ic-status.is-active {
  background: #1b844b;
  color: #fff;
}

body.spx-app .ic-record-actions {
  border-top: 1px solid var(--t-line-soft, #eef2f7);
  padding: 14px 20px;
  background: var(--t-tint-slate, #fafbfc);
}

body.spx-app .ic-record-actions .btn-primary,
body.spx-app .btn.btn-primary {
  background: var(--t-accent, #2f80ed);
  border-color: #2f80ed;
}

body.spx-app .ic-price {
  color: var(--t-tint-green-ink, #22a45d);
}

body.spx-app .content-wrapper .box-header.with-border {
  border-bottom-color: var(--t-line-soft, #eef2f7);
}

body.spx-app .content-wrapper .box-title {
  font-size: 16px;
  font-weight: 700;
  color: var(--t-ink, #2c3340);
}

/* ---- Splynx table + info language on every admin screen ----
   Legacy pages still render AdminLTE / DataTables markup. Map that onto the same
   table and label/value look the CRM already uses, so Hosting / Accounts / Products
   do not keep a second visual language. */

body.spx-app .content-header h1 {
  margin: 2px 0 12px;
  font-size: 22px;
  font-weight: 700;
  letter-spacing: 0;
  text-transform: none;
  color: var(--t-ink, #2c3340);
}

body.spx-app .content-header h1 > small {
  display: block;
  margin-top: 4px;
  font-size: 13px;
  font-weight: 400;
  color: var(--t-faint, #8a96a6);
}

body.spx-app .content-header .btn-success,
body.spx-app .spx-toolbar-actions .btn-success {
  background: var(--t-accent, #2f80ed);
  border-color: #2f80ed;
  font-weight: 600;
}

body.spx-app .content-wrapper .box .box-body,
body.spx-app .content-wrapper .box > .table-responsive {
  padding: 12px 14px;
}

body.spx-app .content-wrapper table.table,
body.spx-app .content-wrapper table.dataTable {
  width: 100% !important;
  margin: 0 !important;
  border-collapse: collapse;
  background: var(--t-surface, #fff);
}

body.spx-app .content-wrapper table.table > thead > tr > th,
body.spx-app .content-wrapper table.dataTable > thead > tr > th {
  font-size: 12px;
  font-weight: 700;
  color: var(--t-muted, #4a5a6a);
  text-transform: none;
  letter-spacing: 0;
  background: var(--t-surface, #fff) !important;
  border-top: 0 !important;
  border-bottom: 1px solid #e4ebf2 !important;
  border-left: 0 !important;
  border-right: 0 !important;
  padding: 8px 10px !important;
  white-space: nowrap;
  vertical-align: middle;
}

/* DataTables bootstrap parks sort glyphs at position:absolute;right:8px. Unified
   chrome then sets padding-right:10px, so the arrows sit on the header text.
   Keep the glyph inline next to the label. */
body.spx-app .content-wrapper table.dataTable thead .sorting:after,
body.spx-app .content-wrapper table.dataTable thead .sorting_asc:after,
body.spx-app .content-wrapper table.dataTable thead .sorting_desc:after,
body.spx-app .content-wrapper table.dataTable thead .sorting_asc_disabled:after,
body.spx-app .content-wrapper table.dataTable thead .sorting_desc_disabled:after {
  position: static !important;
  display: inline-block !important;
  top: auto !important;
  right: auto !important;
  margin-left: 6px;
  vertical-align: middle;
  float: none;
}

/* Username + Copy: later table padding rules beat the 28px right pad, so the
   copy control and wrapped email overlap. Keep one clipped line. */
body.spx-app .content-wrapper table.dataTable > tbody > tr > td.ic-username-cell,
body.spx-app .content-wrapper table.table > tbody > tr > td.ic-username-cell {
  position: relative;
  max-width: 240px;
  min-width: 160px;
  padding-right: 32px !important;
  overflow: hidden;
}
body.spx-app .content-wrapper table.dataTable td.ic-username-cell .ic-copy-row,
body.spx-app .content-wrapper table.table td.ic-username-cell .ic-copy-row {
  display: block !important;
  flex-wrap: nowrap !important;
  overflow: hidden;
  max-width: 100%;
}
body.spx-app .content-wrapper table.dataTable td.ic-username-cell .ic-copy-row > a,
body.spx-app .content-wrapper table.dataTable td.ic-username-cell .ic-copy-row > span,
body.spx-app .content-wrapper table.table td.ic-username-cell .ic-copy-row > a,
body.spx-app .content-wrapper table.table td.ic-username-cell .ic-copy-row > span {
  display: block !important;
  overflow: hidden !important;
  text-overflow: ellipsis !important;
  white-space: nowrap !important;
  overflow-wrap: normal !important;
  word-break: keep-all !important;
}
body.spx-app .content-wrapper table.dataTable td.ic-username-cell .ic-copy-btn,
body.spx-app .content-wrapper table.table td.ic-username-cell .ic-copy-btn {
  opacity: 0;
  pointer-events: none;
}
body.spx-app .content-wrapper table.dataTable tr:hover td.ic-username-cell .ic-copy-btn,
body.spx-app .content-wrapper table.dataTable td.ic-username-cell .ic-copy-btn:focus,
body.spx-app .content-wrapper table.table tr:hover td.ic-username-cell .ic-copy-btn,
body.spx-app .content-wrapper table.table td.ic-username-cell .ic-copy-btn:focus {
  opacity: 1;
  pointer-events: auto;
}

.scc-contract-cell {
  white-space: nowrap;
}
.scc-ticket-open {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  max-width: 100%;
  padding: 0;
  border: 0;
  background: transparent;
  color: inherit;
  text-align: left;
  cursor: pointer;
  font: inherit;
  appearance: none;
  -webkit-appearance: none;
}
.scc-ticket-open:hover .spx-pill,
.scc-ticket-open:focus .spx-pill {
  filter: brightness(0.97);
}
.scc-ticket-count {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--t-brand-text, #5b2c86);
  font-size: 12px;
  font-weight: 700;
}
.scc-ticket-count.is-empty {
  color: var(--t-faint, #8a96a6);
  font-weight: 600;
}
.scc-actions-cell .btn + .btn {
  margin-left: 4px;
}

/* ---- Scheduled cancellations: fit the pane, never scroll sideways ----------
   Same treatment the service lists got: auto layout plus the global nowrap sized
   every column to its longest string, and the Supplier action column carries a
   free-text supplier reference -- "VOX31130760: CANCELLATION - PIETER MARIAS" --
   so one long cancellation ref set the width of the whole column. Measured
   against the real CSS the table needed 1877px in a 1559px pane, which put the
   Action column entirely off the right-hand edge and raised the scrollbar and the
   left/right arrows.

   Fixed layout makes width:100% binding, and the percentages below are ratios:
   the browser rescales whichever columns are currently visible to fill exactly
   100%, so the Columns toggles still fit. Full values stay in the title. */
body.spx-app .content-wrapper table.scc-table {
  table-layout: fixed;
  width: 100%;
}

/* Fixed layout stops long text widening the table, so it has to be clipped
   instead -- otherwise it spills over the next column. */
body.spx-app .content-wrapper table.scc-table > thead > tr > th,
body.spx-app .content-wrapper table.scc-table > tbody > tr > td {
  overflow: hidden;
  text-overflow: ellipsis;
}

/* .spx-clip caps these at 220px, which under fixed layout only fights the ratio:
   narrower than the column's share on a wide screen. The column width governs. */
body.spx-app .content-wrapper table.scc-table > tbody > tr > td.spx-clip,
body.spx-app .content-wrapper table.scc-table > tbody > tr > td.ic-username-cell {
  max-width: none;
  width: auto;
}

/* On a narrower window a column can end up shorter than a long pill
   ("Month-to-Month", "Awaiting Ignite"). Ellipsis inside the pill reads better
   than the cell slicing the word in half. */
body.spx-app .content-wrapper table.scc-table > tbody > tr > td .spx-pill {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: middle;
}

/* Supplier action is a flex button holding a status pill, the supplier's
   reference and the comment count. The reference is the only free-text part, so
   it is the part that gives way; the pill and the count keep their size. */
body.spx-app .content-wrapper table.scc-table td.scc-ticket-cell {
  white-space: nowrap;
}
.scc-ticket-open {
  min-width: 0;
  overflow: hidden;
}
/* The count is the part people scan, so it never gives. The pill can ellipsis,
   but only after the reference has gone: shrinkage is shared in proportion to
   (shrink factor x basis), so the factor of 100 on a ~30px reference outweighs
   the 1 on an 88px "Awaiting Ignite" pill by enough that the reference collapses
   first and the pill only starts clipping once there is nothing left to give. */
.scc-ticket-open > .scc-ticket-count {
  flex: 0 0 auto;
}
.scc-ticket-open > .spx-pill {
  flex: 0 1 auto;
  min-width: 0;
}
.scc-ticket-ref {
  flex: 0 100 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Two buttons at a narrow width stack instead of being clipped. The blanket
   `.spx-table ... > td { white-space: nowrap }` a few hundred lines up is (0,4,4),
   so this has to be scoped through the table to outrank it rather than set on the
   class alone. */
body.spx-app .content-wrapper table.scc-table > tbody > tr > td.scc-actions-cell {
  white-space: normal;
}
.scc-actions-cell .btn {
  margin-bottom: 2px;
}

body.spx-app .content-wrapper table.scc-table > thead > tr > th[data-col="username"] { width: 13.5%; }
body.spx-app .content-wrapper table.scc-table > thead > tr > th[data-col="supplier"] { width: 10.5%; }
body.spx-app .content-wrapper table.scc-table > thead > tr > th[data-col="ref_line"] { width: 8.5%; }
body.spx-app .content-wrapper table.scc-table > thead > tr > th[data-col="product"] { width: 13.5%; }
body.spx-app .content-wrapper table.scc-table > thead > tr > th[data-col="contract"] { width: 10%; }
body.spx-app .content-wrapper table.scc-table > thead > tr > th[data-col="created"] { width: 6.5%; }
body.spx-app .content-wrapper table.scc-table > thead > tr > th[data-col="activated"] { width: 7%; }
body.spx-app .content-wrapper table.scc-table > thead > tr > th[data-col="isp"] { width: 8%; }
body.spx-app .content-wrapper table.scc-table > thead > tr > th[data-col="client"] { width: 10.5%; }
body.spx-app .content-wrapper table.scc-table > thead > tr > th[data-col="status"] { width: 6%; }
body.spx-app .content-wrapper table.scc-table > thead > tr > th[data-col="deletes_on"] { width: 8.5%; }
body.spx-app .content-wrapper table.scc-table > thead > tr > th[data-col="supplier_action"] { width: 12%; }
body.spx-app .content-wrapper table.scc-table > thead > tr > th[data-col="row_action"] { width: 13%; }
.scc-ticket-summary {
  margin-bottom: 12px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--t-line-soft, #eef1f6);
  line-height: 1.45;
}
.scc-ticket-notes {
  margin-top: 8px;
  padding: 8px 10px;
  background: var(--t-surface-2, #f7f9fc);
  border-radius: 6px;
}
.scc-ticket-summary,
.scc-ticket-notes,
.scc-ticket-thread,
.scc-ticket-thread .spx-comment {
  overflow-wrap: anywhere;
  word-break: break-word;
}
.scc-ticket-thread {
  max-height: 360px;
  overflow-y: auto;
  overflow-x: hidden;
  margin-bottom: 16px;
}
.scc-ticket-thread .spx-comment.is-action {
  background: var(--t-tint-slate, #f8f6fb);
  margin: 0 -8px;
  padding: 8px;
  border-radius: 6px;
  border-bottom: 0;
}

body.spx-app .content-wrapper table.table > tbody > tr > td,
body.spx-app .content-wrapper table.dataTable > tbody > tr > td {
  font-size: 13px;
  color: var(--t-ink, #2c3340);
  border-top: 0 !important;
  border-bottom: 1px solid var(--t-line-soft, #eef2f7) !important;
  border-left: 0 !important;
  border-right: 0 !important;
  padding: 6px 10px !important;
  vertical-align: middle;
  line-height: 1.25;
}

body.spx-app .content-wrapper table.table > tbody > tr:hover > td,
body.spx-app .content-wrapper table.dataTable > tbody > tr:hover > td {
  background: var(--t-surface-2, #f7f9fc) !important;
}

body.spx-app .content-wrapper table.table-bordered,
body.spx-app .content-wrapper table.table-striped > tbody > tr:nth-of-type(odd) {
  background: transparent;
}

body.spx-app .content-wrapper table.table-striped > tbody > tr:nth-of-type(odd) > td {
  background: var(--t-surface, #fff) !important;
}

body.spx-app .content-wrapper table.table a:not(.btn),
body.spx-app .content-wrapper table.dataTable a:not(.btn) {
  color: var(--t-accent-text, #2f80ed);
  font-weight: 600;
}

/* DataTables chrome → Splynx show-entries / search / pager language */
body.spx-app .dataTables_wrapper {
  font-size: 13px;
  color: var(--t-muted, #6b7789);
}

body.spx-app .dataTables_wrapper .dataTables_length,
body.spx-app .dataTables_wrapper .dataTables_filter {
  margin-bottom: 10px;
}

body.spx-app .dataTables_wrapper .dataTables_length label,
body.spx-app .dataTables_wrapper .dataTables_filter label {
  font-weight: 400;
  color: var(--t-muted, #6b7789);
}

body.spx-app .dataTables_wrapper .dataTables_length select,
body.spx-app .dataTables_wrapper .dataTables_filter input {
  border: 1px solid #dfe5ee;
  border-radius: 4px;
  height: 30px;
  padding: 2px 8px;
  margin: 0 6px;
  color: var(--t-ink, #2c3340);
  background: var(--t-surface, #fff);
}

body.spx-app .dataTables_wrapper .dataTables_info {
  color: var(--t-faint, #8a96a6);
  padding-top: 10px;
}

body.spx-app .dataTables_wrapper .dataTables_paginate {
  padding-top: 8px;
}

/* DataTables Bootstrap puts .paginate_button on the <li>. Styling the li as a
   button leaves empty leftover boxes because the inner <a> is floated. */
body.spx-app .dataTables_wrapper .dataTables_paginate .paginate_button,
body.spx-app .dataTables_wrapper .dataTables_paginate .paginate_button:hover,
body.spx-app .dataTables_wrapper .dataTables_paginate .paginate_button.current,
body.spx-app .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover,
body.spx-app .dataTables_wrapper .dataTables_paginate .paginate_button.disabled,
body.spx-app .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover {
  border: 0 !important;
  background: transparent !important;
  padding: 0 !important;
  margin: 0 !important;
  color: inherit !important;
  box-shadow: none !important;
}

body.spx-app .dataTables_wrapper .dataTables_paginate .pagination > li > a,
body.spx-app .dataTables_wrapper .dataTables_paginate .pagination > li > span {
  display: inline-block;
  float: none;
  min-width: 32px;
  text-align: center;
  border: 1px solid var(--t-line, #e2e8f0) !important;
  background: var(--t-surface, #fff) !important;
  color: var(--t-muted, #4a5a6a) !important;
  border-radius: 6px !important;
  padding: 4px 10px !important;
  margin: 0 2px;
  line-height: 1.4;
}

body.spx-app .dataTables_wrapper .dataTables_paginate .pagination > li:not(.active):not(.disabled) > a:hover,
body.spx-app .dataTables_wrapper .dataTables_paginate .pagination > li:not(.active):not(.disabled) > span:hover {
  background: var(--t-tint-purple, #f4ecf8) !important;
  border-color: #d8c6ea !important;
  color: var(--t-brand-text, #5b2c86) !important;
}

body.spx-app .dataTables_wrapper .dataTables_paginate .pagination > .active > a,
body.spx-app .dataTables_wrapper .dataTables_paginate .pagination > .active > a:hover,
body.spx-app .dataTables_wrapper .dataTables_paginate .pagination > .active > span {
  background: #5b2c86 !important;
  border-color: #5b2c86 !important;
  color: #fff !important;
}

body.spx-app .dataTables_wrapper .dataTables_paginate .pagination > .disabled > a,
body.spx-app .dataTables_wrapper .dataTables_paginate .pagination > .disabled > a:hover,
body.spx-app .dataTables_wrapper .dataTables_paginate .pagination > .disabled > span {
  color: #b0b8c4 !important;
  background: #fff !important;
  border-color: #eef2f7 !important;
}

/* Info / detail cards: label on the left, value on the right — same as CRM Information */
/* Deliberately NOT align-items:start here, unlike the .ic-account-record grid
   further down. The children of THIS grid are .ic-kv rows, not cards, and each
   carries a 1px bottom divider. Measured on hostings#show: un-stretching them
   takes a row from 37px to 36px where its neighbour stays 37, so the divider
   steps by a pixel across the two columns. Stretch is what keeps those lines
   level. Only the account grid pairs whole cards, and only it needs start. */
body.spx-app .ic-record-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0;
  padding: 4px 8px 8px;
}

body.spx-app .ic-kv {
  display: grid;
  grid-template-columns: 150px 1fr;
  gap: 10px;
  align-items: center;
  margin: 0;
  padding: 8px 12px;
  border-bottom: 1px solid var(--t-line-soft, #eef2f7);
}

body.spx-app .ic-kv dt {
  margin: 0;
  text-align: right;
  font-size: 13px;
  font-weight: 600;
  color: var(--t-muted, #55556b);
}

body.spx-app .ic-kv dd {
  margin: 0;
  font-size: 13px;
  color: var(--t-ink, #1f1f2e);
}

body.spx-app .ic-record-section {
  grid-column: 1 / -1;
  margin: 10px 12px 0;
  padding: 8px 0 4px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--t-tint-purple-ink, #8a7a98);
  border-bottom: 1px solid #eadff2;
}

@media (max-width: 900px) {
  body.spx-app .ic-record-grid { grid-template-columns: 1fr; }
}

body.spx-app .ic-status,
body.spx-app .spx-pill {
  border-radius: 3px;
  font-weight: 600;
  padding: 3px 8px;
  font-size: 12px;
  line-height: 1.2;
}

body.spx-app .btn-default {
  background: var(--t-surface, #fff);
  border-color: #dfe5ee;
  color: var(--t-muted, #4a5a6a);
  font-weight: 600;
}

body.spx-app .btn-default:hover {
  background: var(--t-tint-purple, #f4ecf8);
  border-color: #d8c6ea;
  color: var(--t-brand-text, #5b2c86);
}

/* ---- 2026 shell polish (still Rails/AdminLTE under the hood) ----
   Tighten density, modernize form chrome, and make legacy pages share the CRM look
   without rewriting every ERB template. */

body.spx-app .spx-page {
  padding: 16px 28px 48px;
  overflow: visible;
}

body.spx-app .spx-toolbar,
body.spx-app .spx-record-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}

body.spx-app .spx-crumb {
  display: block;
  font-size: 12px;
  font-weight: 600;
  color: var(--t-faint, #8a96a6);
  letter-spacing: 0.01em;
  margin-bottom: 2px;
}

body.spx-app .spx-crumb a {
  color: var(--t-muted, #6b7789);
  font-weight: 600;
}

body.spx-app .spx-crumb a:hover {
  color: var(--t-brand-text, #5b2c86);
  text-decoration: none;
}

body.spx-app .spx-title,
body.spx-app .content-header h1 {
  font-family: "Source Sans 3", "Segoe UI", Helvetica, Arial, sans-serif;
  letter-spacing: -0.01em;
}

body.spx-app .content-wrapper .box.spx-card,
body.spx-app .content-wrapper .spx-widget,
body.spx-app .ic-record,
body.spx-app .ic-form-shell,
body.spx-app .content-wrapper .box:not(.spx-card) {
  border-radius: 8px !important;
  border-color: var(--t-line, #dde3ec) !important;
  overflow: hidden;
}

body.spx-app .spx-kpi {
  border-radius: 8px;
  border-color: var(--t-line, #dde3ec);
  transition: box-shadow 0.15s ease, border-color 0.15s ease;
}

body.spx-app .spx-kpi:hover {
  border-color: #c9b3de;
  box-shadow: 0 8px 20px rgba(40, 30, 60, 0.08);
}

body.spx-app .btn,
body.spx-app .btn-sm,
body.spx-app .btn-xs {
  border-radius: 6px !important;
  font-family: "Source Sans 3", "Segoe UI", Helvetica, Arial, sans-serif;
  letter-spacing: 0.01em;
  transition: background-color 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}

body.spx-app .btn-primary,
body.spx-app .btn.spx-btn-primary,
body.spx-app .spx-btn-primary {
  background: #5b2c86 !important;
  border-color: #5b2c86 !important;
  color: #fff !important;
  box-shadow: 0 1px 0 rgba(91, 44, 134, 0.18);
}

body.spx-app .btn-primary:hover,
body.spx-app .btn.spx-btn-primary:hover,
body.spx-app .spx-btn-primary:hover {
  background: #4a216e !important;
  border-color: #4a216e !important;
  color: #fff !important;
}

body.spx-app .btn-success,
body.spx-app .spx-toolbar-actions .btn-success,
body.spx-app .content-header .btn-success {
  background: #1f9d55 !important;
  border-color: #1f9d55 !important;
  color: #fff !important;
}

body.spx-app .btn-success:hover {
  background: #18864a !important;
  border-color: #18864a !important;
  color: #fff !important;
}

body.spx-app .form-control,
body.spx-app .selectize-input {
  border-radius: 6px !important;
  border-color: #d5dde8 !important;
  box-shadow: none !important;
  min-height: 34px;
  /* 13px, down from the 13.5px this was, NOT up to 14px. .form-control pins a
     36px height, so a selectize item that wraps is clipped rather than grown:
     at 14px "Zirk Steyn (support@infinityconnect.co.za)" on the CRM ticket
     form wrapped to two lines and needed 52px in a 34px box. 13px is the
     app's body size and keeps it on one line. */
  font-size: 13px;
  color: var(--t-tint-blue-ink, #243041);
  transition: border-color 0.12s ease, box-shadow 0.12s ease;
}

body.spx-app .form-control:focus,
body.spx-app .selectize-input.focus {
  border-color: var(--t-brand, #5b2c86) !important;
  box-shadow: 0 0 0 3px rgba(91, 44, 134, 0.12) !important;
}

body.spx-app .nav-tabs > li > a {
  border-radius: 6px 6px 0 0 !important;
  font-weight: 600;
}

body.spx-app .nav-tabs.spx-record-tabs {
  border-bottom: 1px solid var(--t-line, #dde3ec);
  margin-bottom: 0;
  background: transparent;
}

body.spx-app .nav-tabs.spx-record-tabs > li > a {
  color: var(--t-muted, #6b7789);
  border: 0 !important;
  background: transparent !important;
  padding: 12px 14px;
}

body.spx-app .nav-tabs.spx-record-tabs > li.active > a,
body.spx-app .nav-tabs.spx-record-tabs > li.active > a:hover,
body.spx-app .nav-tabs.spx-record-tabs > li.active > a:focus {
  color: var(--t-brand-text, #5b2c86) !important;
  border: 0 !important;
  border-bottom: 3px solid var(--t-brand, #5b2c86) !important;
  background: transparent !important;
}

body.spx-app .spx-record-body,
body.spx-app .box.spx-card.spx-record-body {
  border-top-left-radius: 0 !important;
  border-top-right-radius: 0 !important;
}

body.spx-app .content-wrapper .small-box,
body.spx-app .content-wrapper a.ic-stat-card {
  border-radius: 4px !important;
  border: 0 !important;
  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1) !important;
}

body.spx-app .content-wrapper .small-box .inner h3,
body.spx-app .content-wrapper a.ic-stat-card .inner h3 {
  font-family: "Source Sans 3", "Segoe UI", Helvetica, Arial, sans-serif;
  font-weight: 700;
  color: #fff !important;
}

body.spx-app .content-wrapper .ic-stat-archive .inner h3,
body.spx-app .content-wrapper .small-box.bg-gray .inner h3 {
  color: var(--t-tint-slate-ink, #111) !important;
}

body.spx-app .ic-brand {
  letter-spacing: 0.02em;
}

body.spx-app .sidebar-menu > li > a {
  border-radius: 8px;
  margin: 2px 8px;
  font-weight: 600;
  font-size: 14px;
}

body.spx-app .sidebar-search input.form-control {
  border-radius: 8px !important;
  padding-left: 12px;
  height: 34px;
}

body.spx-app .label,
body.spx-app .badge {
  border-radius: 4px;
  font-weight: 600;
}

body.spx-app .alert {
  border-radius: 8px;
  border-width: 1px;
  box-shadow: none;
}

body.spx-app .pagination {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  padding-left: 0;
  margin: 0;
}

/* Bootstrap 3 clearfix ghosts become extra empty boxes under display:flex. */
body.spx-app .pagination::before,
body.spx-app .pagination::after {
  display: none !important;
  content: none !important;
}

body.spx-app .pagination > li {
  display: inline-block;
  float: none;
}

body.spx-app .pagination > li > a,
body.spx-app .pagination > li > span {
  border-radius: 6px !important;
  margin: 0 2px;
  border-color: var(--t-line, #dde3ec);
  color: var(--t-muted, #4a5a6a);
  float: none;
}

body.spx-app .pagination > .active > a,
body.spx-app .pagination > .active > a:hover,
body.spx-app .pagination > .active > a:focus,
body.spx-app .pagination > .active > span,
body.spx-app .pagination > .active > span:hover {
  background: #5b2c86 !important;
  border-color: #5b2c86 !important;
  color: #fff !important;
}

body.spx-app .pagination > .disabled > a,
body.spx-app .pagination > .disabled > a:hover,
body.spx-app .pagination > .disabled > span {
  color: #b0b8c4 !important;
  background: #fff !important;
  border-color: #eef2f7 !important;
}

body.spx-app .content-header {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  padding: 18px 24px 4px;
}

body.spx-app .content-header > h1 {
  flex: 1 1 auto;
  margin: 0 !important;
}

body.spx-app .content-header > p,
body.spx-app .content-header > .btn,
body.spx-app .content-header > .btn-group,
body.spx-app .content-header > a.btn {
  margin-top: 4px;
}

body.spx-app .table-responsive {
  border-radius: 0;
}

body.spx-app .dataTables_wrapper .dataTables_filter input {
  border-radius: 6px !important;
}

body.spx-app .selectize-dropdown {
  border-radius: 8px;
  border-color: var(--t-line, #dde3ec);
  box-shadow: 0 12px 28px rgba(30, 40, 60, 0.12);
  z-index: 20000;
}

body.spx-app .selectize-dropdown.spx-crm-watcher-drop {
  z-index: 20000;
}

.spx-watch {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  color: var(--t-tint-blue-ink, #8a93a3);
  font-size: 16px;
}
.spx-watch:hover,
.spx-watch:focus { color: var(--t-tint-amber-ink, #c9a227); text-decoration: none; }
.spx-watch.is-watching { color: var(--t-tint-amber-ink, #c9a227); }
.spx-ticket-actions .spx-watch {
  vertical-align: middle;
  margin-left: 4px;
}
.spx-ticket-actions a.spx-watch.is-watching,
.spx-ticket-actions a.spx-watch.is-watching i {
  color: var(--t-tint-amber-ink, #c9a227) !important;
}

.spx-menu-search {
  padding: 6px 10px;
}
.spx-menu-search .form-control {
  min-width: 180px;
}
.spx-searchable-menu {
  max-height: 280px;
  overflow-y: auto;
}

/* Login shell inherits Source Sans 3 when devise layout loads the font */
body#login,
#login,
.container-login100 {
  font-family: "Source Sans 3", "Segoe UI", Helvetica, Arial, sans-serif;
}

/* ---- Service detail blocks (compact Somali-style) ----
   Cap width, stack Client/Billing beside Service, keep label/value tight. */
.ic-service-record {
  display: flex;
  flex-direction: column;
  gap: 14px;
  width: 100%;
  max-width: 860px;
}

.ic-service-hero {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  padding: 14px 16px;
  background: var(--t-surface, #fff);
}

.ic-service-hero .ic-record-kicker {
  margin: 0 0 2px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--t-brand-text, #5b2c86);
}

.ic-service-hero h2 {
  margin: 0 0 2px;
  font-size: 18px;
  font-weight: 700;
  color: var(--t-tint-blue-ink, #1a202c);
  line-height: 1.25;
}

.ic-service-hero .ic-record-sub {
  margin: 0;
  color: var(--t-tint-blue-ink, #4a5568);
  font-size: 12px;
}

.ic-service-hero-meta {
  text-align: right;
  flex-shrink: 0;
}

.ic-service-hero-meta .ic-price {
  display: block;
  margin-top: 4px;
  font-size: 16px;
  font-weight: 700;
  color: var(--t-tint-blue-ink, #1a202c) !important;
  line-height: 1.2;
}

.ic-service-hero-meta .ic-price-label {
  display: block;
  font-size: 11px;
  color: var(--t-tint-blue-ink, #4a5568);
}

.ic-service-blocks {
  display: grid;
  grid-template-columns: 1.2fr 1fr;
  gap: 14px;
  align-items: start;
}

/* Service card sits left; Client + Billing stack on the right. */
.ic-service-blocks > .ic-service-block:first-child {
  grid-row: 1 / span 2;
}

.ic-service-block {
  padding: 0;
  overflow: hidden;
  background: var(--t-surface, #fff);
}

.ic-service-block-title {
  margin: 0;
  padding: 10px 14px;
  font-size: 12px;
  font-weight: 700;
  color: var(--t-ink, #2c3340) !important;
  border-bottom: 1px solid #e4ebf2;
  background: var(--t-surface-3, #eef1f6);
}

.ic-service-fields {
  padding: 4px 0 6px;
  background: var(--t-surface, #fff);
}

.ic-service-fields .ic-kv {
  display: grid;
  grid-template-columns: 100px minmax(0, 1fr);
  gap: 8px;
  align-items: start;
  margin: 0;
  padding: 8px 14px;
  border-bottom: 1px solid var(--t-line-soft, #eef2f7);
  background: var(--t-surface, #fff);
}

.ic-service-fields .ic-kv:last-child {
  border-bottom: 0;
}

body.spx-app .ic-service-fields .ic-kv dt,
.ic-service-fields .ic-kv dt {
  margin: 0;
  max-width: none;
  text-align: left;
  font-size: 12px;
  font-weight: 700;
  color: var(--t-tint-blue-ink, #4a5568) !important;
  line-height: 1.35;
}

body.spx-app .ic-service-fields .ic-kv dd,
.ic-service-fields .ic-kv dd {
  margin: 0;
  text-align: left;
  font-size: 13px;
  font-weight: 500;
  color: var(--t-tint-blue-ink, #1a202c) !important;
  word-break: break-word;
  line-height: 1.35;
}

body.spx-app .ic-service-block-title,
.ic-service-block-title {
  color: var(--t-ink, #2c3340) !important;
  background: var(--t-surface-3, #eef1f6);
}

.ic-service-actions {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 10px 12px;
  background: var(--t-surface, #fff);
}

.ic-service-actions-primary,
.ic-service-actions-secondary {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.ic-service-actions .btn {
  padding: 5px 10px;
  font-size: 12px;
  font-weight: 600;
  box-shadow: none !important;
}

/* One CRM palette — no Bootstrap rainbow on service records. */
.ic-service-actions .btn-primary,
.ic-service-actions .btn-success,
.ic-service-actions .btn-info {
  background: #5b2c86 !important;
  border-color: #5b2c86 !important;
  color: #fff !important;
}

.ic-service-actions .btn-primary:hover,
.ic-service-actions .btn-success:hover,
.ic-service-actions .btn-info:hover {
  background: #4a216e !important;
  border-color: #4a216e !important;
  color: #fff !important;
}

.ic-service-actions .btn-warning {
  background: var(--t-surface, #fff) !important;
  border-color: #c9a227 !important;
  color: var(--t-tint-amber-ink, #8a6d12) !important;
}

.ic-service-actions .btn-warning:hover {
  background: var(--t-tint-amber, #fff8e6) !important;
  border-color: #a88410 !important;
  color: var(--t-tint-amber-ink, #6e560c) !important;
}

.ic-service-actions .btn-danger {
  background: var(--t-surface, #fff) !important;
  border-color: #d63b3b !important;
  color: var(--t-danger-text, #c0392b) !important;
}

.ic-service-actions .btn-danger:hover {
  background: var(--t-tint-slate, #fdf2f2) !important;
  border-color: #b83a3a !important;
  color: var(--t-tint-red-ink, #a93226) !important;
}

.ic-service-actions .btn-default {
  background: var(--t-surface, #fff) !important;
  border-color: #dfe5ee !important;
  color: var(--t-muted, #4a5a6a) !important;
}

.ic-service-actions .btn-default:hover {
  background: var(--t-tint-purple, #f4ecf8) !important;
  border-color: #d8c6ea !important;
  color: var(--t-brand-text, #5b2c86) !important;
}

body.spx-app .ic-service-hero-meta .ic-price,
.ic-service-hero-meta .ic-price {
  color: var(--t-tint-blue-ink, #1a202c) !important;
}

.ic-service-hero-meta .ic-status.is-active,
.ic-service-hero-meta .spx-pill.spx-status-active,
.ic-service-fields .ic-status.is-active,
.ic-service-fields .spx-pill.spx-status-active {
  background: #5b2c86;
  color: #fff;
  border: 0;
}

.ic-service-fields a {
  color: var(--t-brand-text, #5b2c86) !important;
  font-weight: 600;
}

@media (max-width: 720px) {
  .ic-service-blocks {
    grid-template-columns: 1fr;
  }

  .ic-service-blocks > .ic-service-block:first-child {
    grid-row: auto;
  }

  .ic-service-hero {
    flex-direction: column;
    align-items: flex-start;
  }

  .ic-service-hero-meta {
    text-align: left;
  }
}

/* Account detail: spx-app was forcing .ic-record-grid to gap:0 / 2-col, so Service
   and Fibre cards sat flush. Restore gutters and a clear card grid. */
body.spx-app .ic-account-record {
  background: var(--t-surface, #fff) !important;
}

body.spx-app .ic-account-record .ic-record-grid {
  display: grid !important;
  grid-template-columns: 1fr 1fr;
  /* align-items, NOT the grid default of stretch. Two cards share a row, and
     stretch made the short one as tall as the tall one. Measured on the MTN LTE
     account 7z3l@: Installation holds two fields and was forced to 640px to
     match Device, Delivery to 818px to match Service -- 802px of empty white
     card on that one page, 3216px of card for 2414px of content.

     Note this does not shorten the page: the grid ROW is still as tall as its
     tallest card either way. What changes is that the short card now ends where
     its content ends and the remainder is page background, instead of being a
     tall half-empty white box. That box is what "the spacing is wrong, it looks
     on top of each other" was describing. */
  align-items: start;
  gap: 20px 24px !important;
  padding: 20px 24px 24px !important;
  background: var(--t-tint-slate, #eef1f5) !important;
}

body.spx-app .ic-account-record .ic-record-block {
  background: var(--t-surface, #fff) !important;
  border: 1px solid var(--t-line, #dde3ec) !important;
  border-radius: 8px !important;
  overflow: hidden;
  box-shadow: 0 1px 2px rgba(30, 40, 60, 0.04);
}

body.spx-app .ic-account-record .ic-record-section {
  background: var(--t-tint-slate, #f4f7fb) !important;
  border-bottom: 1px solid #e4eaf1 !important;
  color: var(--t-tint-blue-ink, #243041) !important;
  padding: 12px 16px !important;
  font-size: 12px !important;
  letter-spacing: 0.04em;
}

body.spx-app .ic-account-record .ic-record-fields {
  display: grid;
  grid-template-columns: 1fr;
}

body.spx-app .ic-account-record .ic-record-fields .ic-kv:nth-child(odd) {
  border-right: 0;
}

body.spx-app .ic-account-record .ic-kv {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 16px;
  grid-template-columns: none;
  padding: 10px 16px;
  border-bottom: 1px solid #f0f3f7;
}

body.spx-app .ic-account-record .ic-kv dt {
  flex: 0 0 auto;
  max-width: 42%;
  text-align: left;
  color: var(--t-faint, #8a96a6);
  font-size: 12px;
  font-weight: 600;
}

body.spx-app .ic-account-record .ic-kv dd {
  flex: 1 1 auto;
  text-align: right;
  font-size: 13px;
}

/* Everything below the card grid is a free-standing card, and every one of
   them had margin-top 0. Measured on an LTE record at 1799px, the gaps between
   the record's top-level blocks were 0, 0, 0 and 0 -- the usage panel's bottom
   edge and the COMMENTS panel's top edge were literally the same pixel. Sean:
   "i still see this is to close to each other".

   These panels also sat 24px wider on each side than the cards above them,
   because .ic-record-grid insets its children by 24px and these live outside
   it, so the page stepped in and out as you scrolled. One inset, one rhythm. */
body.spx-app .ic-account-record > .ic-usage-panel,
body.spx-app .ic-account-record > .ic-usage-panel-lazy,
body.spx-app .ic-account-record > .ic-service-invoices-lazy,
body.spx-app .ic-account-record > .ic-service-mailboxes-lazy,
body.spx-app .ic-account-record > .ic-service-disk-lazy,
body.spx-app .ic-account-record > .ic-reseller-estate-lazy {
  margin: 24px 24px 0 !important;
}

body.spx-app .ic-account-record > .ic-history {
  margin: 24px 24px 24px !important;
  border: 0 !important;
  border-radius: 0 !important;
  background: transparent !important;
  display: grid !important;
  grid-template-columns: 1fr 1fr;
  gap: 20px 24px !important;
  padding: 0 !important;
}

body.spx-app .ic-account-record .ic-history-panel {
  background: var(--t-surface, #fff);
  border: 1px solid var(--t-line, #dde3ec) !important;
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 1px 2px rgba(30, 40, 60, 0.04);
}

body.spx-app .ic-account-record .ic-history-panel:nth-child(2n),
body.spx-app .ic-account-record .ic-history-panel:last-child:nth-child(odd) {
  border-right: 1px solid var(--t-line, #dde3ec) !important;
}

body.spx-app .ic-account-record .ic-history-panel header {
  background: var(--t-tint-slate, #f4f7fb);
  border-bottom-color: #e4eaf1;
}

body.spx-app .ic-account-record > .ic-record-actions {
  padding: 12px 20px 16px !important;
  gap: 12px 20px;
  flex-wrap: wrap;
}

body.spx-app .ic-account-toolbar .btn-default,
body.spx-app .ic-account-toolbar .btn-default:visited {
  background: var(--t-surface, #fff) !important;
  border-color: #d5dee9 !important;
  color: var(--t-ink, #2c3340) !important;
}

body.spx-app .ic-account-toolbar .btn-default:hover,
body.spx-app .ic-account-toolbar .btn-default:focus {
  background: var(--t-tint-purple, #f4ecf8) !important;
  border-color: #d8c6ea !important;
  color: var(--t-brand-text, #5b2c86) !important;
}

body.spx-app .ic-account-toolbar .btn-success,
body.spx-app .ic-account-toolbar .btn-success:visited {
  background: #157347 !important;
  border-color: #157347 !important;
  color: #fff !important;
}

body.spx-app .ic-account-toolbar .btn-warning,
body.spx-app .ic-account-toolbar .btn-warning:visited {
  background: var(--t-surface, #fff) !important;
  border-color: #e0a106 !important;
  color: var(--t-tint-amber-ink, #9a6700) !important;
}

body.spx-app .ic-account-toolbar .btn-danger,
body.spx-app .ic-account-toolbar .btn-danger:visited {
  background: var(--t-surface, #fff) !important;
  border-color: #d63b3b !important;
  color: var(--t-danger-text, #c0392b) !important;
}

@media (max-width: 960px) {
  body.spx-app .ic-account-record .ic-record-grid,
  body.spx-app .ic-account-record > .ic-history {
    grid-template-columns: 1fr;
  }
}

/* CRM list screens: keep filters and columns from shoving the table off-screen. */
body.spx-app .spx-toolbar-actions,
body.spx-app .spx-filters,
body.spx-app .spx-table-tools,
body.spx-app .spx-list-controls {
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

body.spx-app form.spx-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 8px;
}

body.spx-app form.spx-filters > label {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin: 0;
  overflow: visible;
  font-weight: 600;
  color: var(--t-tint-slate-ink, #5b6775);
  font-size: 12px;
}

body.spx-app .spx-ticket-bar {
  position: relative;
  z-index: 30;
  margin: 0 0 12px;
  overflow: visible;
}

body.spx-app .spx-ticket-bar .spx-cancel-filter,
body.spx-app .spx-ticket-bar .spx-vhost-filter,
body.spx-app .spx-ticket-bar .spx-unlinked-filter {
  align-self: flex-end;
}

body.spx-app .spx-ticket-bar .btn {
  align-self: flex-end;
}

body.spx-app .spx-table-tools {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
}

body.spx-app .spx-search {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-left: auto;
}

body.spx-app .js-spx-cols-host {
  display: inline-block;
}

body.spx-app table.spx-table > tbody > tr.spx-row-detail > td {
  background: var(--t-surface-2, #f7f9fc);
}

body.spx-app .spx-page .table-responsive {
  max-height: calc(100vh - 380px);
}

/* Table link colour must not paint onto buttons (blue-on-blue "Mark loaded"). */
body.spx-app .btn-primary,
body.spx-app .btn-success,
body.spx-app .btn-info,
body.spx-app .btn-danger,
body.spx-app .btn-warning,
body.spx-app .spx-btn-primary,
body.spx-app a.btn-primary,
body.spx-app a.btn-success,
body.spx-app a.btn-info,
body.spx-app a.btn-danger,
body.spx-app a.btn-warning,
body.spx-app a.spx-btn-primary,
body.spx-app .content-wrapper table a.btn-primary,
body.spx-app .content-wrapper table a.btn-success,
body.spx-app .content-wrapper table a.btn-info,
body.spx-app .content-wrapper table a.btn-danger,
body.spx-app .content-wrapper table a.btn-warning,
body.spx-app .content-wrapper table a.spx-btn-primary {
  color: #fff !important;
}

body.spx-app .btn-default,
body.spx-app a.btn-default,
body.spx-app .content-wrapper table a.btn-default {
  color: var(--t-ink-2, #334155) !important;
}

body.spx-app .content-wrapper table td .btn,
body.spx-app .content-wrapper table a.btn {
  overflow: visible;
  text-overflow: clip;
  white-space: nowrap;
  max-width: none;
}

radiusx-ipam-bar {
  display: inline-block;
  width: 88px;
  height: 8px;
  margin-left: 8px;
  vertical-align: middle;
  background: var(--t-tint-purple, #ececf5);
  border-radius: 4px;
  overflow: hidden;
}
.spx-ipam-bar span {
  display: block;
  height: 100%;
  background: #207ab7;
}
.spx-tab-toolbar .form-control.input-sm {
  display: inline-block;
  width: auto;
  min-width: 220px;
  margin-right: 8px;
}
.spx-attach-thumbs {
  margin-top: 8px;
}
.spx-attach-thumbs img {
  max-width: 220px;
  max-height: 160px;
  margin: 4px 8px 0 0;
  border: 1px solid #e4e4ee;
  border-radius: 4px;
}
.spx-attach-file {
  display: inline-block;
  margin-right: 10px;
}

/* Splynx-style ticket hover: floating short review of the opening message. */
.spx-ticket-preview { display: none; }

/* The preview badge is the only thing that opens the hover card.
   Small and deliberately aimed-at: the trigger used to be the whole subject
   cell, the widest column on the page, so the card fired whenever the pointer
   crossed it on the way somewhere else. */
body.spx-app .spx-preview-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  margin-right: 8px;
  vertical-align: -4px;
  border-radius: 4px;
  font-size: 11px;
  cursor: pointer;
  color: var(--t-tint-slate-ink, #606d7f);
  background: var(--t-tint-slate, #eef1f6);
  border: 1px solid var(--t-line, #e2e8f0);
}

body.spx-app .spx-preview-badge:hover,
body.spx-app .spx-preview-badge:focus {
  color: #fff;
  background: var(--t-brand, #5b2c86);
  border-color: var(--t-brand, #5b2c86);
  outline: none;
}
.spx-ticket-hover {
  display: none;
  position: fixed;
  z-index: 1040;
  width: 540px;
  max-width: calc(100vw - 24px);
  background: var(--t-surface, #fff);
  border: 1px solid #d7dee8;
  border-radius: 4px;
  box-shadow: 0 10px 28px rgba(30, 40, 60, 0.18);
}
.spx-ticket-hover.is-open { display: block; }
.spx-ticket-hover-arrow {
  position: absolute;
  top: -7px;
  width: 12px;
  height: 12px;
  background: var(--t-surface, #fff);
  border-left: 1px solid #d7dee8;
  border-top: 1px solid #d7dee8;
  transform: rotate(45deg);
}
.spx-ticket-hover.is-above .spx-ticket-hover-arrow {
  top: auto;
  bottom: -7px;
  border-left: 0;
  border-top: 0;
  border-right: 1px solid #d7dee8;
  border-bottom: 1px solid #d7dee8;
}
.spx-ticket-hover-subject {
  font-weight: 700;
  font-size: 14px;
  color: var(--t-ink, #2c3340);
  padding: 10px 14px 8px;
  border-bottom: 1px solid #f0f3f8;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.spx-ticket-hover .spx-msg {
  margin: 8px 10px 10px;
}
.spx-ticket-hover .spx-msg-head {
  align-items: flex-start;
}
.spx-ticket-hover-person {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  min-width: 0;
}
.spx-ticket-hover-person .spx-avatar {
  margin-top: 2px;
}
.spx-ticket-hover .spx-msg-body {
  max-height: 180px;
  overflow-y: auto;
  font-size: 13px;
  line-height: 1.45;
  color: var(--t-ink, #2c3340);
}

/* Ticket list: denser rows, live badge, compact customer + timestamps. */
.spx-title .spx-live-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-left: 10px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--t-tint-green-ink, #2f9e6b);
  vertical-align: middle;
}
.spx-live-badge::before {
  content: '';
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #2f9e6b;
  box-shadow: 0 0 0 0 rgba(47, 158, 107, 0.45);
  animation: spx-live-pulse 2s ease-out infinite;
}
.spx-live-badge.is-paused {
  color: var(--t-faint, #9a9ab0);
}
.spx-live-badge.is-paused::before {
  background: #9a9ab0;
  animation: none;
}
@keyframes spx-live-pulse {
  0% { box-shadow: 0 0 0 0 rgba(47, 158, 107, 0.45); }
  70% { box-shadow: 0 0 0 6px rgba(47, 158, 107, 0); }
  100% { box-shadow: 0 0 0 0 rgba(47, 158, 107, 0); }
}

.spx-tickets-table td.spx-subject {
  max-width: 420px;
  overflow: hidden;
}
.spx-tickets-table td.spx-subject > a {
  display: inline-block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: middle;
}
.spx-tickets-table td.spx-subject .spx-labels {
  display: inline;
  margin: 0 0 0 6px;
  vertical-align: middle;
}
.spx-tickets-table td.spx-customer-cell {
  max-width: 200px;
}
.spx-tickets-table td.spx-email-cell {
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 12px;
  color: var(--t-tint-blue-ink, #4a5568);
}
.spx-tickets-table .spx-customer {
  align-items: center;
  min-width: 0;
}
.spx-tickets-table .spx-customer-name {
  display: block;
  min-width: 0;
  max-width: 170px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.spx-tickets-table td.spx-time {
  font-variant-numeric: tabular-nums;
  color: var(--t-muted, #5b6b7c);
}
.spx-tickets-table > tbody > tr:not(.spx-row-detail) > td {
  padding-top: 3px;
  padding-bottom: 3px;
}
.spx-tickets-table > tbody > tr.spx-row-fresh > td {
  animation: spx-row-flash 1.6s ease-out;
}
@keyframes spx-row-flash {
  from { background: var(--t-tint-purple, #f3eefb); }
  to { background: transparent; }
}

body.spx-app .spx-cancel-filter {
  font-weight: 700;
  border-color: var(--t-danger, #c0392b);
  color: var(--t-danger-text, #c0392b);
}
body.spx-app a.spx-cancel-filter.spx-btn-primary {
  border-color: #8e2a21;
  color: #fff;
}
body.spx-app .spx-vhost-filter {
  font-weight: 700;
  border-color: var(--t-brand, #5b2c86);
  color: var(--t-brand-text, #5b2c86);
}
body.spx-app a.spx-vhost-filter.spx-btn-primary {
  border-color: #452066;
  color: #fff;
}
body.spx-app .spx-unlinked-filter {
  font-weight: 700;
  border-color: #b45309;
  color: var(--t-tint-amber-ink, #b45309);
}
body.spx-app a.spx-unlinked-filter.spx-btn-primary {
  border-color: #92400e;
  color: #fff;
}
.spx-vhost-action {
  margin: 0 16px 12px;
}

/* ---------- Global records search (top of every staff page) ----------
   The icon lives in the markup; without these rules it sits on its own
   line above a full-width Bootstrap .form-control.

   The bottom padding is load-bearing. Without it the bar ended at the search
   input's own bottom edge, so whatever rendered next began there: on the
   Services lists the record icon and breadcrumb touched the input with nothing
   between them. Two rules further down used to buy that gap back for the
   elements that happened to follow -- a section and a content-header -- and the
   66 templates whose page head is a direct child of .content-wrapper were not
   among them. The space belongs to the bar, so it is charged once here and
   those two compensations are now zero. */
.ic-records-search-bar {
  padding: 12px 28px;
  overflow: visible;
}

.ic-records-search-bar form {
  margin: 0;
}

.ic-global-search--bar {
  max-width: 560px;
}

.ic-global-search-field {
  position: relative;
  display: block;
}

.ic-global-search-field .ic-global-search-icon {
  position: absolute;
  left: 12px;
  top: 50%;
  width: 16px;
  margin: 0;
  color: var(--t-tint-slate-ink, #6f7c90);
  font-size: 14px;
  line-height: 1;
  text-align: center;
  z-index: 2;
  pointer-events: none;
  -webkit-transform: translateY(-50%);
  transform: translateY(-50%);
}

.ic-global-search-kbd {
  position: absolute;
  right: 10px;
  top: 50%;
  padding: 2px 6px;
  border: 1px solid #d5dde8;
  border-radius: 4px;
  background: var(--t-tint-slate, #f4f6fa);
  color: var(--t-tint-blue-ink, #647082);
  font-family: "Source Sans 3", "Segoe UI", Helvetica, Arial, sans-serif;
  font-size: 11px;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: 0.02em;
  z-index: 2;
  pointer-events: none;
  -webkit-transform: translateY(-50%);
  transform: translateY(-50%);
}

.ic-global-search--bar .form-control.js-global-search,
body.spx-app .ic-global-search--bar .form-control.js-global-search {
  display: block;
  width: 100%;
  height: 40px !important;
  min-height: 40px !important;
  max-height: 40px !important;
  line-height: 24px !important;
  padding: 7px 76px 7px 36px !important;
  border: 1px solid #c5d0de !important;
  border-radius: 10px !important;
  background: var(--t-surface, #fff) !important;
  color: var(--t-ink, #1b2433) !important;
  font-size: 14px !important;
  box-shadow: 0 1px 2px rgba(18, 24, 38, 0.06) !important;
  box-sizing: border-box;
  -webkit-appearance: none;
  appearance: none;
}

.ic-global-search--bar .form-control.js-global-search:focus,
body.spx-app .ic-global-search--bar .form-control.js-global-search:focus {
  border-color: var(--t-brand, #5b2c86) !important;
  outline: none;
  box-shadow: 0 0 0 3px rgba(91, 44, 134, 0.14) !important;
}

.ic-global-search--bar .form-control.js-global-search::-webkit-input-placeholder {
  color: var(--t-faint, #8a96a6);
  line-height: 24px;
}
.ic-global-search--bar .form-control.js-global-search::-moz-placeholder {
  color: var(--t-faint, #8a96a6);
  opacity: 1;
  line-height: 24px;
}
.ic-global-search--bar input[type="search"]::-webkit-search-decoration,
.ic-global-search--bar input[type="search"]::-webkit-search-cancel-button,
.ic-global-search--bar input[type="search"]::-webkit-search-results-button,
.ic-global-search--bar input[type="search"]::-webkit-search-results-decoration {
  -webkit-appearance: none;
}

/* Nothing to add: the search bar now carries its own 12px below itself, so a
   first child that sets its own top padding would stack a second gap on top of
   it. Zero rather than deleted -- without these the section's 16px and the
   content-header's 12px come back and every dashboard gains a gap it did not
   have before. */
body.spx-app .content-wrapper:has(> .ic-records-search-bar) > .content.spx-page {
  padding-top: 0;
}

.content-wrapper:has(> .ic-records-search-bar) > .content-header:first-child,
.content-wrapper:has(> .ic-records-search-bar) > .ic-dashboard > .content-header:first-child {
  padding-top: 0;
}

/* One gutter down the whole column.
   66 templates render the page head *before* <section class="content spx-page">,
   so the head lands as a direct child of .content-wrapper and inherits no
   horizontal padding at all, while the search bar above it and the card below it
   are both inset 28px. The purple record icon therefore sat hard against the
   sidebar and the head's action button against the right edge. The Back bar
   carried a third value again, 15px from ic-theme.css.
   Pad the strays to match the section rather than moving the render inside
   .content in every one of those templates. Direct children only: a head that
   already sits inside .content is padded by it and must not be padded twice. */
.content-wrapper > .spx-record-head,
.content-wrapper > .spx-toolbar,
.content-wrapper > .spx-hint,
.content-wrapper > .ic-back-bar {
  padding-left: 22px;
  padding-right: 22px;
}

body.spx-app .content-wrapper > .spx-record-head,
body.spx-app .content-wrapper > .spx-toolbar,
body.spx-app .content-wrapper > .spx-hint,
body.spx-app .content-wrapper > .ic-back-bar {
  padding-left: 28px;
  padding-right: 28px;
}

/* The Back bar had no bottom padding, so the breadcrumb sat directly under the
   button with the two reading as one stack. The hidden PDF modal renders between
   them, so an adjacent-sibling rule would not match. */
.content-wrapper > .ic-back-bar {
  padding-bottom: 8px;
}

/* Subtitle under the page title, inside the head. Quieter than the title and
   sized like the crumb above it, so the block reads as one heading. */
.spx-head-sub {
  margin: 3px 0 0;
  font-size: 13px;
  line-height: 1.35;
  color: var(--t-muted, #6b7789);
}

.ic-global-search-panel {
  position: fixed;
  z-index: 2000;
  margin: 0;
  padding: 6px 0;
  background: var(--t-surface, #fff);
  border: 1px solid var(--t-line, #dde3ec);
  border-radius: 10px;
  box-shadow: 0 12px 40px rgba(20, 28, 45, 0.18);
  overflow: auto;
  -webkit-overflow-scrolling: touch;
}

.ic-global-search-panel[hidden] {
  display: none !important;
}

.ic-global-search-panel-inner {
  min-width: 0;
}

.ic-gs-empty {
  margin: 0;
  padding: 14px 16px;
  color: var(--t-tint-slate-ink, #6f7c90);
  font-size: 13px;
}

.ic-gs-group {
  padding: 4px 0 8px;
}

.ic-gs-group + .ic-gs-group {
  border-top: 1px solid var(--t-line-soft, #eef1f6);
}

.ic-gs-group-label {
  padding: 8px 16px 4px;
  color: var(--t-faint, #8a96a6);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.ic-gs-group-label .fa {
  margin-right: 6px;
  color: var(--t-tint-slate-ink, #6f7c90);
}

.ic-gs-item {
  padding: 0 8px;
}

.ic-gs-item.is-active .ic-gs-item-main,
.ic-gs-item:hover .ic-gs-item-main {
  background: var(--t-tint-slate, #f4eefb);
}

.ic-gs-item-main {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 10px;
  border-radius: 8px;
  color: var(--t-tint-blue-ink, #243041);
  text-decoration: none;
}

.ic-gs-item-main:hover,
.ic-gs-item-main:focus {
  color: var(--t-tint-blue-ink, #243041);
  text-decoration: none;
}

.ic-gs-item-copy {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 13px;
  line-height: 1.3;
}

.ic-gs-item-copy strong {
  font-weight: 600;
}

.ic-gs-sub {
  margin-top: 2px;
  color: var(--t-tint-slate-ink, #6f7c90);
  font-size: 12px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ic-gs-status {
  display: inline-block;
  margin-left: 8px;
  padding: 1px 6px;
  border-radius: 999px;
  background: var(--t-surface-3, #eef1f6);
  color: var(--t-tint-slate-ink, #5b6775);
  font-size: 11px;
  font-weight: 600;
  vertical-align: middle;
}

.ic-gs-open {
  flex: 0 0 auto;
  color: var(--t-faint, #8a96a6);
  font-size: 11px;
  font-weight: 600;
}

.ic-gs-related {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 0 10px 8px 10px;
}

.ic-gs-chip {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--t-tint-slate, #f4f6fa);
  color: var(--t-tint-slate-ink, #3d5a80);
  font-size: 11px;
  text-decoration: none;
}

.ic-gs-chip:hover,
.ic-gs-chip:focus {
  background: var(--t-tint-purple, #ebe4f5);
  color: var(--t-brand-text, #5b2c86);
  text-decoration: none;
}

.ic-gs-chip em {
  font-style: normal;
  font-weight: 700;
  color: var(--t-faint, #8a96a6);
  margin-right: 4px;
}

.ic-gs-all {
  display: block;
  padding: 10px 16px 6px;
  border-top: 1px solid var(--t-line-soft, #eef1f6);
  color: var(--t-brand-text, #5b2c86);
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
}

.ic-gs-all:hover,
.ic-gs-all:focus {
  color: var(--t-tint-purple-ink, #4a246d);
  text-decoration: underline;
}

@media (max-width: 767px) {
  .ic-records-search-bar {
    padding: 10px 12px;
  }

  .ic-global-search-kbd {
    display: none;
  }

  .ic-global-search--bar .form-control.js-global-search,
  body.spx-app .ic-global-search--bar .form-control.js-global-search {
    padding-right: 12px !important;
  }
}

/* Ticket list: always-visible who/status pills so the selected filter is obvious. */
.spx-list-nav {
  display: inline-flex;
  gap: 6px;
  align-items: center;
}
.spx-list-filters .box-body {
  padding: 12px 16px 14px;
}
.spx-filter-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin: 0 0 10px;
}
.spx-filter-legend {
  flex: 0 0 52px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--t-faint, #8a96a6);
}
.spx-filter-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}
a.spx-filter-pill,
a.spx-filter-pill:visited {
  display: inline-flex;
  align-items: center;
  padding: 5px 12px;
  border: 1px solid #d5dee9;
  border-radius: 999px;
  background: var(--t-surface, #fff);
  color: var(--t-ink, #2c3340);
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
  line-height: 1.2;
}
a.spx-filter-pill:hover,
a.spx-filter-pill:focus {
  border-color: #d8c6ea;
  background: var(--t-tint-purple, #f4ecf8);
  color: var(--t-brand-text, #5b2c86);
  text-decoration: none;
}
a.spx-filter-pill.is-active,
a.spx-filter-pill.is-active:visited {
  background: #5b2c86;
  border-color: #5b2c86;
  color: #fff;
}
a.spx-filter-pill.spx-cancel-filter.is-active,
a.spx-filter-pill.spx-cancel-filter.is-active:visited {
  background: #a12622;
  border-color: #a12622;
}
a.spx-filter-pill.spx-vhost-filter.is-active,
a.spx-filter-pill.spx-vhost-filter.is-active:visited {
  background: var(--t-brand, #5b2c86);
  border-color: var(--t-brand, #5b2c86);
}
a.spx-filter-pill.spx-unlinked-filter.is-active,
a.spx-filter-pill.spx-unlinked-filter.is-active:visited {
  background: #b45309;
  border-color: #b45309;
}
.spx-filter-inline {
  display: inline-flex;
  margin: 0;
}
.spx-filter-inline .form-control {
  min-width: 160px;
}
.spx-filter-grid-static {
  margin-top: 4px;
}
.spx-active-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 10px;
}
a.spx-active-chip,
a.spx-active-chip:visited {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--t-tint-purple, #ebe4f5);
  color: var(--t-brand-text, #5b2c86);
  font-size: 12px;
  font-weight: 600;
  text-decoration: none;
}
a.spx-active-chip:hover {
  background: #5b2c86;
  color: #fff;
  text-decoration: none;
}

body.spx-app .spx-ms {
  position: relative;
  z-index: 1;
  display: inline-block;
  vertical-align: middle;
}

body.spx-app .spx-ms.is-open {
  z-index: 40;
}

body.spx-app .spx-ms-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  text-align: left;
  height: 30px;
  padding: 4px 8px;
  cursor: pointer;
  background: var(--t-surface, #fff);
}

body.spx-app .spx-ms-summary {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 500;
  color: var(--t-ink-2, #334155);
}

body.spx-app .spx-ms:not(.is-open) .spx-ms-menu {
  display: none;
}

body.spx-app .spx-ms.is-open .spx-ms-menu {
  display: block;
}

body.spx-app .spx-ms-menu {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 41;
  min-width: 100%;
  max-height: 280px;
  overflow: auto;
  padding: 6px 0;
  background: var(--t-surface, #fff);
  border: 1px solid #d5dce6;
  border-radius: 6px;
  box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);
}

body.spx-app .spx-ms-option {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin: 0;
  padding: 5px 12px;
  font-weight: 500;
  color: var(--t-ink-2, #334155);
  cursor: pointer;
  white-space: nowrap;
}

body.spx-app .spx-ms-option:hover {
  background: var(--t-tint-slate, #f4f6fb);
}

body.spx-app .spx-ms-option input {
  margin: 3px 0 0;
}

/* Sage customer Quick View on the CRM Billing tab */
.spx-sage-toolbar-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

.spx-sage-quick .box-title {
  color: var(--t-tint-blue-ink, #1e3a5f);
  font-weight: 700;
}

.spx-sage-quick .spx-sage-scroll {
  max-height: 420px;
  overflow-y: auto;
}

.spx-sage-quick.spx-sage-preview:not(.is-expanded) .spx-sage-scroll {
  max-height: none;
  overflow: visible;
}

.spx-sage-quick.spx-sage-preview:not(.is-expanded) table tbody tr:nth-child(n+11) {
  display: none;
}

.spx-sage-quick.spx-sage-preview:not(.is-expanded) .spx-sage-invoices-card {
  display: none;
}

body.spx-app .spx-sage-quick table.spx-sage-invoices > tbody > tr:nth-child(even) > td,
.spx-sage-quick table.spx-sage-invoices > tbody > tr:nth-child(even) > td {
  background: var(--t-tint-slate, #f3f6fa) !important;
}

/* Beat ic-theme sticky thead (pale #f4f7fb + our white text = unreadable). */
body.spx-app .content-wrapper .spx-sage-quick table.table.spx-sage-ledger > thead > tr > th,
body.spx-app .content .spx-sage-quick table.table.spx-sage-ledger > thead > tr > th,
.spx-sage-quick table.table.spx-sage-ledger > thead > tr > th {
  background: #2f3b4d !important;
  color: #fff !important;
  font-weight: 700;
  border-bottom: 0 !important;
  box-shadow: none !important;
}

body.spx-app .content-wrapper .spx-sage-quick table.table.spx-sage-invoices > thead > tr > th,
body.spx-app .content .spx-sage-quick table.table.spx-sage-invoices > thead > tr > th,
.spx-sage-quick table.table.spx-sage-invoices > thead > tr > th {
  background: var(--t-tint-slate, #e8eef6) !important;
  color: var(--t-tint-blue-ink, #1f2a3a) !important;
  font-weight: 700;
  box-shadow: inset 0 -1px 0 #cfd8e6 !important;
}

body.spx-app .spx-sage-quick table.spx-sage-ledger > tbody > tr:nth-child(even) > td,
.spx-sage-quick table.spx-sage-ledger > tbody > tr:nth-child(even) > td {
  background: var(--t-tint-slate, #f4f4f4) !important;
}

.spx-sage-quick a.spx-sage-detail {
  color: var(--t-accent-text, #2f80ed);
  font-weight: 600;
}






/* Tagging a colleague on a staff note. Fallbacks are the light values: the
   --t-* tokens exist only under [data-theme="dark"], so in light mode the
   fallback is what renders. */
.spx-mention {
  display: inline-block;
  padding: 1px 6px;
  border-radius: 10px;
  font-weight: 600;
  font-size: 12px;
  /* --t-tint-purple and its -ink partner are a pair: both are defined under
     [data-theme="dark"], so the chip flips together. --t-brand-text has no
     matching tint token, and pairing it with an invented one painted dark
     mode's light purple onto light mode's near-white ground. */
  color: var(--t-tint-purple-ink, #5b2c86);
  background: var(--t-tint-purple, #f1eaf8);
}

.spx-mention-field { position: relative; }

.spx-mention-menu {
  position: absolute;
  z-index: 30;
  left: 0;
  right: 0;
  /* top is set from the textarea's own height in crm-ticket-thread.js. */
  top: 0;
  margin: 0;
  padding: 4px;
  list-style: none;
  max-height: 232px;
  overflow-y: auto;
  border: 1px solid var(--t-line, #dde3ec);
  border-radius: 8px;
  background: var(--t-surface, #fff);
  box-shadow: 0 12px 28px rgba(30, 40, 60, 0.16);
}

.spx-mention-item {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 6px 10px;
  border-radius: 6px;
  cursor: pointer;
}

.spx-mention-item.is-active,
.spx-mention-item:hover {
  background: var(--t-tint-slate, #eef2f6);
}

.spx-mention-name {
  font-weight: 600;
  color: var(--t-ink, #1f2937);
  white-space: nowrap;
}

.spx-mention-email {
  font-size: 12px;
  color: var(--t-faint, #8a96a6);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Proof of payment: the office reconcile queue. Fallbacks are the light values:
   the --t-* tokens exist only under [data-theme="dark"]. */
.spx-filter-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-bottom: 12px;
}

.pop-address {
  font-size: 12px;
  color: var(--t-faint, #8a96a6);
  overflow-wrap: anywhere;
}

.pop-note {
  font-size: 12px;
  font-style: italic;
  color: var(--t-muted, #5b6875);
  overflow-wrap: anywhere;
}

.pop-when, .pop-cell { font-variant-numeric: tabular-nums; white-space: nowrap; }

.pop-check {
  display: block;
  font-weight: 400;
  margin: 0;
  cursor: pointer;
}

/* Who ticked it and when, under the tick. A flag with no name beside it is
   worth nothing the day a payment is disputed. */
.pop-stamp {
  display: block;
  font-size: 11px;
  color: var(--t-faint, #8a96a6);
  white-space: nowrap;
}

/* Reconciled rows stay readable but stop competing with the work. */
tr.pop-done td { opacity: .62; }

.pop-results { max-height: 320px; overflow-y: auto; }

.pop-result {
  display: block;
  width: 100%;
  text-align: left;
  border: 1px solid var(--t-line, #dde3ec);
  border-radius: 8px;
  background: var(--t-surface, #fff);
  padding: 8px 11px;
  margin-bottom: 6px;
  cursor: pointer;
}

.pop-result:hover,
.pop-result:focus {
  border-color: var(--t-brand, #5b2c86);
  background: var(--t-tint-purple, #f7f2fb);
}

.pop-result-name {
  display: block;
  font-weight: 600;
  color: var(--t-ink, #1f2937);
}

.pop-result-meta {
  display: block;
  font-size: 12px;
  color: var(--t-faint, #8a96a6);
}

.pop-amount, .pop-ref { font-variant-numeric: tabular-nums; white-space: nowrap; }

/* The customer chosen on the capture form, before it is submitted.
   [hidden] first: an element with display:flex ignores the hidden attribute
   entirely, so the empty chip rendered on page load with nothing in it. */
.pop-chosen[hidden] { display: none !important; }

.pop-chosen {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-top: 8px;
  padding: 7px 11px;
  border: 1px solid var(--t-brand, #5b2c86);
  border-radius: 8px;
  background: var(--t-tint-purple, #f7f2fb);
  font-weight: 600;
  color: var(--t-tint-purple-ink, #5b2c86);
}

/* Removing a subnet is the one destructive control in the row, so it does not
   share the brand hover the view and edit icons use. */
.spx-row-actions a.spx-action-danger { color: var(--t-faint, #8a96a6); }
.spx-row-actions a.spx-action-danger:hover,
.spx-row-actions a.spx-action-danger:focus {
  color: var(--t-tint-red-ink, #bc382a);
}

/* Voice credit: load history. Fallbacks are the light values -- the --t-*
   tokens exist only under [data-theme="dark"]. */

/* Bootstrap 3 has no fifths, so five cards get an explicit width. Below the
   md breakpoint they fall back to the col-sm-6 pairs they already were. */
@media (min-width: 992px) {
  .spx-stat-row .spx-stat-fifth { width: 20%; }
}

.spx-card-action { cursor: pointer; border-color: var(--t-brand, #5b2c86); }
.spx-card-action:hover { box-shadow: 0 6px 18px rgba(30, 40, 60, .14); }
.spx-card-action .spx-stat { color: var(--t-tint-purple-ink, #5b2c86); }
.spx-card-action-hint {
  margin: 6px 0 0; font-size: 11px; font-weight: 600;
  color: var(--t-tint-purple-ink, #5b2c86);
}

.spx-hist-badge {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 12px; font-weight: 600; padding: 3px 9px;
  border: 1px solid var(--t-brand, #5b2c86); border-radius: 20px;
  background: var(--t-tint-purple, #f1eaf8);
  color: var(--t-tint-purple-ink, #5b2c86);
  cursor: pointer; white-space: nowrap;
}
.spx-hist-badge.is-empty {
  border-color: var(--t-line, #dde3ec); background: transparent;
  color: var(--t-faint, #8a96a6); cursor: default;
}
.spx-hist-count {
  background: var(--t-brand, #5b2c86); color: #fff; border-radius: 10px;
  font-size: 11px; padding: 0 6px; font-variant-numeric: tabular-nums;
}

.spx-hist-roll {
  display: flex; justify-content: space-between; gap: 10px;
  padding: 9px 15px; font-size: 12px;
  background: var(--t-surface-2, #f7f9fb);
  border-bottom: 1px solid var(--t-line-soft, #eef1f5);
}
.spx-hist-roll strong { font-variant-numeric: tabular-nums; }

.spx-hist-body { max-height: 60vh; overflow-y: auto; padding: 0; }
.spx-hist-body > .text-muted, .spx-hist-body > .text-danger { padding: 14px 15px; margin: 0; }

.spx-hist-entry { padding: 11px 15px; border-bottom: 1px solid var(--t-line-soft, #eef1f5); }
.spx-hist-entry:last-child { border-bottom: 0; }
/* A load that never reached Session moved no balance. It should not read the
   same as one that did. */
.spx-hist-entry.is-failed { background: var(--t-tint-red, #fdecea); }

.spx-hist-top { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
.spx-hist-amt { font-weight: 700; font-variant-numeric: tabular-nums; }
.spx-hist-entry.is-failed .spx-hist-amt {
  color: var(--t-tint-red-ink, #bc382a); text-decoration: line-through;
}
.spx-hist-cust { font-weight: 600; color: var(--t-ink, #1f2937); }
.spx-hist-when {
  font-size: 12px; color: var(--t-faint, #8a96a6);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.spx-hist-meta { font-size: 12px; color: var(--t-muted, #5b6875); margin-top: 3px; }
.spx-hist-comment {
  font-size: 12px; font-style: italic; color: var(--t-muted, #5b6875);
  margin-top: 3px; overflow-wrap: anywhere;
}
.spx-hist-error {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 11px;
  color: var(--t-tint-red-ink, #bc382a); margin-top: 4px; overflow-wrap: anywhere;
}
.spx-hist-pill {
  display: inline-block; font-size: 11px; font-weight: 700;
  padding: 1px 7px; border-radius: 20px;
}
.spx-hist-pill.is-ok { background: var(--t-tint-green, #e7f6ec); color: var(--t-tint-green-ink, #1f7d47); }
.spx-hist-pill.is-no { background: var(--t-tint-red, #fdecea); color: var(--t-tint-red-ink, #bc382a); }

/* RADIUS status. Fallbacks are the light values -- the --t-* tokens exist only
   under [data-theme="dark"]. Semantic colours, deliberately not the brand
   purple: this says what RADIUS thinks, not what VHOST is. */
.ic-radius-badge {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 12px; font-weight: 700; letter-spacing: .02em;
  padding: 3px 10px; border-radius: 20px; white-space: nowrap;
  border: 1px solid transparent;
}

.spx-radius-ok {
  background: var(--t-tint-green, #e7f6ec);
  color: var(--t-tint-green-ink, #1f7d47);
  border-color: var(--t-tint-green-ink, #1f7d47);
}
.spx-radius-warn {
  background: var(--t-tint-amber, #fdf3e2);
  color: var(--t-tint-amber-ink, #96601a);
  border-color: var(--t-tint-amber-ink, #96601a);
}
.spx-radius-bad {
  background: var(--t-tint-red, #fdecea);
  color: var(--t-tint-red-ink, #bc382a);
  border-color: var(--t-tint-red-ink, #bc382a);
}
.spx-radius-grey {
  background: var(--t-tint-slate, #eef1f5);
  color: var(--t-faint, #8a96a6);
  border-color: var(--t-line, #dde3ec);
}
.spx-radius-load {
  background: transparent;
  color: var(--t-faint, #8a96a6);
  border-style: dashed;
  border-color: var(--t-line, #dde3ec);
}

/* A disagreement between VHOST and RADIUS is the one thing on this badge worth
   interrupting somebody for, so it is the only state that moves. */
.spx-radius-clash { box-shadow: 0 0 0 2px var(--t-tint-red, #fdecea); }

.ic-radius-resync { display: inline-block; margin-left: 6px; }

/* A cell allowed to be long without setting the table's width.
   The cap sits on a block inside the cell, not on the cell: max-width on a td
   is advisory under the default auto table layout, and the browser sized the
   Product column to its content regardless -- 417px against a 320px cap, with
   nothing ellipsised.
   The speed keeps its place at the end while the name takes the truncation,
   because the speed is the short half and the half worth reading. The full
   name is on the title attribute, so only the boilerplate tail of a product
   name goes off screen. */
.spx-table td.spx-col-clamp { white-space: nowrap; }
.spx-clamp-line { display: flex; gap: 6px; align-items: baseline; max-width: 300px; }
.spx-clamp-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.spx-clamp-line .text-muted { flex: 0 0 auto; }

/* ---- Down 24h: why a service is off -------------------------------------
   A verdict and its evidence, stacked. The chip groups RFC 2866 terminate
   causes by what the desk would do about them -- Lost-Carrier and a dead ARP
   entry are one problem, User-Request is a customer rebooting a router -- and
   the line underneath carries the raw code, so the grouping never hides what
   it was derived from.
   Colours are set as tokens on the modifier rather than as plain declarations,
   because the palette has no light block: the var() fallback is the light
   value and [data-theme="dark"] supplies the other half. */
.spx-reason { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.spx-reason-chip {
  display: inline-flex; align-items: center; gap: 6px; align-self: flex-start;
  padding: 2px 9px; border-radius: 11px; font-size: 12px; font-weight: 600;
  line-height: 1.7; white-space: nowrap;
  border: 1px solid var(--t-reason-bd, #d9dee5);
  background: var(--t-reason-bg, #f1f3f6);
  color: var(--t-reason-fg, #495261);
}
.spx-reason-chip .fa { font-size: 11px; opacity: .85; }
.spx-reason-detail {
  font-size: 12px; line-height: 1.5;
  color: var(--t-reason-muted, #8a94a6);
  max-width: 280px; white-space: normal;
}

.spx-reason-line     { --t-reason-bd: #e3b7a0; --t-reason-bg: #fbeee6; --t-reason-fg: #8a4c21; }
.spx-reason-customer { --t-reason-bd: #b9c9e6; --t-reason-bg: #eaf1fb; --t-reason-fg: #2f568f; }
.spx-reason-network  { --t-reason-bd: #cbc0e4; --t-reason-bg: #f1ecfa; --t-reason-fg: #5a4494; }
.spx-reason-idle     { --t-reason-bd: #cdd3da; --t-reason-bg: #f2f4f7; --t-reason-fg: #5b6472; }
.spx-reason-conflict { --t-reason-bd: #c8ddb5; --t-reason-bg: #eef6e7; --t-reason-fg: #4a6b31; }
.spx-reason-unknown  { --t-reason-bd: #d7dbe1; --t-reason-bg: transparent; --t-reason-fg: #8a94a6; font-weight: 500; }

[data-theme="dark"] .spx-reason-line     { --t-reason-bd: #6d4425; --t-reason-bg: #3a2617; --t-reason-fg: #f0b483; }
[data-theme="dark"] .spx-reason-customer { --t-reason-bd: #2f4b74; --t-reason-bg: #1b2a3f; --t-reason-fg: #8fb6e8; }
[data-theme="dark"] .spx-reason-network  { --t-reason-bd: #4a3f6e; --t-reason-bg: #241f38; --t-reason-fg: #b9a6e8; }
[data-theme="dark"] .spx-reason-idle     { --t-reason-bd: #3b4351; --t-reason-bg: #242b36; --t-reason-fg: #9fa9b8; }
[data-theme="dark"] .spx-reason-conflict { --t-reason-bd: #3f5a2c; --t-reason-bg: #1f2a18; --t-reason-fg: #a8cf88; }
[data-theme="dark"] .spx-reason-unknown  { --t-reason-bd: #39414e; --t-reason-bg: transparent; --t-reason-fg: #79828f; }
[data-theme="dark"] .spx-reason-detail   { --t-reason-muted: #8892a0; }

.spx-reason-wait { opacity: .55; }
.spx-reason-wait .fa { animation: spx-reason-spin 1.1s linear infinite; }
@keyframes spx-reason-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .spx-reason-wait .fa { animation: none; }
}

/* ---- The Internet list is wider than the screen, and that is fine ----------
   Every other table here is held at width:100% !important a few hundred lines
   up. That works while the columns fit; this one carries thirteen and does not,
   so 100% stopped meaning "fill the box" and started meaning "squeeze every
   column until they all fit". The visible cost was the RADIUS header clipped to
   a single "R" and the IP column pushed off the end -- neither of them a width
   anybody chose.

   So this one table sizes to its content and scrolls inside .table-responsive,
   which already has overflow-x. min-width keeps it filling the box on a wide
   screen, where it does fit.

   Scoped to .spx-internet-table on purpose: the blanket rule is right for the
   other lists and is left alone. */
body.spx-app .content-wrapper table.spx-internet-table,
body.spx-app .content-wrapper table.spx-internet-table.dataTable {
  width: auto !important;
  min-width: 100%;
}

/* A header that wraps is what turned RADIUS into "R". Columns are narrow enough
   already without losing a line to it. */
body.spx-app .content-wrapper table.spx-internet-table > thead > tr > th {
  white-space: nowrap;
}

/* ==========================================================================
   Phone: one control height, one gap, and a search bar that holds its icon
   --------------------------------------------------------------------------
   Measured on the Clients list at 390px. Every interactive control in the
   page head arrived at a different height -- theme toggle 25px, notify bell
   32px, Status select 34px, the buttons and Columns 40px, the table search
   44px -- so nothing lined up with anything and each row sat at its own
   rhythm. Four separate wrapping rows resulted where two would do.

   This block is at the end of splynx-ui.css deliberately. Every class below
   is defined in this file, and this file loads after ic-theme.css, so being
   last is what lets these win without a pile of !important. The few that do
   carry it are beating an !important in ic-theme.css, noted where they are.
   ========================================================================== */
@media (max-width: 767px) {

  /* The records bar floats the theme toggle and the bell, then lets the search
     follow in normal flow. That is why the magnifier detached from its input.

     An <input> establishes its own formatting context, and such a box may not
     overlap a float: it either narrows or is pushed below. This one is
     width:100% so it cannot narrow, and it dropped 32px -- exactly the bell's
     height. The icon is positioned against .ic-global-search-field, which is
     an ordinary block and is *not* pushed, so the field grew to 72px while the
     input sat in its bottom 40px. top:50% then centred the icon on the field,
     16px above the input it belongs to, which is the magnifier sitting outside
     the bar.

     Flex fixes the cause rather than nudging the icon: no floats, so nothing
     is pushed, and the field collapses back to the input's own 40px. Explicit
     order keeps the bell and toggle in the order the float gave them, since
     floating right reverses source order and flex does not. */
  .ic-records-search-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding: 10px 12px;
  }

  .ic-records-search-bar .ic-theme-toggle,
  .ic-records-search-bar .ic-notify-inline {
    float: none;
    margin: 0;
  }

  /* margin-left:auto on the first of the pair holds both to the right edge,
     which is where the float used to put them. */
  .ic-records-search-bar .ic-notify-inline {
    order: 1;
    margin-left: auto;
  }
  .ic-records-search-bar .ic-theme-toggle {
    order: 2;
  }
  .ic-records-search-bar .ic-global-search--bar {
    order: 3;
    flex: 1 1 100%;
    max-width: none;
  }

  /* One height for the chrome pair. The bell's 32px is !important in
     ic-theme.css:5634, so matching it needs the same weight. */
  .ic-records-search-bar .ic-notify-toggle {
    height: 40px !important;
    line-height: 38px !important;
    padding: 0 13px !important;
    border-radius: 8px;
  }

  .ic-records-search-bar .ic-theme-toggle {
    height: 40px;
    border-radius: 8px;
    align-items: stretch;
  }
  .ic-records-search-bar .ic-theme-toggle button {
    min-width: 40px;
    padding: 0 12px;
  }

  /* Page head and its toolbar.
     flex-end, not center: the Status filter carries a label above its select,
     so centring it left the select riding 9px high against the buttons beside
     it. Aligning on the bottom edge puts every control on one line and lets
     the caption sit above the row where it reads as a caption. */
  .spx-record-head {
    gap: 10px;
  }

  .spx-toolbar-actions {
    align-items: flex-end;
    gap: 8px;
  }

  /* Measured: filter 100 + refresh 42 + Deleted clients 126 leaves 82px of a
     366px row, and Add customer needs 125, so it wrapped alone onto a third
     line. Giving the filter the full first row leaves 309px of buttons for
     366px of room -- all three fit, and the primary action takes the slack so
     the row ends flush with the card instead of trailing off. */
  .spx-toolbar-actions .spx-filters {
    flex: 1 1 100%;
  }
  .spx-toolbar-actions .spx-btn-primary {
    flex: 1 1 auto;
  }

  .spx-filters label {
    margin: 0;
    font-size: 11px;
    font-weight: 600;
    line-height: 1.7;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--t-faint, #8a96a6);
  }

  /* The single control height. Buttons get inline-flex so a lone icon centres
     in the box; selects and text inputs keep their native display, because
     inline-flex on a select loses the drop-down arrow in WebKit. */
  /* gap is load-bearing, not decoration. Flex makes each of a button's child
     nodes a flex item and drops the whitespace between them, so "<i/> Columns
     <span class=caret/>" lost both its spaces and ran together. 6px puts them
     back at one consistent distance instead of a collapsed space. */
  .spx-toolbar-actions .btn,
  .spx-list-controls .btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    height: 40px;
    min-height: 40px;
    padding: 0 14px;
    border-radius: 8px;
    font-size: 14px;
    line-height: 1;
    white-space: nowrap;
  }

  .spx-toolbar-actions .form-control,
  .spx-toolbar-actions select.form-control,
  .spx-list-controls .form-control,
  .spx-list-controls select.form-control {
    height: 40px;
    min-height: 40px;
    padding: 0 10px;
    border-radius: 8px;
    font-size: 14px;
  }

  /* Tabs: one row that scrolls, not two rows that wrap.
     Three tabs need 420px and have 366px, so the third wrapped onto a second
     line -- and nav-tabs draws a bottom border per line, so the strip came out
     as two stacked rules with the active underline stranded on the first.
     A single scrolling row is the same information without the broken frame. */
  .spx-record-tabs {
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    padding: 0 4px;
    scrollbar-width: none;
  }
  .spx-record-tabs::-webkit-scrollbar {
    display: none;
  }
  .spx-record-tabs > li {
    flex: 0 0 auto;
  }
  .spx-record-tabs > li > a {
    padding: 11px 12px;
    white-space: nowrap;
  }

  /* List controls: Show entries, Columns and the table search each took a row
     of its own at a different height. Same height, same gap, and the search
     takes the slack so the row ends flush. */
  .spx-list-controls {
    align-items: center;
    gap: 8px;
  }
  .spx-list-controls-right {
    width: 100%;
    align-items: center;
    gap: 8px;
  }
  /* basis, not auto. At auto the search sizes to its content (330px) and wraps
     below the Columns button with 204px of the row left empty; a 160px basis
     lets it sit alongside and then grow into whatever is left. */
  .spx-table-search {
    flex: 1 1 160px;
    align-items: center;
  }
  .spx-table-search .form-control {
    flex: 1 1 auto;
    min-width: 0;
  }

  /* Plain Bootstrap .nav-tabs: the same defect as .spx-record-tabs above, on
     the pages that never adopted that class. Measured at 390px, four tabs need
     420px and get 366, so the last wrapped -- and nav-tabs draws its bottom
     border once per line, so the strip came out as two stacked rules with the
     active tab's underline stranded on the first. Same remedy: one row that
     scrolls.

     Flex, and li float:none with it. Bootstrap lays these out by floating the
     items, and a float is precisely what wraps -- flex-wrap has no say over a
     float, so leaving it set would keep the second row. */
  .spx-page .nav-tabs {
    display: flex;
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .spx-page .nav-tabs::-webkit-scrollbar {
    display: none;
  }
  .spx-page .nav-tabs > li {
    float: none;
    flex: 0 0 auto;
  }
  .spx-page .nav-tabs > li > a {
    white-space: nowrap;
  }
}
