/* ---------------------------------------------------------------------------
 * nexus token compatibility layer
 *
 * WHY THIS BLOCK EXISTS
 *
 * nexus keeps 82 design tokens in its own css/custom.css, not in theme.min.css.
 * assetPath resolves child-first, so the moment this theme ships a custom.css
 * of its own, nexus's is never loaded and every one of those tokens vanishes.
 * 405 var() references across the stock templates then resolve to nothing.
 *
 * An invalid var() does not inherit and does not warn. It falls back to the
 * property's initial value, so `background: var(--bg-lifted)` became
 * transparent and every product card, panel and dropdown rendered white with
 * unreadable text while the header and footer, which use this theme's own
 * tokens, looked correct.
 *
 * So every name nexus defines is redefined here with a SurgeNode value. The
 * names are nexus's because the templates reference them; the values are ours.
 *
 * The neutral ramp is INVERTED on purpose. nexus runs 50 light to 950 dark for
 * a light theme. A stock template asking for --neutral-100 wants "a surface
 * barely off the background", which on dark means near-black, not near-white.
 * Inverting keeps that intent intact without touching a single template.
 * --------------------------------------------------------------------------- */

:root {
    --white: #fff;

    /* Neutral ramp, inverted: 50 is now the darkest surface. */
    --neutral-50: #050505;
    --neutral-100: #0a0a0a;
    --neutral-200: #111111;
    --neutral-300: #1c1c1c;
    --neutral-400: #2a2a2a;
    --neutral-500: #8f8f8f;
    --neutral-600: #c9c9c9;
    --neutral-700: #d4d4d4;
    --neutral-800: #e8e8e8;
    --neutral-900: #f5f5f5;
    --neutral-950: #ffffff;

    --primary-50: var(--neutral-50);
    --primary-100: var(--neutral-100);
    --primary-200: var(--neutral-200);
    --primary-300: var(--neutral-300);
    --primary-400: var(--neutral-400);
    --primary-500: var(--neutral-500);
    --primary-600: var(--neutral-600);
    --primary-700: var(--neutral-700);
    --primary-800: var(--neutral-800);
    --primary-900: var(--neutral-900);
    --primary-950: var(--neutral-950);

    /* Primary is the accent, not a neutral. nexus points these at neutral-900
     * because its primary action is a near-black button on white. Ours is the
     * cobalt from the marketing site. */
    --primary: var(--cobalt);
    --primary-lifted: var(--cobalt-lo);
    --primary-accented: var(--cobalt-lo);

    --secondary: var(--ink-600);
    --secondary-lifted: var(--ink-700);
    --secondary-accented: var(--ink-800);

    /* Status colours keep nexus's hues. They were chosen for contrast against
     * white, and all four still clear 4.5:1 against #050505, so there is no
     * reason to repaint them. */







    /* Text. Inverted from nexus: light on dark. --text-inverted is what sits on
     * a filled accent button, so it is the deep ink, not white. */

    /* Borders are alpha hairlines rather than solid greys, matching the
     * marketing site's discipline of hairlines over shadows. */

    /* Backgrounds. This is the block that was breaking the product cards. */


    --text-xs: 0.625rem;
    --text-sm: 0.75rem;
    --text-md: 0.875rem;
    --text-lg: 1rem;

    --outline-sm: 1px;
    --outline-md: 2px;
    --outline-lg: 3px;

    /* Rounding follows the marketing site rather than nexus: 6 / 10 / 12. */

}
/* ============================================================================
 * SurgeNode v2 :: custom.css
 *
 * This file is the Phase 2 surface. Page level and component styling goes
 * here. It is linked after css/sn-tokens.css, so a rule here beats a rule
 * there at equal specificity, which is the intended relationship: tokens and
 * base chrome are frozen, page work is not.
 *
 * ----------------------------------------------------------------------------
 * WHY THIS FILE EXISTS EVEN THOUGH IT IS ALMOST EMPTY
 *
 * It is not a placeholder. It has to exist.
 *
 * assetExists and assetPath resolve child first and then fall back to the
 * parent theme. Verified on this install: with no custom.css in this theme,
 * includes/head.tpl emitted
 *     <link href="/templates/nexus/css/custom.css" rel="stylesheet">
 * and pulled in nexus's 4 KB example customisation file, which declares a
 * complete LIGHT palette including --primary, --secondary, --success and
 * --border. Because it loads after sn-tokens.css it won every one of those
 * tokens. Shipping this file shadows it.
 *
 * So: do not delete this file, and do not let it become empty enough that
 * someone tidies it away. If you replace its contents, keep the file.
 * ----------------------------------------------------------------------------
 *
 * Rules for working in here:
 *
 *   - Reference tokens, never literals. If you are typing a hex colour you are
 *     almost certainly wrong. The one exception is a colour that genuinely is
 *     not in the system, and that is a conversation, not a commit.
 *
 *   - Do not redeclare anything in the :root block of sn-tokens.css. That file
 *     is frozen precisely so several agents can work at once without fighting
 *     over colours. If a token is wrong, say so, do not shadow it.
 *
 *   - Prefix a `body` ancestor when you need to out rank nexus's
 *     theme.min.css, which is a light theme and is 242 KB of fairly specific
 *     selectors. That lifts a bare class from (0,1,0) to (0,1,1) without
 *     reaching for !important, which would take the override away from whoever
 *     comes next.
 *
 *   - No em dashes, in code, comments or copy. Standing operator preference.
 * ==========================================================================*/

/* Intentionally no rules yet. Phase 2 fills this in. */


/* ===== BEGIN sn-support-errors ==============================================
 * SurgeNode v2 :: support, errors and long tail
 *
 * Owner: the SUPPORT / ERRORS / long tail agent.
 * Canonical copy: /root/surgenode-v2-build/css-fragments/support-errors.css
 *
 * This block is delimited by the BEGIN and END markers so it can be replaced
 * in place without disturbing anything another Phase 2 agent has appended to
 * custom.css. Regenerate by deleting from BEGIN to END and re-appending the
 * canonical copy. Do not rewrite custom.css wholesale; it is shared.
 *
 * ---------------------------------------------------------------------------
 * WHY SO MANY OF THESE RULES TARGET NEXUS CLASS NAMES RATHER THAN NEW ONES
 *
 * The support templates are full of live JS hooks: the star rating reads
 * ticketid / ticketkey / ticketreplyid attributes off .rating, the attachment
 * "add more" button clones .file-upload and rebinds .custom-file-input, the
 * department select calls refreshCustomFields(), the reply box is a
 * .markdown-editor with a data-auto-save-name, and the ticket list is a
 * DataTable initialised by id. Renaming any of that to fit a prettier
 * stylesheet would trade a working support flow for a nicer looking one.
 *
 * So with one exception the support templates are NOT forked, and the styling
 * is done by overriding the class names nexus already emits. The exception is
 * supportticketsubmit-stepone.tpl, which is nothing but links and where the
 * stock markup is genuinely poor.
 * ------------------------------------------------------------------------ */


/* ---------------------------------------------------------------------------
 * E0. Status and label chip CONTRAST. RESOLVED DURING RECONCILIATION.
 *
 * This block used to force `color: #1d0703` onto thirteen chip selectors. It
 * was written against the assumption that the chip keeps the bright SOLID
 * fill that theme.min.css declares and sn-nexus-bridge.css repairs, where a
 * dark foreground scores 5.99 to 11.25 : 1 and is correct.
 *
 * That assumption was already false. css/sn-clientarea.css had, in parallel,
 * REPLACED the chip design entirely: `body .label` there sets
 *     background: color-mix(in srgb, var(--st) 16%, transparent);
 *     color:      var(--st);
 * a tinted pill with coloured text, deliberately built so it does not depend
 * on the fill surviving. The solid fill never reaches the page.
 *
 * The two designs are individually sound and jointly broken. custom.css loads
 * last and the state selectors tie on specificity (0,2,1), so the foreground
 * came from here and the background came from there: near black text on a 16%
 * tint over #0a0a0a. Measured on the composited result:
 *
 *     mint    #0e2817   1.23 : 1        amber   #312608   1.30 : 1
 *     danger  #31151a   1.16 : 1        cobalt  #082631   1.23 : 1
 *     ink-400 #1f1f1f   1.18 : 1
 *
 * against 5.10 to 8.64 : 1 for the tinted design left alone. 1.2 : 1 is not a
 * contrast failure, it is invisible text, and it hit every status chip in the
 * services, invoices and tickets lists. It also hit only the thirteen states
 * named here, so a single table rendered some chips legible and some blank.
 *
 * Resolution: the tinted design in sn-clientarea.css wins. It is self
 * consistent, it passes AA on every state, and it is immune to the nexus fill
 * variables being shadowed, which is the whole defect class the bridge exists
 * for. This block is deleted rather than moved. Do not reintroduce a
 * foreground here without changing the background in the same rule.
 * ------------------------------------------------------------------------ */

/* Custom department and status colours arrive as an inline background-color,
   which beats any class rule. Their hue is unknown at author time, so the
   stock white is kept for that case only: it is the safer default against an
   arbitrary admin chosen colour, which is usually a saturated mid tone. */
body .label.status-custom { color: #ffffff; }


/* ---------------------------------------------------------------------------
 * E1. Error pages.
 *
 * page-not-found, rate-limit-exceeded and unknown-routepath are Smarty
 * partials that render inside the normal theme shell, so they inherit the dark
 * chrome and only need their own centre column. internal-error.tpl is NOT one
 * of these: it is a standalone document with its own inline CSS, because it
 * renders when WHMCS itself has failed and neither Smarty nor this stylesheet
 * can be assumed to be running. Do not add rules for it here.
 * ------------------------------------------------------------------------ */

body .sn-error {
  max-width: 620px;
  margin: 0 auto;
  padding: 64px 20px 88px;
  text-align: center;
}

/* The status numeral. Language independent, so it carries the mono voice while
   every word on the page still comes from a lang key. */
body .sn-error-code {
  display: inline-block;
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.14em;
  color: var(--cobalt);
  background: var(--cobalt-dim);
  border: 1px solid var(--cobalt);
  border-radius: var(--r-pill);
  padding: 5px 14px;
  margin-bottom: 24px;
}

body .sn-error-mark {
  width: 64px;
  height: 64px;
  display: grid;
  place-items: center;
  margin: 0 auto 22px;
  border-radius: var(--r-lg);
  border: 1px solid var(--line-strong);
  background: var(--ink-850);
  color: var(--cobalt);
  font-size: 24px;
}

body .sn-error-title {
  font-family: var(--display);
  font-size: clamp(30px, 4vw, 44px);
  font-weight: 800;
  letter-spacing: -0.018em;
  line-height: 1.1;
  color: var(--ink-100);
  margin: 0 0 10px;
}

body .sn-error-sub {
  font-family: var(--display);
  font-size: clamp(16px, 1.7vw, 20px);
  font-weight: 700;
  letter-spacing: -0.015em;
  color: var(--ink-100);
  margin: 0 0 10px;
}

body .sn-error-desc {
  color: var(--ink-400);
  font-size: 15px;
  max-width: 46ch;
  margin: 0 auto 28px;
}

body .sn-error-actions {
  display: flex;
  gap: 10px;
  justify-content: center;
  flex-wrap: wrap;
}

/* Severity variant. The accent swap is the only difference, and because every
   rule above reads var(--cobalt) the whole block follows automatically. This
   is the same mechanism the .theme-<game> scopes in sn-tokens.css use. */
body .sn-error--warn { --cobalt: var(--amber); --cobalt-dim: var(--amber-dim); }

body .sn-error-referrer {
  max-width: 620px;
  margin: 0 auto 72px;
  padding: 12px 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--ink-850);
  color: var(--ink-400);
  font-size: 13px;
  text-align: center;
}

body .sn-error-referrer .sn-referrer-url {
  font-family: var(--mono);
  font-size: 12.5px;
  word-break: break-all;
}

/* Fact pairs on banned.tpl: the reason and the expiry, which are the only two
   things on that page a person can act on. */
body .sn-ban-facts {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
  margin-top: 26px;
}

body .sn-ban-fact {
  flex: 1 1 200px;
  max-width: 280px;
  text-align: left;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--ink-850);
}

body .sn-fact-label {
  display: block;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-500);
  margin-bottom: 4px;
}

body .sn-fact-value { display: block; font-size: 14px; color: var(--ink-100); overflow-wrap: break-word; }

/* The permission list on access-denied.tpl. */
body .sn-perms {
  text-align: left;
  max-width: 380px;
  margin: 0 auto 24px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--ink-850);
  overflow: hidden;
}

body .sn-perms-head {
  padding: 10px 16px;
  background: var(--ink-800);
  border-bottom: 1px solid var(--line);
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-500);
}

body .sn-perms-list { list-style: none; margin: 0; padding: 0; }
body .sn-perms-list li {
  padding: 9px 16px;
  border-top: 1px solid var(--line-soft);
  color: var(--ink-200);
  font-size: 13.5px;
}
body .sn-perms-list li:first-child { border-top: 0; }


/* ---------------------------------------------------------------------------
 * E2. Support: the ticket list.
 *
 * supportticketslist.tpl is a DataTable, so the table is rebuilt in JS and the
 * wrapper controls are generated by DataTables rather than by the template.
 * The stock rules paint td and th #fff, which is a white table dropped onto a
 * near black page, so these are the highest value overrides in this file.
 *
 * The .dataTables_wrapper rules also land on every other list in the client
 * area, services and invoices included. That is intentional: it is one shared
 * component and it should not look different per page.
 * ------------------------------------------------------------------------ */

body .dataTables_wrapper table.table-list,
body table.table-list {
  background: var(--ink-850);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  border-collapse: separate;
  border-spacing: 0;
  overflow: hidden;
}

/* This block and sn-clientarea.css:297 both style the same header cell. Before,
   they disagreed: sn-clientarea said 11.5px uppercase 0.05em with 11px 14px
   padding, this file said 12.5px and named no case, tracking or padding. Since
   custom.css loads last, a DataTables-wrapped table rendered as a BLEND that
   neither file describes (12.5px, but uppercase and 0.05em from the other), and
   a PLAIN table.table-list, which sn-clientarea's selector does not reach, came
   out non-uppercase and unpadded. Two table styles on one component.
   Resolved here by carrying the full set at sn-clientarea's values, so both
   table shapes now render identically and the file that loads last is the one
   that describes what you actually see. */
body table.table-list thead th,
body .dataTables_wrapper table.table-list thead th {
  background: var(--ink-800);
  color: var(--ink-400);
  font-family: var(--sans);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  text-align: left;
  padding: 11px 14px;
  white-space: nowrap;
  border: 0;
  border-bottom: 1px solid var(--line);
}

body .dataTables_wrapper table.table-list thead th.sorting_asc,
body .dataTables_wrapper table.table-list thead th.sorting_desc {
  background: var(--ink-750);
  color: var(--ink-100);
}

body .table-list > tbody > tr > td,
body .dataTables_wrapper table.table-list td {
  background: transparent;
  border-top: 1px solid var(--line-soft);
  color: var(--ink-200);
  text-align: left;
}

body .table-list > tbody > tr:hover > td { background: var(--ink-800); }
body .table-list > tbody > tr > td a.border-left { border-left: 1px solid var(--line-soft); }

body .table-list .ticket-number {
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--ink-500);
  margin-right: 8px;
}

body .table-list .ticket-subject { color: var(--ink-200); }
body .table-list .ticket-subject.unread { color: var(--ink-100); font-weight: 700; }
body .table-list tr:hover .ticket-subject { color: var(--cobalt); }

/* DataTables' own chrome: search box, page length select, info line, pager. */
body .dataTables_wrapper .dataTables_filter input,
body .dataTables_wrapper .dataTables_length select {
  background: var(--ink-800);
  border: 1px solid var(--line);
  border-radius: var(--r-btn);
  color: var(--ink-100);
  padding: 5px 9px;
  font-size: 13.5px;
}
body .dataTables_wrapper .dataTables_length select option { background: var(--ink-800); color: var(--ink-100); }
body .dataTables_wrapper .dataTables_filter input:focus,
body .dataTables_wrapper .dataTables_length select:focus {
  border-color: var(--cobalt);
  box-shadow: var(--shadow-accent);
  outline: none;
}
body .dataTables_wrapper .dataTables_filter,
body .dataTables_wrapper .dataTables_length,
body .dataTables_wrapper .dataTables_info { color: var(--ink-400); font-size: 13px; }

body .dataTables_wrapper .dataTables_paginate .paginate_button {
  color: var(--ink-300) !important;
  border: 1px solid var(--line);
  border-radius: var(--r-btn);
  background: var(--ink-850);
  margin-left: 4px;
  padding: 5px 11px;
}
body .dataTables_wrapper .dataTables_paginate .paginate_button:hover {
  color: var(--ink-100) !important;
  background: var(--ink-800) !important;
  border-color: var(--line-strong);
}
body .dataTables_wrapper .dataTables_paginate .paginate_button.current {
  color: var(--ink-on-accent) !important;
  background: var(--cobalt) !important;
  border-color: var(--cobalt);
}
body .dataTables_wrapper .dataTables_paginate .paginate_button.disabled {
  color: var(--ink-600) !important;
  background: transparent !important;
  border-color: var(--line-soft);
}


/* ---------------------------------------------------------------------------
 * E3. Support: the ticket conversation.
 *
 * Stock nexus paints .posted-by on #f6f6f6 and frames attachments with #ddd,
 * both of which are light theme values sitting directly on the dark card.
 * ------------------------------------------------------------------------ */

body .card.view-ticket { padding-bottom: 4px; }

body .view-ticket .ticket-reply {
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--ink-850);
  overflow: hidden;
  margin-bottom: 14px;
}

/* A staff reply is the thing the customer opened the page to read, so it is
   the one element that gets the accent. The customer's own posts stay quiet. */
body .view-ticket .ticket-reply.staff { box-shadow: inset 3px 0 0 var(--cobalt); }

body .view-ticket .posted-by {
  background: var(--ink-800);
  border-bottom: 1px solid var(--line);
  border-radius: 0;
  color: var(--ink-400);
  font-size: 12.5px;
  padding: 10px 16px;
}

body .view-ticket .posted-by .posted-by-name {
  color: var(--ink-100);
  font-family: var(--display);
  font-weight: 700;
}

body .view-ticket .posted-by .posted-on { font-family: var(--mono); font-size: 11.5px; color: var(--ink-500); }

body .view-ticket .requestor-badge {
  font-size: 10.5px;
  font-family: var(--mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 3px 9px;
  border-radius: var(--r-pill);
  background: var(--ink-750);
  border: 1px solid var(--line);
  color: var(--ink-300);
}

body .view-ticket .ticket-reply.staff .requestor-badge {
  background: var(--cobalt-dim);
  border-color: var(--cobalt);
  color: var(--ink-100);
}

body .view-ticket .message {
  color: var(--ink-200);
  font-size: 14.5px;
  line-height: 1.7;
  overflow-wrap: break-word;
}
body .view-ticket .message img { max-width: 100%; height: auto; }
body .view-ticket .message hr { border-top: 1px solid var(--line-soft); }
body .view-ticket .message blockquote {
  border-left: 2px solid var(--line-strong);
  padding-left: 14px;
  color: var(--ink-400);
}

body .view-ticket .attachments {
  border-top: 1px dashed var(--line);
  background: var(--ink-800);
  color: var(--ink-300);
}

body .view-ticket .attachment-list li span {
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--ink-850);
  color: var(--ink-200);
}
body .view-ticket .attachment-list li a:hover span { border-color: var(--cobalt); }
body .view-ticket .attachment-list li figure {
  background: var(--ink-750);
  color: var(--ink-500);
  border-radius: var(--r-sm);
}
body .view-ticket .attachment-list li a:hover figure { color: var(--cobalt); }

/* Star rating. Stock uses #999 for empty and #f2de88 for filled; the filled
   colour moves onto the amber token so it matches the rest of the system. */
body .ticket-reply .rating span.star:before,
body .ticket-reply .rating-done span.star:before { color: var(--ink-600); }
body .ticket-reply .rating span.star:hover:before,
body .ticket-reply .rating span.star:hover ~ span.star:before,
body .ticket-reply .rating-done span.star.active:before { color: var(--amber); }
body .ticket-reply .rating-done .rated { color: var(--ink-400); }


/* ---------------------------------------------------------------------------
 * E4. Support: the department picker on step one.
 *
 * This is the one support template that IS forked, because it carries no form,
 * no JS and no field names, only links, and because the stock markup renders
 * each department as a bare <p class="h5"><a> with an envelope glyph and the
 * description as a separate muted paragraph, which does not read as a set of
 * choices.
 * ------------------------------------------------------------------------ */

body .sn-dept {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  padding: 18px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--ink-850);
  margin-bottom: 10px;
  transition: border-color .15s ease, background-color .15s ease;
}

body a.sn-dept:hover,
body a.sn-dept:focus { border-color: var(--cobalt); background: var(--ink-800); }

body .sn-dept-icon {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
  background: var(--ink-800);
  color: var(--cobalt);
  font-size: 15px;
}

body a.sn-dept:hover .sn-dept-icon { border-color: var(--cobalt); }
body .sn-dept-body { flex: 1 1 auto; min-width: 0; }
body .sn-dept-name {
  font-family: var(--display);
  font-weight: 700;
  font-size: 15.5px;
  letter-spacing: -0.015em;
  color: var(--ink-100);
  margin: 0 0 3px;
}
body a.sn-dept:hover .sn-dept-name { color: var(--cobalt); }
body .sn-dept-desc { color: var(--ink-400); font-size: 13.5px; margin: 0; }
body .sn-dept-go { flex: 0 0 auto; color: var(--ink-500); font-size: 13px; align-self: center; }
body a.sn-dept:hover .sn-dept-go { color: var(--cobalt); }


/* ---------------------------------------------------------------------------
 * E5. Knowledgebase, downloads and announcements.
 *
 * text-black-50 is a Bootstrap utility that resolves to black at 50 percent
 * opacity. nexus puts it on the file and article glyphs in four templates, so
 * on a near black ground those icons are invisible. Repointed at a grey that
 * is actually visible.
 * ------------------------------------------------------------------------ */

body .kb-article-item .text-black-50,
body .kbarticles .text-black-50,
body #main-body .text-black-50 { color: var(--ink-500) !important; }

body .kb-article-item { background: transparent; }
body .kb-article-item:hover { background: var(--ink-800); }
body .kb-article-item a { color: var(--ink-100); }
body .kb-article-item:hover a { color: var(--cobalt); }
/* Stock sets this to var(--bg-lifted), a background colour used as a text
   colour, and that variable is undefined here anyway. */
body .kb-article-item small { color: var(--ink-400); }

/* ---------------------------------------------------------------------------
 * E6. Shared furniture for the long tail list pages.
 * ------------------------------------------------------------------------ */

body .sn-pagehead {
  margin: 0 0 26px;
  padding-bottom: 18px;
  border-bottom: 1px solid var(--line-soft);
}

body .sn-pagehead-title {
  font-family: var(--display);
  font-size: clamp(24px, 2.6vw, 34px);
  font-weight: 800;
  letter-spacing: -0.018em;
  color: var(--ink-100);
  margin: 0;
}

body .sn-pagehead-lead { color: var(--ink-400); font-size: 14.5px; margin: 8px 0 0; max-width: 68ch; }

body .sn-pagehead-eyebrow {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--cobalt);
  margin: 0 0 10px;
}

/* Empty state. Every list page here can reach one, and stock renders a bare
   sentence with no framing. */
body .sn-empty {
  text-align: center;
  padding: 44px 20px;
  border: 1px dashed var(--line);
  border-radius: var(--r-md);
  color: var(--ink-400);
  font-size: 14px;
}
body .sn-empty-mark { font-size: 22px; color: var(--ink-600); margin-bottom: 10px; }

/* ---------------------------------------------------------------------------
 * E7. Long tail page styling.
 *
 * The .label-* fills, the .kb-category hover surface and the announcement
 * excerpt background are all supplied by css/sn-nexus-bridge.css and are NOT
 * restated here. What follows is styling this theme is choosing, not values
 * that were missing.
 * ------------------------------------------------------------------------ */

/* Knowledgebase and downloads category cards. The bridge restores the hover
   surface via --bg-lifted; this adds the accented border and heading that the
   rest of the theme uses to say "this whole block is the click target". */
body .card.kb-category { transition: border-color .15s ease; }
body .kb-category a.card-body { display: block; color: var(--ink-200); }
body .card.kb-category:hover { border-color: var(--cobalt); }
body .kb-category .h5 { color: var(--ink-100); font-family: var(--display); letter-spacing: -0.015em; }
body .card.kb-category:hover .h5 { color: var(--cobalt); }
body .kb-category .fa-folder { color: var(--cobalt); }

/* The announcement excerpt. The bridge gives it a surface and a neutral left
   rule; the rule is moved onto the accent because this block is a pull quote
   and it is the only accent on an otherwise flat list page. */
body .announcements .announcement article {
  border-left: 3px solid var(--cobalt);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  color: var(--ink-200);
}

/* nexus gives every announcement in the list an <h1>. That is several h1s per
   page and, at the h1 scale from sn-tokens.css, roughly 40px per item. Sized
   down to a card heading here rather than by forking the template. */
body .announcements .announcement h1 {
  font-size: clamp(18px, 1.8vw, 23px);
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 0 0 6px;
  gap: 12px;
}
body .announcements .announcement h1 a { color: var(--ink-100); }
body .announcements .announcement h1 a:hover { color: var(--cobalt); }
body .announcements .announcement { border-bottom: 1px solid var(--line-soft); padding-bottom: 26px; }
body .announcements .announcement:last-child { border-bottom: 0; }

/* The 3-D Secure iframe hosts the ACQUIRER's page, which this theme does not
   control and must not restyle. theme.min.css already gives it a white border;
   the white background is belt and braces, so that a bank page which does not
   set its own background cannot inherit a dark one and become unreadable
   halfway through a payment. */
body .submit-3d {
  background: #ffffff;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
}

/* Affiliate summary figures. Stock sizes these in em off a 1.6em parent, which
   lands at roughly 3.8em for the number and a 4em floated icon. */
body .affiliate-stat {
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--ink-850);
  font-size: 13px;
  color: var(--ink-400);
  text-align: left;
}
body .affiliate-stat span {
  font-family: var(--stat);
  font-size: 26px;
  font-weight: 800;
  letter-spacing: -0.03em;
  color: var(--ink-100);
  line-height: 1.15;
}
body .affiliate-stat i { float: none; padding: 0 0 8px; font-size: 16px; color: var(--cobalt); }

/* Knowledgebase and downloads search bar. */
body .kb-search .form-control { border-right: 0; }
body .kb-search .btn { border-top-left-radius: 0; border-bottom-left-radius: 0; }

/* Inline edit affordances shown to staff. They sit inside headings and cards
   and are opacity 0 until hover, which is fine, but they inherit btn-default
   sizing that fights the heading. */
body .show-on-hover,
body .show-on-card-hover { font-size: 12px; }


/* ---------------------------------------------------------------------------
 * E8. Small screens.
 * ------------------------------------------------------------------------ */

@media (max-width: 640px) {
  body .sn-error { padding: 44px 16px 64px; }
  body .sn-dept { padding: 14px; }
  body .view-ticket .posted-by { font-size: 12px; }
}

/* ===== END sn-support-errors ============================================== */

/* ---------------------------------------------------------------------------
 * nexus hardcoded light surfaces
 *
 * theme.min.css carries 55 literal `#fff` background declarations. They are
 * not var() references, so the token bridge cannot reach them: defining
 * --bg-lifted does nothing to `background-color:#fff`.
 *
 * That is why the store page rendered white cards with pale text while the
 * header, footer and login page looked right. Those use this theme's own
 * tokens; the product cards, the Categories panel and the Actions panel are
 * Bootstrap components taking nexus's literal white.
 *
 * custom.css is the last stylesheet in head.tpl, so plain selectors here beat
 * nexus at equal specificity on source order. No `body .x` escalation, which
 * would outrank utility classes like .btn-block and break layout.
 * --------------------------------------------------------------------------- */

/* Cards: the product grid, and every panel built on them. */
.card,
.mc-promo-login,
.mc-promo-manage {
    background-color: var(--ink-850);
    border: 1px solid var(--line-soft);
    border-radius: var(--r-md, 10px);
    color: var(--ink-100);
}

.card-header {
    background-color: transparent;
    border-bottom: 1px solid var(--line-soft);
    color: var(--ink-100);
}

.card-footer {
    background: transparent;
    border-top: 1px solid var(--line-soft);
    color: var(--ink-300);
}

.card-body {
    color: var(--ink-300);
}

.card-title,
.card h1, .card h2, .card h3, .card h4, .card h5 {
    color: var(--ink-100);
}

/* List groups: the Categories and Actions panels in the store sidebar. */
.list-group {
    background-color: transparent;
}

.list-group-item {
    background-color: var(--ink-850);
    border-color: var(--line-soft);
    color: var(--ink-200);
}

.list-group-item:hover,
.list-group-item:focus {
    background-color: var(--ink-800);
    color: var(--ink-100);
}

.list-group-item.active {
    background-color: var(--ink-800);
    border-color: var(--line);
    color: var(--ink-100);
}

/* Dropdowns. nexus sets color:#212529 on the item, which is unreadable here. */
.dropdown-menu {
    background-color: var(--ink-850);
    border: 1px solid var(--line);
    border-radius: var(--r-md, 10px);
    color: var(--ink-200);
}

.dropdown-item {
    color: var(--ink-200);
}

.dropdown-item:hover,
.dropdown-item:focus {
    background-color: var(--ink-800);
    color: var(--ink-100);
}

.dropdown-divider {
    border-top-color: var(--line-soft);
}

/* Modals and popovers. */
.modal-content {
    background-color: var(--ink-850);
    border: 1px solid var(--line);
    color: var(--ink-100);
}

.modal-header,
.modal-footer {
    border-color: var(--line-soft);
}

.popover {
    background-color: var(--ink-850);
    border-color: var(--line);
    color: var(--ink-200);
}

/* Tables. Same hardcoded #212529 text problem as dropdowns. */
.table {
    color: var(--ink-200);
}

.table th,
.table td {
    border-color: var(--line-soft);
}

.table thead th {
    border-bottom-color: var(--line);
    color: var(--ink-300);
}

.table-striped tbody tr:nth-of-type(odd) {
    background-color: rgba(255, 255, 255, .02);
}

.table-hover tbody tr:hover {
    background-color: rgba(255, 255, 255, .04);
    color: var(--ink-100);
}

/* Form controls. Left readable rather than restyled, so focus behaviour and
 * validation states from Bootstrap keep working. */
.form-control,
.custom-select {
    background-color: var(--ink-800);
    border-color: var(--line);
    color: var(--ink-100);
}

.form-control:focus,
.custom-select:focus {
    background-color: var(--ink-800);
    border-color: var(--cobalt);
    color: var(--ink-100);
}

.form-control::placeholder {
    color: var(--ink-400);
}

.input-group-text {
    background-color: var(--ink-750);
    border-color: var(--line);
    color: var(--ink-300);
}

/* Pagination. */
.page-link {
    background-color: var(--ink-850);
    border-color: var(--line-soft);
    color: var(--ink-200);
}

.page-link:hover {
    background-color: var(--ink-800);
    color: var(--ink-100);
}

.page-item.active .page-link {
    background-color: var(--cobalt);
    border-color: var(--cobalt);
    color: var(--ink-on-accent);
}

.page-item.disabled .page-link {
    background-color: var(--ink-900);
    border-color: var(--line-soft);
    color: var(--ink-500);
}

/* Misc surfaces that inherit the same literal white. */
.breadcrumb {
    background-color: transparent;
}

.nav-tabs {
    border-bottom-color: var(--line);
}

.nav-tabs .nav-link.active {
    background-color: var(--ink-850);
    border-color: var(--line) var(--line) var(--ink-850);
    color: var(--ink-100);
}

.close {
    color: var(--ink-200);
    text-shadow: none;
}

.close:hover {
    color: var(--ink-100);
}

/* ---------------------------------------------------------------------------
 * The store grid and the sidebar panels
 *
 * These are the white cards. Two separate causes, neither reachable by the
 * token layer and neither fixed by source order.
 *
 * 1. `.product` is painted white TWICE:
 *      nexus/css/theme.min.css              .product { background-color:#fff }
 *      orderforms/standard_cart/all.min.css .product { background:#fff }
 *
 *    The order form's stylesheet is the LAST link in head.tpl, after this
 *    file. So a plain `.product` here at (0,1,0) loses on source order no
 *    matter what it says. `#products .product` at (1,1,0) wins on specificity
 *    instead, which is order independent.
 *
 * 2. `.panel .panel-heading` is (0,2,0), so the `.card` rule above it at
 *    (0,1,0) never applied to the Categories or Actions panels. Matching its
 *    specificity and adding `.card` gets to (0,3,0).
 *
 * Specificity is raised only as far as needed. `body .x` would outrank
 * Bootstrap utilities like .btn-block and break layout elsewhere.
 * --------------------------------------------------------------------------- */

#products .product,
.products .product {
    background: var(--ink-850);
    border: 1px solid var(--line-soft);
    border-radius: var(--r-md, 10px);
    color: var(--ink-200);
}

#products .product header,
.products .product header {
    background: transparent;
    border-bottom: 1px solid var(--line-soft);
    color: var(--ink-100);
}

#products .product h3,
#products .product .product-name,
.products .product h3 {
    color: var(--ink-100);
}

#products .product .product-desc,
.products .product .product-desc {
    color: var(--ink-300);
}

#products .product .product-pricing,
.products .product .product-pricing {
    color: var(--ink-100);
}

/* "Starting from" and the billing cycle line under the price. */
#products .product .product-pricing small,
#products .product .cycle,
.products .product .product-pricing small {
    color: var(--ink-400);
}

/* Sidebar panels: Categories and Actions. */
.panel.card .panel-heading,
.panel.card .card-header {
    background: transparent;
    border-bottom: 1px solid var(--line-soft);
    color: var(--ink-300);
}

.panel.card .panel-footer,
.panel.card .card-footer {
    background: transparent;
    border-top: 1px solid var(--line-soft);
}

.panel.card .panel-body,
.panel.card .card-body {
    background: transparent;
    color: var(--ink-200);
}

.panel.card .panel-title {
    color: var(--ink-300);
}

/* The category list inside those panels. */
.panel.card .list-group-item {
    background: transparent;
    border-color: var(--line-soft);
    color: var(--ink-200);
}

.panel.card .list-group-item:hover {
    background: var(--ink-800);
    color: var(--ink-100);
}

.panel.card .list-group-item.active {
    background: var(--ink-800);
    border-left: 2px solid var(--cobalt);
    color: var(--ink-100);
}

/* ---------------------------------------------------------------------------
 * nexus escalates the store grid to `body #order-standard_cart ...`
 *
 * theme.min.css writes:
 *     body #order-standard_cart .products .product { background:#fff }
 * at specificity (1,2,1) with a literal white. Nothing below that can win, which
 * is why `.products .product` and `#order-standard_cart .products .product`
 * both applied their border and colour but lost the background.
 *
 * Matched here at the same specificity. custom.css loads after theme.min.css,
 * so equal specificity wins on source order and no !important is needed.
 * Confirmed with CSS.getMatchedStylesForNode rather than by reading files.
 * --------------------------------------------------------------------------- */

body #order-standard_cart .products .product {
    background: var(--ink-850);
    border: 1px solid var(--line-soft);
}

body #order-standard_cart .products .product header {
    background: transparent;
    border-bottom: 1px solid var(--line-soft);
}

body #order-standard_cart .products .product footer .btn-order-now {
    background: var(--cobalt);
    border-color: var(--cobalt);
    color: var(--ink-on-accent);
}

body .panel .panel-heading,
body .panel .panel-footer {
    background: transparent;
}

/* nexus escalates the sidebar panels the same way: literal #fff at (1,3,1).
 * Matched exactly; custom.css loads later so source order settles it. */
body #order-standard_cart .panel .panel-heading,
body #order-standard_cart .panel .card-header {
    background: transparent;
    border-bottom: 1px solid var(--line-soft);
    color: var(--ink-300);
}

body #order-standard_cart .panel .panel-footer,
body #order-standard_cart .panel .card-footer {
    background: transparent;
    border-top: 1px solid var(--line-soft);
}

body #order-standard_cart .panel,
body #order-standard_cart .panel .panel-body {
    background: var(--ink-850);
    color: var(--ink-200);
}

/* The product name bar. nexus reaches it through .cart-body, which is a
 * different ancestor chain from the .products one used above, so the earlier
 * override never matched it. Same specificity (1,2,1), later in the file. */
body #order-standard_cart .cart-body .product header,
body #order-standard_cart .cart-body .product > header {
    background: transparent;
    border-bottom: 1px solid var(--line-soft);
    color: var(--ink-100);
}

body #order-standard_cart .cart-body .product header h3,
body #order-standard_cart .cart-body .product header span {
    color: var(--ink-100);
}

/* The exact selector nexus uses, read from CSS.getMatchedStylesForNode rather
 * than guessed. My earlier attempt omitted `.products` from the chain, so it
 * sat a class below this at (1,2,1) and lost. */
body #order-standard_cart .cart-body .products .product header {
    background: transparent;
    border-bottom: 1px solid var(--line-soft);
    color: var(--ink-100);
}


/* ---------------------------------------------------------------------------
 * Navbar corrections
 *
 * Scope note: the island and the brand lockup are NOT here. Both are already
 * correct in sn-tokens.css (`body .sn-nav-strip`, `body .sn-brand-name`). The
 * navbar looked broken because header.tpl rendered the logo image INSTEAD of
 * the wordmark rather than alongside it, which is fixed in the template.
 * --------------------------------------------------------------------------- */

/* Breadcrumb. nexus paints an accented slab behind the page title via
   `.master-breadcrumb .breadcrumb`, which ties sn-tokens' `body .breadcrumb`
   on specificity and wins on source order. custom.css loads after both, so
   matching the same selector is enough. The V2 site has no such band. */
.master-breadcrumb .breadcrumb {
    background-color: transparent;
    padding: 10px 0;
    margin: 0;
}

/* Search. The two halves disagreed by 10px because only the button had a
   height. Pinning both to 40px lines the control up with the cart button.

   Order caution: the input is classed "appended-form-control" but lives in an
   .input-group-PREPEND pairing, so paint order is [button][input], icon on the
   left. The radii below follow the DOM, not the class name. Inner borders are
   dropped so the pair reads as a single field. */
body #header .search .btn {
    height: 40px;
    border-radius: var(--r-md, 10px) 0 0 var(--r-md, 10px);
    border-right: 0;
    box-shadow: none;
}

body #header .search .form-control {
    height: 40px;
    width: 210px;
    border-radius: 0 var(--r-md, 10px) var(--r-md, 10px) 0;
    border-left: 0;
    box-shadow: none;
}

body #header .search .form-control::placeholder {
    color: var(--ink-500);
}

/* Focus lights the whole control, not the half that happens to have the ring. */
body #header .search:focus-within .btn,
body #header .search .form-control:focus {
    border-color: var(--cobalt);
    box-shadow: none;
}


/* Pin the header so the island has somewhere to travel.
 *
 * .sn-nav-strip is already `position: sticky; top: 0` in sn-tokens.css, but a
 * sticky box is bounded by its parent, and its parent #header is 177px tall
 * with static positioning. So the strip stuck for 177px and then left with the
 * header, which is why the island state applied but was never on screen.
 *
 * The nav row below the island keeps its links reachable while scrolled;
 * sn-tokens already clears its top border in the scrolled state so the two
 * rows read as one surface rather than a stack of slabs. */
body #header.header {
    position: sticky;
    top: 0;
    z-index: 1030;
}



/* ---------------------------------------------------------------------------
 * Nav links inside the bar
 *
 * nexus stacks two navbars: brand row, then a separate links row. header.tpl
 * now renders one row instead, so the links ride into the island rather than
 * being hidden from it.
 *
 * Source order is brand, actions, collapse, search. `order` below rearranges
 * that to brand, links, search, actions at xl+. The reason source order is not
 * simply the visual order: under xl the collapse takes flex-basis 100% and
 * wraps onto its own line, so an actions cluster placed after it would drop
 * the burger below the menu it opens.
 * --------------------------------------------------------------------------- */

@media (min-width: 1200px) {
    body .sn-nav-bar > .container {
        display: flex;
        align-items: center;
        flex-wrap: nowrap;
    }

    body .sn-nav-bar .navbar-brand    { order: 1; margin-right: 8px; flex: 0 0 auto; }
    body .sn-nav-bar .sn-nav-collapse { order: 2; flex: 1 1 auto; min-width: 0; }
    body .sn-nav-bar .sn-search-desktop { order: 3; flex: 0 1 auto; margin-left: 8px; }
    body .sn-nav-bar .sn-nav-actions  { order: 4; flex: 0 0 auto; margin-left: 4px; }

    /* Links centred in the space between brand and search, account pinned to
       the right of them, mirroring the site's links-centre / actions-right. */
    body .sn-nav-bar .sn-nav-collapse { display: flex; align-items: center; }
    body .sn-nav-bar .sn-nav-primary  { margin: 0 auto; flex-wrap: nowrap; }
    body .sn-nav-bar .sn-nav-secondary { margin-left: 0; flex-wrap: nowrap; }

    /* The search is the only part that may shrink when the island clamps to
       1120px, so a long nav never pushes the cart off the end. */
    body .sn-nav-bar .sn-search-desktop .input-group { width: 210px; }
    body .sn-nav-strip[data-scrolled="true"] .sn-search-desktop .input-group { width: 168px; }
    body .sn-nav-bar .sn-search-desktop .form-control { width: auto; min-width: 0; }
}

/* Link treatment, matching the site: quiet by default, white on hover, cobalt
 * underline on the current section.
 *
 * Selectors are `> li > a`, not `.nav-item > .nav-link`. includes/navbar.tpl
 * emits <li class="d-block"><a class=""> with no Bootstrap nav classes at all,
 * so the .nav-item form matched nothing. Specificity is raised with #header to
 * clear sn-tokens' own `body #header #nav > li > a` at (1,2,1). */
body #header .sn-nav-bar .sn-nav-primary > li > a,
body #header .sn-nav-bar .sn-nav-secondary > li > a {
    position: relative;
    padding: 8px 2px;
    font-size: 14px;
    font-weight: 500;
    color: var(--ink-300);
    white-space: nowrap;
    background: transparent;
    transition: color .16s ease;
}

body #header .sn-nav-bar .sn-nav-primary > li > a:hover,
body #header .sn-nav-bar .sn-nav-secondary > li > a:hover {
    background: transparent;
    color: var(--ink-100);
}

body #header .sn-nav-bar .sn-nav-primary > li.active > a {
    background: transparent;
    color: var(--ink-100);
}

/* Underline drawn on the link so it hugs the text rather than a padded box. */
body #header .sn-nav-bar .sn-nav-primary > li.active > a::after {
    content: "";
    position: absolute;
    left: 2px;
    right: 2px;
    bottom: -2px;
    height: 2px;
    border-radius: 2px;
    background: var(--cobalt);
}

/* Under xl the menu stacks into a panel. */
@media (max-width: 1199.98px) {
    /* A bare `#nav { gap: 40px }` sets all gaps; horizontally that is the
       desktop rhythm, but as a row gap in a stacked column it is enormous.
       Needs an id to outrank it. */
    body #header ul#nav.sn-nav-primary,
    body #header ul.sn-nav-secondary {
        row-gap: 2px;
        column-gap: 0;
    }

    /* Bootstrap zeroes .container padding below the expand breakpoint because
       the navbar is meant to supply it. This one does not, so the menu ran to
       the screen edge. */
    body .sn-nav-bar.navbar-expand-xl > .container {
        padding-left: 15px;
        padding-right: 15px;
    }

    body .sn-nav-bar .sn-nav-collapse {
        padding-bottom: 6px;
    }

    body #header .sn-nav-bar .sn-nav-primary > li > a,
    body #header .sn-nav-bar .sn-nav-secondary > li > a {
        display: block;
        padding: 9px 2px;
    }

    body #header .sn-nav-bar .sn-nav-primary > li.active > a::after {
        left: 2px;
        right: auto;
        width: 18px;
        bottom: 4px;
    }
}

/* The search group must not wrap.
 *
 * .input-group is flex-wrap: wrap by default, so clamping it to a fixed width
 * pushed the input onto a second line under the button. min-width: 0 is what
 * actually lets the input shrink: flex items default to min-width: auto, which
 * refuses to go below the field's intrinsic size. */
body .sn-nav-bar .sn-search-desktop .input-group {
    flex-wrap: nowrap;
}

body .sn-nav-bar .sn-search-desktop .input-group-prepend {
    flex: 0 0 auto;
}

body .sn-nav-bar .sn-search-desktop .form-control {
    flex: 1 1 auto;
    min-width: 0;
    width: auto;
}


/* Fit the links, the account menu and the search inside one 1140px row.
 *
 * A bare `#nav { gap: 40px }` sets the horizontal rhythm. That suits the four
 * links on the marketing site; this nav carries six plus Account, and at 40px
 * the row overflowed its flex box and slid under the search field, which then
 * intercepted clicks meant for Account. Narrowing the gap is what makes the
 * row fit; an id is needed to outrank the original rule. */
@media (min-width: 1200px) {
    body #header ul#nav.sn-nav-primary {
        column-gap: 16px;
    }

    body .sn-nav-bar .sn-search-desktop .input-group { width: 190px; }

    /* Nothing in the row may overflow its box, or it reappears beneath a
       neighbour and steals its clicks. */
    body .sn-nav-bar .sn-nav-collapse { overflow: visible; }
    body #header ul#nav.sn-nav-primary,
    body #header ul.sn-nav-secondary { flex-shrink: 0; }
}


/* The island is 58px narrower than the bar at rest, so the row needs to tighten
 * with it or Account slides back under the search. Rides the same transition as
 * the rest of the island, so it reads as one movement. */
@media (min-width: 1200px) {
    body #header .sn-nav-strip[data-scrolled="true"] ul#nav.sn-nav-primary {
        column-gap: 10px;
    }

    body #header ul#nav.sn-nav-primary {
        transition: column-gap .28s ease;
    }
}


/* Account is a control, not a seventh nav link, so it gets air before it the
 * way the site separates "Sign in" from its links. Paid for out of the slack
 * left by the tightened island gap. */
@media (min-width: 1200px) {
    body #header ul.sn-nav-secondary {
        margin-left: 18px;
    }
}


/* ---------------------------------------------------------------------------
 * Match the marketing site's nav metrics
 *
 * Values measured off surgenode.net/v2 rather than eyeballed: 1440 wide at
 * rest, 74 tall; 1120 and 64 as an island; links 13px/500 with a 32px gap; the
 * active tab a 2px cobalt underline.
 * --------------------------------------------------------------------------- */

@media (min-width: 1200px) {
    /* The site's bar is 1440, not Bootstrap's 1140. The island still clamps the
       parent to 1120, so this only widens the at-rest state. */
    body .sn-nav-bar > .container {
        max-width: 1440px;
    }

    /* The 25px of extra island height was mt-2/mb-2 on the container. */
    body .sn-nav-bar > .container {
        margin-top: 0;
        margin-bottom: 0;
    }

    /* Row height is set by the tallest control, which is the search. */
    body #header .search .btn,
    body #header .search .form-control,
    body .sn-nav-bar .sn-search-desktop .btn,
    body .sn-nav-bar .sn-search-desktop .form-control {
        height: 38px;
    }

    body #header ul#nav.sn-nav-primary {
        column-gap: 32px;
    }

    /* The island is 1120 against the site's 4 links; this nav carries 6 plus
       Account, so the search gives up the difference instead of the gap. */
    body .sn-nav-bar .sn-search-desktop .input-group { width: 190px; }
    body #header .sn-nav-strip[data-scrolled="true"] .sn-search-desktop .input-group { width: 150px; }
}

/* Links at the site's 13px/500. */
body #header .sn-nav-bar .sn-nav-primary > li > a,
body #header .sn-nav-bar .sn-nav-secondary > li > a {
    font-size: 13px;
    font-weight: 500;
    padding: 6px 0;
}

/* Active tab: 2px cobalt under the text, matching the site exactly. The
   .sn-active class is applied by the marker script in header.tpl, because
   WHMCS never sets .active on these items itself. */
body #header .sn-nav-bar .sn-nav-primary > li.sn-active > a {
    color: var(--ink-100);
}

body #header .sn-nav-bar .sn-nav-primary > li.sn-active > a::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: -3px;
    height: 2px;
    border-radius: 2px;
    background: var(--cobalt);
}


/* The site's exact nav box model.
 *
 *   at rest   1440 wide, padding 14px 28px, 46px of content  -> 74 tall
 *   island    1120 wide, padding 9/16/9/20, 46px of content  -> 64 tall
 *
 * .sn-nav-bar takes the island chrome from sn-tokens, so .container carries the
 * at-rest padding and surrenders its vertical padding once scrolled, letting
 * the bar's own 9/9 land the island on 64.
 *
 * The row was measuring 53 rather than 46 because the nav <ul> keeps the UA's
 * default block margin; .navbar-nav only clears margin-bottom. */
@media (min-width: 1200px) {
    body #header .sn-nav-bar > .container {
        max-width: 1440px;
        padding: 14px 28px;
        min-height: 74px;
        align-items: center;
    }

    body #header .sn-nav-bar .navbar-collapse,
    body #header .sn-nav-bar .navbar-collapse > ul,
    body #header .sn-nav-bar .navbar-nav {
        margin-top: 0;
        margin-bottom: 0;
    }

    body #header .sn-nav-strip[data-scrolled="true"] .sn-nav-bar > .container {
        padding-top: 0;
        padding-bottom: 0;
        min-height: 46px;
    }
}


/* Exact heights. .sn-nav-bar carries min-height: 70px, which floored the island
 * at 70 no matter how short its contents were. Everything here is border-box,
 * so at rest 74 = 72 container + 2 border, and as an island
 * 64 = 44 container + 18 padding + 2 border. */
@media (min-width: 1200px) {
    body #header .sn-nav-bar > .container { min-height: 72px; }

    body #header .sn-nav-strip[data-scrolled="true"] .sn-nav-bar {
        min-height: 64px;
    }

    body #header .sn-nav-strip[data-scrolled="true"] .sn-nav-bar > .container {
        min-height: 44px;
    }
}


/* The content area must not paint over the dot field.
 *
 * nexus gives #main-body an opaque background, which covered .sn-page-grid for
 * the whole page and read as a grey slab against the black header and footer.
 * The site's equivalent <main> is transparent and lets body's #050505 plus the
 * fixed dot layer show through. Cards keep their own surface, so only the
 * wrapper is cleared. */
body #main-body {
    background: transparent;
}


/* ---------------------------------------------------------------------------
 * Nav dropdown, matched to the marketing site's .nav-dropdown
 *
 * Background, border, shadow and padding already matched. What did not: the
 * radius, the width, the trigger offset and the rows.
 *
 * sn-tokens wins the panel with `body .dropdown-menu` at (0,1,1), so a bare
 * `.dropdown-menu` here loses despite loading later. These carry #header to
 * clear it and to stay scoped to the navbar, leaving client-area dropdowns be.
 * --------------------------------------------------------------------------- */

body #header .dropdown-menu {
    min-width: 300px;
    border-radius: var(--r-chip, 6px);
    padding: 6px;
    /* The site sits 12px under its trigger. This menu anchors to the parent li,
       which is shorter than the bar, so the offset also has to clear the row. */
    margin-top: 10px;
    box-shadow: 0 18px 40px rgba(0, 0, 0, .45);
}

/* The row is the <a>. The <li> also carries .dropdown-item, so it has to be
   neutralised or every row gets padded and hover-highlighted twice. */
body #header .dropdown-menu > li.dropdown-item {
    padding: 0;
    background: transparent;
    border: 0;
    border-radius: var(--r-chip, 6px);
}

body #header .dropdown-menu > li.dropdown-item:hover,
body #header .dropdown-menu > li.dropdown-item:focus {
    background: transparent;
}

body #header .dropdown-menu a.dropdown-item {
    display: flex;
    align-items: center;
    /* min-height rather than padding: the anchor carries px-2/py-0, which are
       !important, and this reaches the same row height without fighting them. */
    min-height: 38px;
    font-size: 13.5px;
    font-weight: 600;
    line-height: 1.3;
    color: var(--ink-100);
    background: transparent;
    border-radius: var(--r-chip, 6px);
    transition: background-color .15s ease;
}

/* The site tints hover with 10% cobalt over --ink-800 rather than a flat grey. */
body #header .dropdown-menu a.dropdown-item:hover,
body #header .dropdown-menu a.dropdown-item:focus {
    background-color: var(--ink-800);
    background-color: color-mix(in srgb, var(--cobalt) 10%, var(--ink-800));
    color: var(--ink-100);
}

body #header .dropdown-menu a.dropdown-item:active {
    background-color: color-mix(in srgb, var(--cobalt) 16%, var(--ink-800));
    color: var(--ink-100);
}

/* The site has no dividers at all. This menu genuinely groups "Browse All"
   away from the rest, so the rule stays but drops to a hairline. */
body #header .dropdown-menu .dropdown-divider {
    margin: 6px 4px;
    border-top: 1px solid var(--line-soft);
}

/* ---------------------------------------------------------------------------
 * Client area home cards
 *
 * nexus paints these white from selectors that outrank the theme's own:
 *   .client-home-cards .card-header                             (0,2,0)
 *   body .primary-content .client-home-cards .card .card-footer (0,4,1)
 *   body ... .card-header .btn                                  (0,5,1)
 * Matching nexus's selector shape ties the specificity, and custom.css loads
 * later, so these win without !important. The .list-group borders are the one
 * exception: nexus sets them !important.
 * --------------------------------------------------------------------------- */

.client-home-cards .card-header {
    background-color: var(--ink-800);
    border-bottom: 1px solid var(--line-soft);
    color: var(--ink-100);
}

body .primary-content .client-home-cards .card .card-header,
body .primary-content .client-home-cards .mc-promo-login .card-header,
body .primary-content .client-home-cards .mc-promo-manage .card-header {
    background: var(--ink-800);
    color: var(--ink-100);
}

body .primary-content .client-home-cards .card .card-footer,
body .primary-content .client-home-cards .mc-promo-login .card-footer,
body .primary-content .client-home-cards .mc-promo-manage .card-footer {
    background: var(--ink-850);
    border-top: 1px solid var(--line-soft);
    color: var(--ink-300);
}

/* Buttons sitting in those headers and footers were white on white. */
body .primary-content .client-home-cards .card .card-header .btn,
body .primary-content .client-home-cards .mc-promo-login .card-header .btn,
body .primary-content .client-home-cards .mc-promo-manage .card-header .btn {
    background: transparent;
    border: 1px solid var(--line);
    color: var(--ink-200);
}

body .primary-content .client-home-cards .card .card-header .btn:hover,
body .primary-content .client-home-cards .mc-promo-login .card-header .btn:hover,
body .primary-content .client-home-cards .mc-promo-manage .card-header .btn:hover {
    background: var(--ink-750, #161616);
    color: var(--ink-100);
}

/* nexus hardcodes #ddd here with !important, so this has to answer in kind. */
.client-home-cards .list-group {
    border-top: 1px solid var(--line-soft) !important;
    border-bottom: 1px solid var(--line-soft) !important;
}

.client-home-cards .list-group .list-group-item {
    background: transparent;
    border-bottom: 1px solid var(--line-soft);
    color: var(--ink-200);
}

.client-home-cards .list-group .list-group-item:last-child {
    border-bottom: 0;
}

/* #888 on a dark card is unreadable. */
.client-home-cards small {
    color: var(--ink-400);
}


/* ---------------------------------------------------------------------------
 * Client area: the Update button
 *
 * `body .sidebar .btn-success` replaced the background with --bg-inverted but
 * left the colour from `body .btn-success`, which is #04140b, the dark ink
 * meant to sit on --mint. Dark green ink on --ink-700 is roughly 1.2:1.
 *
 * It is the primary action of its card, so it becomes cobalt rather than
 * merely legible, matching the site's primary button.
 * --------------------------------------------------------------------------- */

body .sidebar .btn-success,
body .sidebar .btn-success:focus {
    background: var(--cobalt);
    border-color: var(--cobalt);
    color: var(--ink-on-accent, #04202c);
    font-weight: 600;
}

body .sidebar .btn-success:hover {
    background: color-mix(in srgb, #ffffff 12%, var(--cobalt));
    border-color: color-mix(in srgb, #ffffff 12%, var(--cobalt));
    color: var(--ink-on-accent, #04202c);
}

/* ---------------------------------------------------------------------------
 * Client area: Your Active Products/Services
 *
 * Scoped to #servicesPanel and to .div-service-item, which only ever appears
 * in a services list, so no other panel is touched.
 * --------------------------------------------------------------------------- */

/* The design carries ONE accent. An amber top edge and an amber button are
   left over from nexus's colour-coded panels. */
body [class*="card-accent-"] {
    border-top-color: var(--line);
}

body #servicesPanel .card-header .btn.bg-color-gold {
    background: transparent;
    border: 1px solid var(--line);
    color: var(--ink-200);
    font-weight: 600;
}

body #servicesPanel .card-header .btn.bg-color-gold:hover {
    background: color-mix(in srgb, var(--cobalt) 12%, var(--ink-800));
    border-color: color-mix(in srgb, var(--cobalt) 40%, transparent);
    color: var(--ink-100);
}

/* Rows. Separator rules go; spacing and a hover tint carry the grouping, the
   same treatment the nav dropdown uses so the two read as one system. */
body #servicesPanel .list-group {
    border: 0;
    padding: 6px;
}

body #servicesPanel .list-group-item {
    background: transparent;
    border: 0;
    border-radius: var(--r-chip, 6px);
    padding: 0;
    margin: 0;
    transition: background-color .15s ease;
}

body #servicesPanel .list-group-item:hover,
body #servicesPanel .list-group-item.list-group-item-action:hover,
body #servicesPanel .list-group-item.list-group-item-action:focus {
    background-color: color-mix(in srgb, var(--cobalt) 10%, var(--ink-800));
    color: var(--ink-100);
}

body #servicesPanel .div-service-item {
    padding: 9px 12px;
    gap: 12px;
}

/* Product name and the address line under it. */
body #servicesPanel .div-service-name .font-weight-bold {
    color: var(--ink-100);
    font-size: 13.5px;
    font-weight: 600;
}

body #servicesPanel .div-service-name .text-domain {
    color: var(--ink-400);
    font-size: 12px;
}

/* Status: a coloured dot and plain text, no chip.
 *
 * Applies to every status, not just Active. nexus assigns a per-status colour
 * to --st (mint for success, amber for warning, and so on), so the dot reads
 * that and each state is coloured correctly without enumerating them here.
 * Unknown statuses fall back to --ink-400 rather than vanishing.
 *
 * The .label-placeholder sibling is position:absolute + visibility:hidden and
 * exists only to reserve width, so its dot never paints. */
body #servicesPanel .div-service-status .label,
body #servicesPanel .div-service-status .label.label-success,
body #servicesPanel .div-service-status .label.label-warning,
body #servicesPanel .div-service-status .label.label-danger {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    background: transparent;
    border: 0;
    border-radius: 0;
    padding: 0;
    color: var(--ink-200);
    font-size: 12.5px;
    font-weight: 500;
    letter-spacing: 0;
    text-transform: none;
}

body #servicesPanel .div-service-status .label::before {
    content: "";
    flex: 0 0 auto;
    width: 7px;
    height: 7px;
    border-radius: 999px;
    background: var(--st, var(--ink-400));
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--st, var(--ink-400)) 18%, transparent);
}

/* View Details: was 36px at 14px, heavier than the row itself. */
body #servicesPanel .div-service-buttons .btn {
    padding: 5px 11px;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--ink-300);
    background: transparent;
    border: 1px solid var(--line-soft);
    border-radius: var(--r-chip, 6px);
}

body #servicesPanel .div-service-buttons .btn:hover {
    background: color-mix(in srgb, var(--cobalt) 14%, var(--ink-800));
    border-color: color-mix(in srgb, var(--cobalt) 45%, transparent);
    color: var(--ink-100);
}

/* Footer sat at 3px of padding, so "View More..." was jammed against the edge. */
body #servicesPanel .card-footer {
    padding: 9px 20px;
    background: transparent;
    border-top: 1px solid var(--line-soft);
}

body #servicesPanel .card-footer .btn-view-more {
    color: var(--ink-300);
    font-size: 12.5px;
    font-weight: 600;
}

body #servicesPanel .card-footer .btn-view-more:hover {
    color: var(--cobalt);
}


/* ---------------------------------------------------------------------------
 * Radii, aligned to the marketing site
 *
 * Tokens already matched; these fix components reaching for the wrong one.
 * Measured vocabulary on the site: 10px big surfaces, 6px controls and icon
 * tiles, 999px text chips, 12px tiles.
 * --------------------------------------------------------------------------- */

/* Store product cards rendered 8px against the site's 10px card surfaces. */
body #order-standard_cart .products .product,
body #products .product,
body .products .product {
    border-radius: var(--r-md, 10px);
}

/* Controls are 6px on the site. The search halves were on --r-md, which left
   them visibly rounder than the buttons beside them. */
body #header .search .btn,
body .sn-nav-bar .sn-search-desktop .btn {
    border-radius: var(--r-btn, 6px) 0 0 var(--r-btn, 6px);
}

body #header .search .form-control,
body .sn-nav-bar .sn-search-desktop .form-control {
    border-radius: 0 var(--r-btn, 6px) var(--r-btn, 6px) 0;
}

body .btn-sm,
body .btn-xs,
body .btn-block {
    border-radius: var(--r-btn, 6px);
}

/* Text chips are pills on the site (.gm-chip, 999px), not 6px rectangles. */
body .label,
body .label.status,
body #servicesPanel .div-service-status .label.label-success,
body #servicesPanel .div-service-status .label.label-warning,
body #servicesPanel .div-service-status .label.label-danger {
    border-radius: var(--r-pill, 999px);
}

/* The cart count is already a pill; keep it that way rather than inheriting
   the chip rule's specificity fight. */
body #header .cart-btn .badge {
    border-radius: var(--r-pill, 999px);
}

/* Border leak: the client-home-cards list-group rule uses !important to answer
   nexus's #ddd, and the services panel is inside .client-home-cards, so it drew
   a second hairline under the card header. */
body #servicesPanel .list-group {
    border-top: 0 !important;
    border-bottom: 0 !important;
}


/* ---------------------------------------------------------------------------
 * Service details page
 * --------------------------------------------------------------------------- */

/* The product tile was rgb(239,239,239) with rgb(212,212,212) text, so the
   product name and group were invisible. nexus assumes a light theme here. */
body .product-icon {
    background: var(--ink-800);
    border: 1px solid var(--line-soft);
    border-bottom: 0;
    border-radius: var(--r-md, 10px) var(--r-md, 10px) 0 0;
    color: var(--ink-100);
}

body .product-icon h1,
body .product-icon h2,
body .product-icon h3,
body .product-icon .product-name,
body .product-icon strong {
    color: var(--ink-100);
}

body .product-icon small,
body .product-icon .product-group,
body .product-icon p {
    color: var(--ink-400);
}

/* The icon medallion sat on a light disc. */
body .product-icon .fa-stack,
body .product-icon .fa-circle {
    color: var(--ink-900);
}

/* Status band under the tile. */
body .product-status {
    border-radius: 0 0 var(--r-md, 10px) var(--r-md, 10px);
    font-weight: 600;
    letter-spacing: .04em;
}

/* Destructive actions are outlined, not a full-width solid slab. */
body .btn-danger,
body .btn-danger:focus {
    background: transparent;
    border: 1px solid color-mix(in srgb, var(--danger, #ff4d6d) 45%, transparent);
    color: var(--danger, #ff4d6d);
    font-weight: 600;
}

body .btn-danger:hover {
    background: color-mix(in srgb, var(--danger, #ff4d6d) 14%, transparent);
    border-color: var(--danger, #ff4d6d);
    color: var(--danger, #ff4d6d);
}

/* ---------------------------------------------------------------------------
 * Service rows: vertical centring
 *
 * .div-service-item is a flex row. Rows carrying an address line under the
 * product name are taller, and without this the chip and the button aligned to
 * the top of the row rather than its middle.
 * --------------------------------------------------------------------------- */

body #servicesPanel .div-service-item {
    display: flex;
    align-items: center;
}

body #servicesPanel .div-service-status {
    display: flex;
    align-items: center;
}

body #servicesPanel .div-service-name {
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-width: 0;
}

body #servicesPanel .div-service-buttons {
    display: flex;
    align-items: center;
    margin-left: auto;
}

/* ---------------------------------------------------------------------------
 * Secondary buttons in the sidebar cards
 *
 * A full-strength --line border across the full width outweighed the primary
 * action sitting above it.
 * --------------------------------------------------------------------------- */

body .sidebar .btn-default,
body .sidebar .btn-block.btn-default {
    background: transparent;
    border: 1px solid var(--line-soft);
    color: var(--ink-200);
    font-weight: 600;
}

body .sidebar .btn-default:hover {
    background: color-mix(in srgb, var(--cobalt) 12%, var(--ink-800));
    border-color: color-mix(in srgb, var(--cobalt) 40%, transparent);
    color: var(--ink-100);
}


/* The product tile, at the specificity nexus actually uses.
 * `div.product-details div.product-icon` is (0,2,2); a plain `body
 * .product-icon` is (0,2,1) and loses on the type-selector column. */
body div.product-details div.product-icon {
    background-color: var(--ink-800);
    border: 1px solid var(--line-soft);
    border-bottom: 0;
    border-radius: var(--r-md, 10px) var(--r-md, 10px) 0 0;
}

body div.product-details div.product-icon h3 {
    color: var(--ink-100);
    font-weight: 700;
}

body div.product-details div.product-icon h4 {
    color: var(--ink-400);
    font-size: 14px;
}

/* The medallion disc behind the product glyph. */
body div.product-details div.product-icon .fa-stack .fa-circle {
    color: var(--ink-900);
}


/* Radii, second pass: the order form escalates its own selectors.
 *
 *   body #order-standard_cart .cart-body .products .product  -> 8px  (1,4,1)
 *   body #order-standard_cart .products .product footer .btn -> 10px
 *
 * A (1,3,1) override loses to the first and a (0,1,1) one loses to the second,
 * so both are matched at their own shape. Site vocabulary: 10px card surfaces,
 * 6px controls. */
body #order-standard_cart .cart-body .products .product {
    border-radius: var(--r-md, 10px);
}

body #order-standard_cart .products .product footer .btn,
body #order-standard_cart .cart-body .products .product footer .btn {
    border-radius: var(--r-btn, 6px);
}

/* Sidebar buttons were landing on 10px against the site's 6px controls. */
body .sidebar .btn,
body .sidebar .btn-success,
body .sidebar .btn-default,
body .sidebar .btn-block {
    border-radius: var(--r-btn, 6px);
}


/* The last service row kept a 1px #ddd hairline that nothing in nexus appears
 * to set on :last-child, and which survived a `border: 0` at (1,2,1). Scoped
 * to this panel and marked important rather than left rendering a stray
 * light-theme line above the footer. */
body #servicesPanel .list-group > .list-group-item,
body #servicesPanel .list-group > .list-group-item:last-child {
    border-bottom: 0 !important;
    border-top: 0 !important;
}

/* Panel title, centred against its button.
 *
 * The header is a block <h3> holding a right-floated button. Floats are out of
 * flow, so the title sat 8px above the button's centre. Flex fixes it; the
 * button is first in the DOM, so it is ordered last and pushed right. */
body #servicesPanel .card-header .card-title {
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 36px;
}

body #servicesPanel .card-header .card-title .float-right {
    float: none;
    order: 2;
    margin-left: auto;
}

/* The cube glyph should sit on the text baseline, not ride above it. */
body #servicesPanel .card-header .card-title > i {
    line-height: 1;
}


/* ---------------------------------------------------------------------------
 * Cart: Configure, review and checkout
 *
 * Everything here was measured under 3:1. Two failure modes: nexus's light
 * surfaces showing through, and light-theme ink left on dark.
 * --------------------------------------------------------------------------- */

/* Section legend ("Configurable Options", "Available Addons"). It sits on top
   of a divider rule and must stay opaque to break it, so it takes the page
   colour instead of going transparent. Was #f5f5f5 on #f8f9fa. */
body .primary-bg-color,
body #order-standard_cart .primary-bg-color {
    background-color: var(--ink-900);
    color: var(--ink-300);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    padding: 0 12px;
}

/* Config selects carried black ink on a dark control. The <option> list needs
   setting too, or the closed control reads and the open one does not. */
body #order-standard_cart select,
body #order-standard_cart select.form-control,
body select.form-control {
    background-color: var(--ink-800);
    border: 1px solid var(--line);
    color: var(--ink-100);
}

body #order-standard_cart select option,
body select.form-control option {
    background-color: var(--ink-800);
    color: var(--ink-100);
}

/* Billing cycle and any other cart field. */
body #order-standard_cart .form-control,
body #order-standard_cart input[type="text"] {
    background-color: var(--ink-800);
    border: 1px solid var(--line);
    color: var(--ink-100);
}

body #order-standard_cart label {
    color: var(--ink-100);
}

/* Addon cards. */
body #order-standard_cart .panel-price,
body .panel-price {
    background-color: var(--ink-800);
    color: var(--ink-200);
    border-top: 1px solid var(--line-soft);
}

/* Was Bootstrap 3's #5cb85c at 2.48:1, and off-palette besides. */
body #order-standard_cart .panel-add,
body .panel-add {
    background-color: var(--cobalt);
    color: var(--ink-on-accent, #04202c);
    font-weight: 600;
}

body #order-standard_cart .panel-add:hover,
body .panel-add:hover {
    background-color: color-mix(in srgb, #ffffff 12%, var(--cobalt));
    color: var(--ink-on-accent, #04202c);
}

/* "Apply Promo Code" tab was #f5f5f5 on #fff. */
body #order-standard_cart .nav-tabs .nav-link.active,
body #order-standard_cart .nav-link.active,
body .promo-tabs .nav-link.active {
    background-color: transparent;
    color: var(--ink-100);
    border-color: var(--line) var(--line) transparent;
}

/* Checkout button: the Update-button bug again. A rule replaced the background
   with a grey and left #04140b, the ink meant for mint, at 1.01:1. */
body a#checkout.btn,
body #checkout.btn.btn-success,
body #order-standard_cart #checkout {
    background: var(--cobalt);
    border-color: var(--cobalt);
    color: var(--ink-on-accent, #04202c);
    font-weight: 700;
}

body a#checkout.btn:hover,
body #checkout.btn.btn-success:hover {
    background: color-mix(in srgb, #ffffff 12%, var(--cobalt));
    border-color: color-mix(in srgb, #ffffff 12%, var(--cobalt));
    color: var(--ink-on-accent, #04202c);
}

body a#continueShopping,
body #continueShopping.btn-link {
    color: var(--ink-300);
}

body a#continueShopping:hover,
body #continueShopping.btn-link:hover {
    color: var(--cobalt);
}


/* ---------------------------------------------------------------------------
 * pterosync Quick Actions
 *
 * One neutral button treatment; only the icon carries the state colour. Scoped
 * to the module's own ids (overview.tpl) so it cannot reach the Update or
 * Checkout buttons, which are also .btn-success.
 * --------------------------------------------------------------------------- */

body #startButton.btn,
body #rebootButton.btn,
body #stopButton.btn,
body #killButton.btn,
body .btn-info[data-target="#ftpDetails"] {
    background: transparent;
    border: 1px solid var(--line);
    border-radius: var(--r-btn, 6px);
    color: var(--ink-100);
    font-weight: 600;
    padding: 9px 16px;
    transition: background-color .15s ease, border-color .15s ease;
}

body #startButton.btn:hover:not(:disabled),
body #rebootButton.btn:hover:not(:disabled),
body #stopButton.btn:hover:not(:disabled),
body #killButton.btn:hover:not(:disabled),
body .btn-info[data-target="#ftpDetails"]:hover {
    background: var(--ink-800);
    border-color: var(--line-strong);
    color: var(--ink-100);
}

/* The icon is the only thing that carries state colour. */
body #startButton.btn i          { color: var(--mint); }
body #rebootButton.btn i         { color: var(--amber); }
body #stopButton.btn i,
body #killButton.btn i           { color: var(--danger, #ff4d6d); }
body .btn-info[data-target="#ftpDetails"] i { color: var(--cobalt); }

/* Start is disabled while online, Stop while offline. Say so visually. */
body #startButton.btn:disabled,
body #rebootButton.btn:disabled,
body #stopButton.btn:disabled,
body #killButton.btn:disabled {
    opacity: 1;
    background: transparent;
    border-color: var(--line-soft);
    color: var(--ink-500);
    cursor: not-allowed;
}

body #startButton.btn:disabled i,
body #rebootButton.btn:disabled i,
body #stopButton.btn:disabled i,
body #killButton.btn:disabled i {
    color: var(--ink-600);
}


/* ---------------------------------------------------------------------------
 * Service details header
 *
 * Icon (no circle) left of the name and group, lockup centred, no green.
 *
 * .product-icon holds span.fa-stack + h3 + h4 as flat siblings with no wrapper
 * around the text, so a grid with named areas is what lets the icon span both
 * text rows without touching the template.
 * --------------------------------------------------------------------------- */

body div.product-details div.product-icon {
    display: grid;
    grid-template-columns: auto auto;
    grid-template-areas:
        "icon name"
        "icon group";
    justify-content: center;
    align-items: center;
    column-gap: 14px;
    row-gap: 2px;
    text-align: left;
    padding: 22px 20px;
}

body div.product-details div.product-icon .fa-stack { grid-area: icon; }
body div.product-details div.product-icon h3        { grid-area: name; }
body div.product-details div.product-icon h4        { grid-area: group; }

/* fa-stack is a fixed 2em box built around the circle. With the circle gone it
   is unsized and the glyph scaled directly, or the icon renders tiny. */
body div.product-details div.product-icon .fa-stack {
    width: auto;
    height: auto;
    line-height: 1;
    display: inline-flex;
    align-items: center;
}

body div.product-details div.product-icon .fa-stack .fa-circle {
    display: none;
}

/* fa-inverse is white because it was meant to sit on the circle. */
body div.product-details div.product-icon .fa-stack .fa-stack-1x,
body div.product-details div.product-icon .fa-stack .fa-inverse {
    position: static;
    width: auto;
    line-height: 1;
    font-size: 30px;
    color: var(--cobalt);
}

body div.product-details div.product-icon h3 {
    margin: 0;
    font-size: 18px;
    font-weight: 700;
    line-height: 1.2;
}

body div.product-details div.product-icon h4 {
    margin: 0;
    font-size: 13px;
    font-weight: 400;
    line-height: 1.2;
}

/* No green. .product-status tinted the whole block and the strip sat on it;
   state is carried by the dot alone now, matching the services list. */
body div.product-details .product-status {
    background: transparent;
    border: 1px solid var(--line-soft);
    border-radius: var(--r-md, 10px);
    overflow: hidden;
}

body div.product-details .product-status-text {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    background: transparent;
    border-top: 1px solid var(--line-soft);
    padding: 10px;
    color: var(--ink-200);
    font-size: 12.5px;
    font-weight: 500;
    letter-spacing: 0;
    text-transform: none;
}

body div.product-details .product-status-text::before {
    content: "";
    width: 7px;
    height: 7px;
    border-radius: 999px;
    background: var(--st, var(--mint));
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--st, var(--mint)) 18%, transparent);
}

/* Statuses other than active get their own dot colour. */
body div.product-details .product-status-suspended   { --st: var(--danger, #ff4d6d); }
body div.product-details .product-status-pending     { --st: var(--amber); }
body div.product-details .product-status-terminated,
body div.product-details .product-status-cancelled   { --st: var(--ink-500); }

/* Meta column: label/value rows instead of centred bold-over-plain text.
   The values are BARE TEXT NODES with no element around them, so they cannot
   be selected. Making the column a grid turns each anonymous inline run into
   its own grid item, which is what pairs each value with its label. */
body div.product-details .col-md-6.text-center {
    display: grid;
    grid-template-columns: max-content 1fr;
    align-items: baseline;
    column-gap: 28px;
    row-gap: 14px;
    /* .text-center is a Bootstrap utility carrying !important, so this has to
       answer in kind or every value stays centred. */
    text-align: left !important;
    align-content: start;
}

body div.product-details .col-md-6.text-center h4 {
    margin: 0;
    padding: 0;
    font-size: 12.5px;
    font-weight: 500;
    color: var(--ink-400);
    white-space: nowrap;
    line-height: 1.4;
}


/* ---------------------------------------------------------------------------
 * DataTables controls
 *
 * The filter box measured rgb(255,255,255) with rgb(245,245,245) text, so the
 * search field on My Products was white on white and looked empty. Pagination
 * links carried rgb(42,42,42) on the dark page.
 * --------------------------------------------------------------------------- */

body .dataTables_wrapper .dataTables_filter input,
body .dataTables_wrapper input[type="search"],
body .dataTables_filter input {
    background-color: var(--ink-800);
    border: 1px solid var(--line);
    border-radius: var(--r-btn, 6px);
    color: var(--ink-100);
    padding: 7px 11px;
    min-width: 220px;
}

body .dataTables_wrapper .dataTables_filter input::placeholder,
body .dataTables_wrapper input[type="search"]::placeholder {
    color: var(--ink-500);
}

body .dataTables_wrapper .dataTables_filter input:focus,
body .dataTables_wrapper input[type="search"]:focus {
    border-color: var(--cobalt);
    outline: none;
    box-shadow: none;
}

body .dataTables_wrapper .dataTables_filter label,
body .dataTables_wrapper .dataTables_length label,
body .dataTables_wrapper .dataTables_info {
    color: var(--ink-300);
}

body .dataTables_wrapper .dataTables_length select {
    background-color: var(--ink-800);
    border: 1px solid var(--line);
    border-radius: var(--r-btn, 6px);
    color: var(--ink-100);
}

/* Pagination. */
body .dataTables_wrapper .paginate_button,
body .dataTables_wrapper .paginate_button a {
    color: var(--ink-200);
}

body .dataTables_wrapper .paginate_button.disabled,
body .dataTables_wrapper .paginate_button.disabled a {
    color: var(--ink-500);
}

body .dataTables_wrapper .paginate_button.active a,
body .dataTables_wrapper .page-item.active .page-link {
    background-color: var(--cobalt);
    border-color: var(--cobalt);
    color: var(--ink-on-accent, #04202c);
}


/* The DataTables filter box, matched at nexus's own shape.
 *
 * nexus paints it with `background: url(search.png) #fff no-repeat` on
 * `.dataTables_wrapper .dataTables_filter label .form-control`, served
 * body-prefixed at (0,3,2). My first attempt was (0,2,2) and lost, so the
 * field stayed white with white text in it.
 *
 * search.png is a dark glyph drawn for a white field and disappears on a dark
 * one, so it is swapped for an inline SVG tinted to --ink-500. The 45px left
 * padding nexus sets !important is exactly the room the icon needs, so it is
 * left alone. */
body .dataTables_wrapper .dataTables_filter label .form-control,
body div.dataTables_wrapper div.dataTables_filter label .form-control {
    background-color: var(--ink-800);
    border: 1px solid var(--line);
    border-radius: var(--r-btn, 6px);
    color: var(--ink-100);
    height: auto;
}

body .dataTables_wrapper .dataTables_filter label .form-control:focus {
    border-color: var(--cobalt);
    box-shadow: none;
    outline: none;
}

body .dataTables_wrapper .dataTables_filter label .form-control::placeholder {
    color: var(--ink-500);
}


/* The search field is input[type="search"], so the UA draws its own decoration
 * on top of our background. That is the second magnifier: our SVG is a single
 * background layer, the label holds nothing else, and both pseudo-elements are
 * empty, yet two rings rendered and swapping our SVG changed nothing. */
body .dataTables_wrapper .dataTables_filter label .form-control[type="search"],
body .dataTables_filter input[type="search"] {
    -webkit-appearance: none;
    appearance: none;
}

body .dataTables_filter input[type="search"]::-webkit-search-decoration,
body .dataTables_filter input[type="search"]::-webkit-search-results-button,
body .dataTables_filter input[type="search"]::-webkit-search-results-decoration {
    -webkit-appearance: none;
    display: none;
}

/* Keep the clear button, but tint it so it is visible on a dark field. */
body .dataTables_filter input[type="search"]::-webkit-search-cancel-button {
    -webkit-appearance: none;
    height: 14px;
    width: 14px;
    cursor: pointer;
    background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 14 14' fill='none' stroke='%238f8f8f' stroke-width='1.6' stroke-linecap='round'%3E%3Cline x1='3.5' y1='3.5' x2='10.5' y2='10.5'/%3E%3Cline x1='10.5' y1='3.5' x2='3.5' y2='10.5'/%3E%3C/svg%3E") no-repeat center;
}


/* ---------------------------------------------------------------------------
 * Client-area sidebar rails
 *
 * Same treatment as the cart rail: spaced rows, 6px radius, solid cobalt with
 * dark ink on hover and selection.
 *
 * The stock active state is a 18% cobalt tint plus `box-shadow: cobalt 2px 0 0`
 * (a left bar). The bar is redundant once the whole row fills, so it is
 * cleared explicitly; leaving it produces a lighter stripe over the fill.
 * --------------------------------------------------------------------------- */

body .card-sidebar .list-group,
body .panel-sidebar .list-group {
    padding: 6px;
    border: 0;
}

body .card-sidebar .list-group-item,
body .panel-sidebar .list-group-item {
    background: transparent;
    border: 0;
    border-radius: var(--r-btn, 6px);
    margin-bottom: 4px;
    padding: 9px 12px;
    color: var(--ink-300);
    box-shadow: none;
    transition: background-color .15s ease, color .15s ease;
}

body .card-sidebar .list-group-item:last-child,
body .panel-sidebar .list-group-item:last-child {
    margin-bottom: 0;
}

body .card-sidebar .list-group-item:hover,
body .card-sidebar .list-group-item:focus,
body .card-sidebar .list-group-item.active,
body .panel-sidebar .list-group-item:hover,
body .panel-sidebar .list-group-item.active {
    background: var(--cobalt);
    color: var(--ink-on-accent, #04202c);
    box-shadow: none;
}

/* Icons would otherwise stay cobalt on cobalt and disappear. */
body .card-sidebar .list-group-item:hover i,
body .card-sidebar .list-group-item.active i,
body .card-sidebar .list-group-item:hover .fa,
body .card-sidebar .list-group-item.active .fa,
body .panel-sidebar .list-group-item:hover i,
body .panel-sidebar .list-group-item.active i {
    color: var(--ink-on-accent, #04202c);
}

/* Badge counts: a light chip on a cobalt row is unreadable, so invert it. */
body .card-sidebar .list-group-item .badge,
body .panel-sidebar .list-group-item .badge {
    background: var(--ink-800);
    color: var(--ink-200);
    border-radius: var(--r-pill, 999px);
    font-weight: 600;
}

body .card-sidebar .list-group-item:hover .badge,
body .card-sidebar .list-group-item.active .badge,
body .panel-sidebar .list-group-item:hover .badge,
body .panel-sidebar .list-group-item.active .badge {
    background: rgba(0, 0, 0, .26);
    color: var(--ink-on-accent, #04202c);
}


/* The icon lives in a 26px chip (.sidebar-menu-item-icon-wrapper, bg --ink-800
   with its own border), not directly in the row. On a filled cobalt row that
   chip stays dark, so a dark glyph inside it disappears. Clear the chip and let
   the glyph sit on the cobalt. */
body .card-sidebar .list-group-item:hover .sidebar-menu-item-icon-wrapper,
body .card-sidebar .list-group-item.active .sidebar-menu-item-icon-wrapper,
body .panel-sidebar .list-group-item:hover .sidebar-menu-item-icon-wrapper,
body .panel-sidebar .list-group-item.active .sidebar-menu-item-icon-wrapper {
    background: transparent;
    border-color: transparent;
}

body .card-sidebar .list-group-item:hover .sidebar-menu-item-icon,
body .card-sidebar .list-group-item.active .sidebar-menu-item-icon,
body .panel-sidebar .list-group-item:hover .sidebar-menu-item-icon,
body .panel-sidebar .list-group-item.active .sidebar-menu-item-icon {
    color: var(--ink-on-accent, #04202c);
}

/* A dark chip with dark ink on cobalt was muddy; invert it so the badge keeps
   the same figure/ground relationship as the row label. */
body .card-sidebar .list-group-item:hover .badge,
body .card-sidebar .list-group-item.active .badge,
body .panel-sidebar .list-group-item:hover .badge,
body .panel-sidebar .list-group-item.active .badge {
    background: rgba(255, 255, 255, .34);
    color: var(--ink-on-accent, #04202c);
}
