/* Poppins — must stay the FIRST rule in the file. CSS only
   permits @import before other rules (comments excepted).

   This is kept as a FAIL-SAFE. nexus-lx/includes/head.tpl also
   requests Poppins via <link>, which is faster (parallel, with
   preconnect) — but .tpl overrides need the WHMCS template
   cache cleared before they take effect, whereas this file
   deploys immediately. Verified on the live site: custom.css
   updates land at once, head.tpl did not.

   Browsers dedupe identical URLs, so having both costs nothing
   — one request either way. Once head.tpl is confirmed live,
   this line can be deleted for a marginally faster first paint.

   >>> After editing this file, bump lxAssetVersion in
   >>> nexus-lx/includes/head.tpl or browsers will keep serving
   >>> a cached copy for up to 7 days. See that file for why. */
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap');

/* *****************************************************

    ** nexus-lx — hostLX Client Area Theme **

    Child theme of: nexus
    Brand source:   https://hostlx.com (css/custom.css, css/main.min.css)

    ---------------------------------------------------
    IMPORTANT — DO NOT DELETE THE :root BLOCK BELOW
    ---------------------------------------------------
    The Nexus parent theme is entirely token-driven:
    nexus/css/theme.css contains 392 var(--...) references
    and NONE of those tokens are defined in theme.css,
    all.css or the sass partials — they live only in
    nexus/css/custom.css.

    WHMCS resolves custom.css child-first. This file
    therefore REPLACES the parent's token block rather
    than adding to it. If any token below is removed,
    every rule referencing it silently fails (transparent
    backgrounds, collapsed radii, invisible borders).

    All 82 tokens from the parent are reproduced here.

***************************************************** */

:root {
    --white: #fff;

    /* ---------------------------------------------------
       Neutral shades — hostLX slate-blue ramp
       Replaces Nexus's pure-gray ramp. Values marked (site)
       are taken verbatim from hostlx.com; the rest are
       interpolated to complete the scale.
       --------------------------------------------------- */
    --neutral-50: #f8f9fb;
    --neutral-100: #f0f2f5;  /* (site) section backgrounds */
    --neutral-200: #e6e9ee;  /* (site) borders — most-used color on hostlx.com */
    --neutral-300: #d3d9e2;
    --neutral-400: #a0abbc;  /* (site) muted text */
    --neutral-500: #667791;  /* (site) */
    --neutral-600: #4a5669;  /* (site) body text */
    --neutral-700: #3a4659;  /* (site) */
    --neutral-800: #2c3645;  /* (site) */
    --neutral-900: #1e2632;
    --neutral-950: #12171f;

    /* ---------------------------------------------------
       Primary ramp — hostLX navy
       Brand primary is #15417a (site): links, headings,
       header bg, footer bg, primary buttons, colored rows.
       --------------------------------------------------- */
    --primary-50: #eaf0f8;
    --primary-100: #d5e0ef;
    --primary-200: #adc2dc;
    --primary-300: #6589b8;  /* (site) */
    --primary-400: #446795;  /* (site) */
    --primary-500: #2a5c9c;  /* (site) */
    --primary-600: #15417a;  /* (site) BRAND PRIMARY */
    --primary-700: #123769;  /* (site) notification bg */
    --primary-800: #0e2c55;
    --primary-900: #0a2140;
    --primary-950: #06152a;

    /* Primary colors
       Nexus ships these mapped to the neutral ramp (gray).
       Remapped to the navy ramp so the client area picks up
       the hostLX brand color the way the main site does. */
    --primary: var(--primary-600);
    --primary-lifted: var(--primary-700);
    --primary-accented: var(--primary-800);

    /* Secondary colors — slate, NOT the hostLX gold.
       Careful: despite the name, --secondary has exactly one
       consumer in Nexus — .status-cancelled (theme.css:10528).
       It is a status gray, not the main site's "secondary
       button" color. Setting it to gold makes the Cancelled
       badge bright gold with white text (1.5:1, illegible).
       The hostLX gold lives in --brand-gold / --yellow-300. */
    --secondary: var(--neutral-500);
    --secondary-lifted: var(--neutral-600);
    --secondary-accented: var(--neutral-700);

    /* hostLX gold #ffcc33 (site) — the main site's secondary
       button color. Not consumed by any parent rule; kept here
       for component overrides (gold CTAs) in a later pass. */
    --brand-gold: #ffcc33;
    --brand-gold-lifted: #f0b81a;
    --brand-gold-accented: #d19d00;

    /* Success colors — base #00b75a (site) */
    --success: #00b75a;
    --success-lifted: #009548;
    --success-accented: #007a3b;

    /* Info colors — base #0098ef (the Nexus/site template blue),
       accented #00629a (site notification default) */
    --info: #0098ef;
    --info-lifted: #0079c0;
    --info-accented: #00629a;

    /* Notice colors
       hostLX has no purple in its palette, but Nexus needs a
       distinct hue for status badges (.status-answered) and
       card accents. Muted indigo, harmonized to the navy. */
    --notice: #5b5bd6;
    --notice-lifted: #4a4ac0;
    --notice-accented: #3b3b9e;

    /* Warning colors — amber, sits between the site's
       gold (#ffcc33) and its error red (#cd3100) */
    --warning: #f5a300;
    --warning-lifted: #d18a00;
    --warning-accented: #a86f00;

    /* Error colors — base #cd3100 (site) */
    --error: #cd3100;
    --error-lifted: #a82800;
    --error-accented: #8a2100;

    /* Grayscale colors */
    --grayscale: var(--neutral-900);
    --grayscale-lifted: var(--neutral-800);
    --grayscale-accented: var(--neutral-700);

    /* Neutral colors */
    --neutral: var(--neutral-500);
    --neutral-lifted: var(--neutral-600);
    --neutral-accented: var(--neutral-700);

    /* Text neutral colors
       --text is #4a5669 to match the main site's body color
       exactly (hostlx.com sets body { color: #4a5669 }). */
    --text-inverted: var(--white);
    --text-muted: var(--neutral-400);
    --text-lifted: var(--neutral-500);
    --text-accented: var(--neutral-600);
    --text: var(--neutral-600);

    /* Border neutral colors
       --border-muted is #e6e9ee, the main site's border color. */
    --border-muted: var(--neutral-200);
    --border: var(--neutral-300);
    --border-lifted: var(--neutral-400);
    --border-accented: var(--neutral-600);

    /* Background neutral colors */
    --bg: var(--white);
    --bg-muted: var(--neutral-50);
    --bg-lifted: var(--neutral-100);
    --bg-accented: var(--neutral-200);
    --bg-inverted: var(--primary-600);

    /* Additional colors
       Retuned from Nexus's neon defaults to sit alongside the
       navy/slate scheme. Used by .card-accent-* and status badges. */
    --yellow-200: #ffe08a;
    --yellow-300: #ffcc33;
    --teal-300: #4fd1c5;
    --teal-400: #26b3a6;
    --emerald-300: #4fd48a;
    --pink-400: #e86a9e;

    /* Additional custom properties */
    /* Font sizes — unchanged from Nexus. These are UI text
       sizes; the main site's 16px applies to body copy, set
       in the typography section below. */
    --text-xs: 0.625rem;
    --text-sm: 0.75rem;
    --text-md: 0.875rem;
    --text-lg: 1rem;

    /* Spacing */
    --outline-sm: 1px;
    --outline-md: 2px;
    --outline-lg: 3px;

    /* Rounding — matched to hostlx.com
       Site uses 4px (small), 6px (buttons/inputs), 12px (cards). */
    --rounding-sm: 0.25rem;   /* 4px  */
    --rounding-md: 0.375rem;  /* 6px  — was 0.5rem in Nexus */
    --rounding-lg: 0.75rem;   /* 12px */

    /* Other */
    --letter-spacing: 0em;
    --disabled-opacity: 25%;

    /* ===================================================
       ADDITIONS BEYOND THE PARENT'S TOKEN SET
       Everything above mirrors nexus/css/custom.css. The
       tokens below are new — the parent has no spacing scale
       and no focus-ring definition, which is why spacing in
       Nexus is ad hoc (every component invents its own
       numbers) and why focus states fall back to Bootstrap
       blue.
       =================================================== */

    /* Spacing scale — 4px base. Nexus has no spacing tokens at
       all; component padding is hardcoded per-rule, which is
       the root of the inconsistent rhythm across pages. */
    --space-1: 0.25rem;   /* 4px  */
    --space-2: 0.5rem;    /* 8px  */
    --space-3: 0.75rem;   /* 12px */
    --space-4: 1rem;      /* 16px */
    --space-5: 1.5rem;    /* 24px */
    --space-6: 2rem;      /* 32px */
    --space-7: 3rem;      /* 48px */

    /* Brand primary as raw channels, so rgba() rings can be
       built from it. CSS cannot extract components from a hex
       token, so this has to be maintained alongside
       --primary-600 (#15417a). */
    --primary-rgb: 21, 65, 122;

    /* Focus ring — one definition for every interactive
       element. theme.css:2270 etc. uses Bootstrap's
       rgba(0,123,255,.25) blue in ~34 places. */
    --focus-ring: 0 0 0 3px rgba(var(--primary-rgb), 0.15);
    --focus-ring-strong: 0 0 0 3px rgba(var(--primary-rgb), 0.28);

    /* Elevation — matched to hostlx.com's
       box-shadow: 0 15px 30px rgba(74,86,105,0.1) */
    --shadow-sm: 0 1px 2px rgba(74, 86, 105, 0.06);
    --shadow-md: 0 1px 2px rgba(74, 86, 105, 0.04), 0 8px 16px rgba(74, 86, 105, 0.06);
    --shadow-lg: 0 1px 2px rgba(74, 86, 105, 0.04), 0 15px 30px rgba(74, 86, 105, 0.1);

    /* Minimum comfortable tap target (WCAG 2.5.8 asks 24px,
       platform guidance asks 44px) */
    --tap-min: 44px;
}

/* *****************************************************
    Typography — Poppins

    Nexus sets Open Sans on body at theme.css:9199 (which
    already overrides the Bootstrap system stack at
    theme.css:64). Both are replaced here.

    Three other selectors hardcode their own stack and would
    otherwise stay on the old font:
      theme.css:5368  .tooltip
      theme.css:5470  .popover
      theme.css:11304 .popover-user-notifications

    Form controls need no help — theme.css:247 already sets
    font-family: inherit on input/button/select/textarea.
    Monospace and Font Awesome stacks are left alone.

    Poppins is geometric and noticeably WIDER than Open Sans
    at the same px size, with taller ascenders. Two knock-on
    adjustments: slightly negative tracking on headings so
    they do not sprawl, and more body leading (1.6 vs
    Bootstrap's 1.5) because the tall ascenders make tight
    lines feel cramped.
***************************************************** */

body,
.tooltip,
.popover,
.popover-user-notifications {
    font-family: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}

body {
    color: var(--text);
    line-height: 1.6;
}

/* *****************************************************
    Type scale

    theme.css:362-392 is Bootstrap 4's raw scale — h1 2.5rem
    (40px), h2 2rem, h3 1.75rem — applied with NO responsive
    step-down, so a phone renders headings at full desktop
    size. That is why the store headline swallows the viewport
    while its subtitle stays tiny: the jump between them is
    ~27px with nothing in between.

    Rebuilt as a scale that actually steps down, and pulled in
    a little overall since Poppins reads larger than the
    Open Sans these numbers were chosen for.

    Weight moves 500 -> 600: Bootstrap's 500 is too light for
    Poppins, whose geometric forms need more stroke to hold as
    headings.

    Note: the --text-xs/sm/md/lg tokens are NOT used here, and
    are not used anywhere in the parent theme either (zero
    references across theme.css, store.css and invoice.css).
    They are dead in Nexus. They stay defined above only so
    the child keeps full parity with the parent's contract —
    editing them changes nothing on screen.
***************************************************** */

h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
    font-weight: 600;
    line-height: 1.25;
    letter-spacing: -0.015em;
}

h1, .h1 { font-size: 2.25rem; }   /* 36px, was 40px */
h2, .h2 { font-size: 1.875rem; }  /* 30px, was 32px */
h3, .h3 { font-size: 1.5rem; }    /* 24px, was 28px */
h4, .h4 { font-size: 1.25rem; }   /* 20px, was 24px */
h5, .h5 { font-size: 1.125rem; }  /* 18px, was 20px */
h6, .h6 { font-size: 1rem; }      /* 16px, unchanged */

/* Phones: Bootstrap applies no reduction at all, so a 40px h1
   sat on a 390px screen. */
@media (max-width: 767.98px) {
    h1, .h1 { font-size: 1.75rem; }     /* 28px */
    h2, .h2 { font-size: 1.5rem; }      /* 24px */
    h3, .h3 { font-size: 1.25rem; }     /* 20px */
    h4, .h4 { font-size: 1.125rem; }    /* 18px */
    h5, .h5 { font-size: 1rem; }        /* 16px */
    h6, .h6 { font-size: 0.9375rem; }   /* 15px */
}

.card-title {
    letter-spacing: -0.015em;
}

/* *****************************************************
    FIX 1 — Footer copyright contrast

    theme.css:9851 sets .copyright to var(--text-lifted)
    (#667791) on the footer's var(--bg-inverted). With the
    navy footer that is 2.2:1 — fails WCAG AA (needs 4.5:1).

    Note: stock Nexus had --bg-inverted as near-black
    (#111827), giving ~4.0:1 — still failing, but less
    visibly. Pointing --bg-inverted at the brand navy to
    match hostlx.com's footer surfaced it.

    --neutral-300 on #15417a = 7.1:1
***************************************************** */

footer.footer .copyright {
    color: var(--neutral-300);
}

/* *****************************************************
    FIX 1b — Footer social icons were invisible

    Two overlapping causes:

    1. .btn hardcodes `color: #212529` (Bootstrap base).
       footer.footer sets `color: #fff`, but that is
       INHERITED styling and loses to .btn's own
       declaration. Result: near-black icons on the navy
       footer at 1.5:1.

       Proof: the language button in the same row IS
       legible because it carries .btn-outline-light
       (color: #f8f9fa). The social icons use a bare .btn
       (includes/social-accounts.tpl:3), so nothing ever
       lightens them.

    2. theme.css:9837 sets footer .btn border-color to
       var(--border-accented) (#4a5669) — 1.4:1 on navy,
       so the boxes read as barely-there smudges. At
       specificity 0,2,1 it also beats .btn-outline-light's
       light border, so the language button is affected too.

    White on navy = 10.1:1. Border at 50% white blends to
    #8aa0bd = 3.8:1, clearing the 3:1 bar for non-text UI.

    .btn-icon has no base definition anywhere in the theme
    (only footer.footer .btn-icon exists), so the glyph is
    also flex-centered here rather than baseline-aligned in
    its 1.75rem box.
***************************************************** */

footer.footer .btn {
    border-color: rgba(255, 255, 255, 0.5);
}

/* *****************************************************
    FIX 1f — "Contact UsTerms of Service" ran together

    theme.css:9829-9833 zeroes the footer link padding below
    1200px:

      @media (max-width: 1199.98px) {
        footer.footer .nav-link { padding: 0 }
      }

    Bootstrap's .nav-link normally supplies 0.5rem 1rem, and
    that is the ONLY thing separating the two footer links
    (footer.tpl:34-45 has no margins or separators). Zeroing it
    butts the labels directly against each other.

    Restored with enough vertical padding to make them real tap
    targets too, since this only applies on small screens.
***************************************************** */

@media (max-width: 1199.98px) {
    footer.footer .nav-link {
        padding: 0.35rem 0.75rem;
    }
}

footer.footer .btn-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    border-radius: var(--rounding-sm);
}

footer.footer .btn-icon:hover,
footer.footer .btn-icon:focus {
    color: var(--primary);
    background-color: #fff;
    border-color: #fff;
}

/* *****************************************************
    FIX 1c — Logo row was cramped against the topbar

    theme.css:9741 zeroes the navbar padding and :9762
    zeroes .navbar-brand's padding/margin, so the ONLY
    breathing room above the logo is mt-2 (8px) from
    header.tpl:81. With a 60px logo that reads as squeezed
    against the navy topbar.

    hostlx.com uses #header { height: 60px; padding: 30px 0 }
    — 30px above and below. Matched here.

    The mt-2/mb-2 utilities are neutralized because
    Bootstrap's spacing utilities ship with !important, so
    they cannot be overridden any other way short of
    copying header.tpl into the child. Spacing then lives
    in one place (the padding below) instead of being split
    between markup and CSS.

    Only the logo row is targeted: it is .navbar.navbar-light
    (header.tpl:80), whereas the menu row below is
    .navbar-expand-xl.main-navbar-wrapper (header.tpl:117).
***************************************************** */

header.header .navbar.navbar-light > .container {
    margin-top: 0 !important;
    margin-bottom: 0 !important;
}

header.header .navbar.navbar-light {
    padding-top: 30px;
    padding-bottom: 20px;
}

/* hostlx.com drops to body{padding-top:80px} on small
   screens, so the header tightens up there too. */
@media (max-width: 767.98px) {
    header.header .navbar.navbar-light {
        padding-top: 16px;
        padding-bottom: 12px;
    }
}

/* *****************************************************
    FIX 1d — Mobile: logo, cart and menu on one line

    theme.css:9683 allows .logo-img up to 400px wide. On a
    ~390px viewport the logo eats the full container, so the
    .toolbar (cart + hamburger, header.tpl:101-114) wraps to
    a second row. theme.css:9744 then centers that orphaned
    row via `justify-content: center` under 576px, which is
    why the two buttons sit centered under the logo.

    Fixed by capping logo height on smaller screens and
    forbidding the row from wrapping.

    The .navbar-light selector keeps this on the logo row
    only. Specificity 0,3,1 beats theme.css:9744's 0,2,1,
    so the centering rule is overridden regardless of order.
***************************************************** */

@media (max-width: 1199.98px) {
    header.header .navbar.navbar-light > .container {
        flex-wrap: nowrap;
        justify-content: space-between;
        align-items: center;
        gap: 12px;
    }

    header.header .navbar-brand {
        flex: 0 1 auto;
        min-width: 0;
    }

    header.header .logo-img {
        max-height: 42px;
        max-width: 100%;
    }

    header.header .toolbar {
        flex: 0 0 auto;
        flex-wrap: nowrap;
    }
}

/* *****************************************************
    FIX 1e — Mobile menu had 40px gaps between every item

    theme.css:9646 sets #nav { gap: 40px }. On desktop
    .navbar-nav is flex-direction: row, so that is HORIZONTAL
    spacing between top-level menu items — correct.

    When the navbar collapses, Bootstrap switches the list to
    flex-direction: column and the same 40px becomes VERTICAL
    space between every item. The mobile menu balloons to
    several screens tall.

    Made worse by markup: the <a> in includes/navbar.tpl:3
    carries no .nav-link class (only `dropdown-toggle`, or no
    class at all for leaf items), so the links get zero
    padding from Bootstrap. The result is small tap targets
    separated by large voids.

    So: collapse the gap, then give the links real padding —
    ~44px tap targets with a divider for structure.

    #nav is an ID (specificity 1,0,0), so it has to be named
    explicitly; a class-only selector cannot beat it.
***************************************************** */

@media (max-width: 1199.98px) {
    /* Menu items sat flush against the viewport edge because
       Bootstrap zeroes the container padding below the expand
       breakpoint (theme.css:3966-3976):

         @media (max-width: 1199.98px) {
           .navbar-expand-xl > .container { padding: 0 }
         }

       That is deliberate in Bootstrap — it lets a collapsed
       menu run edge to edge on the assumption the theme pads
       the items itself. Nexus never does, so nav text, the
       dividers and the search box all ran into the screen
       edge.

       Restoring the 15px here (rather than padding each link)
       realigns the menu with the breadcrumb and cards, and
       fixes the search box in the same stroke. */
    header.header .main-navbar-wrapper > .container {
        padding-right: 15px;
        padding-left: 15px;
    }

    header.header .main-navbar-wrapper #nav,
    header.header .main-navbar-wrapper .navbar-nav {
        gap: 0;
    }

    /* Horizontal padding now comes from the container, so links
       align exactly with the page grid */
    header.header .main-navbar-wrapper .navbar-nav > li > a {
        display: block;
        padding: 11px 0;
        border-bottom: 1px solid var(--border-muted);
    }

    /* Last item in each list needs no trailing rule */
    header.header .main-navbar-wrapper .navbar-nav > li:last-child > a {
        border-bottom: 0;
    }

    /* Submenus: theme.css:3801 already makes them static when
       collapsed, but they arrive unindented and on a white
       card, so they read as top-level items. Indent + tint to
       show hierarchy. */
    header.header .main-navbar-wrapper .dropdown-menu {
        margin: 0 0 4px;
        padding: 4px 0;
        border: 0;
        border-left: 2px solid var(--border-muted);
        border-radius: 0;
        margin-left: 8px;
        background-color: var(--bg-muted);
        box-shadow: none;
    }

    /* navbar.tpl:14-15 puts .dropdown-item on BOTH the <li>
       and the <a>, so Bootstrap's 1.5rem side padding applies
       twice (3rem total indent). Neutralize the outer one. */
    header.header .main-navbar-wrapper .dropdown-menu > li.dropdown-item {
        padding: 0;
    }

    header.header .main-navbar-wrapper .dropdown-menu a.dropdown-item {
        padding: 9px 12px !important;
        white-space: normal;
    }
}

/* *****************************************************
    FIX 2 — Badge text contrast

    theme.css:9521 hardcodes .label { color: #fff }, but
    several badge backgrounds are far too light for white
    text. Measured against white:

      --yellow-300 #ffcc33  1.5:1  (Suspended, Refunded)
      --warning    #f5a300  2.1:1  (Pending, In Progress)
      --success    #00b75a  2.7:1  (Active, Open, Paid)
      --info       #0098ef  3.1:1  (On Hold)

    All four fail. Rather than dull the brand colors, the
    foreground is flipped to dark on those backgrounds —
    every combination below clears AA:

      dark on --yellow-300  10.1:1
      dark on --warning      7.3:1
      dark on --success      5.8:1
      dark on --info         4.9:1

    Backgrounds where white already passes are left alone:
    --error 5.2:1, --notice 5.4:1, --neutral 4.6:1,
    --primary 10.1:1.

    This is a pre-existing Nexus bug, not a brand issue —
    stock #ffdf20 on white text was 1.45:1.
***************************************************** */

.label-warning,
.status-suspended,
.status-pending-transfer,
.status-refunded,
.requestor-type-registereduser,
.status-pending,
.status-customer-reply,
.status-pending-registration,
.status-redemption,
.status-grace,
.status-inprogress,
.status-active,
.status-open,
.status-completed,
.status-paid,
.status-accepted,
.status-onhold,
.label-success,
.label-info {
    color: var(--neutral-900);
}

/* *****************************************************
    FIX 2a — Container-less pages ran edge to edge

    header.tpl:159 renders:

      <div class="{if !$skipMainBodyContainer}container{/if}">

    WHMCS core sets $skipMainBodyContainer on cart and order
    pages, so those render a bare <div class=""> with no
    container and therefore no 15px gutter. Headings, panels
    and product cards all touch the viewport edge.

    The intent upstream is that such pages supply their own
    .container (as store/order.tpl:1 does). Order form
    templates frequently do not, which is the broken case.

    :has() lets this pad ONLY when the page has not already
    provided its own container, so templates that do the right
    thing are left untouched rather than double-padded.
***************************************************** */

section#main-body > div:not(.container):not(:has(> .container)) {
    padding-left: 15px;
    padding-right: 15px;
}

/* *****************************************************
    FIX 2b — Service status badges: clipped text + white-on-gold

    Two separate defects on the "Your Active Products/Services"
    list (includes/active-products-services-item.tpl:6, which
    renders <span class="label label-{modifier}">).

    (a) theme.css:11089
          .div-service-status .label:not(.label-placeholder)
            { width: 3rem }
        A hard 48px cap, combined with overflow:hidden and
        text-overflow:ellipsis on the same element, is why
        "Suspended" renders as "Susp...". theme.css:11125
        releases it with `width: initial !important` — but only
        at min-width 768px, so mobile stays clamped.

        The .label-placeholder sibling exists specifically to
        reserve the width of the longest status string, so
        sizing to content is what the markup already intends.

    (b) theme.css:11080
          .div-service-status .label { color: white }
        At specificity 0,2,0 this beat the 0,1,0 .label-success
        / .label-warning rules in FIX 2 above, so Active and
        Suspended kept their unreadable white text. Re-applied
        here at matching specificity.

    Contrast recap: dark on --success 5.8:1, on --yellow-300
    10.1:1. White was 2.7:1 and 1.5:1.
***************************************************** */

.div-service-status .label:not(.label-placeholder) {
    width: auto;
    max-width: 100%;
}

.div-service-status .label-success,
.div-service-status .label-warning,
.div-service-status .label-info {
    color: var(--neutral-900);
}

/* *****************************************************
    FIX 2c — Dead 70px band under the logo

    theme.css:9653 sets `header.header .navbar { min-height: 70px }`.
    Both header rows carry the .navbar class — the logo row
    (header.tpl:80) and the menu row (header.tpl:117) — so the
    menu row reserves 70px even when it has collapsed to
    nothing on mobile. That is the empty white gap under the
    logo, and it is at its worst on the login page, where
    there is no menu to show at all.

    min-height only matters for the logo row, which already
    exceeds it.
***************************************************** */

@media (max-width: 1199.98px) {
    header.header .navbar.main-navbar-wrapper {
        min-height: 0;
    }

    /* An empty collapse still contributes its own box */
    header.header .main-navbar-wrapper .navbar-collapse:not(.show):empty {
        display: none;
    }

    header.header .main-navbar-wrapper .navbar-nav {
        margin-top: 0;
        margin-bottom: 8px;
    }
}

/* *****************************************************
    FIX 2d — Empty card footers padding out every panel

    clientareahome.tpl:116-120 renders .card-footer
    unconditionally — the {if $item->hasFooterHtml()} sits
    INSIDE the div rather than around it. Every panel without
    footer content therefore gets an empty footer carrying
    Bootstrap's `padding: 0.75rem 1.25rem` plus a tinted
    background, which is the dead space under Overdue
    Invoices, Recent Support Tickets and Register a New Domain.
    _client-home.scss:32 strips its border-top, so the strip is
    invisible but still occupies height.

    :empty alone will not match: Smarty leaves a whitespace
    text node inside the div. :not(:has(*)) catches the
    whitespace-only case by testing for element children.

    Caveat: a footer holding ONLY bare text with no element
    wrapper would also be hidden. Every footer this theme
    produces wraps its content in <a>/<button>, so nothing
    real is affected — but keep it in mind if you add footer
    HTML later.
***************************************************** */

.client-home-cards .card-footer:empty,
.client-home-cards .card-footer:not(:has(*)) {
    display: none;
}

/* *****************************************************
    FIX 3 — Client-area stat tiles

    theme.css:10983-11024 hardcodes five grays (#f8f8f8,
    #ccc, #888, #f2f2f2, #aaa) and never touches the token
    system. They are neutral warm grays, so against the
    slate-blue palette the tiles read as washed-out gray
    islands. Remapped onto tokens.

    .title moved to --text-accented rather than
    --text-lifted: at 12px bold uppercase, --text-lifted
    on --bg-muted is only 4.32:1. --text-accented is 7.1:1.
***************************************************** */

.tiles .tile {
    background-color: var(--bg-muted);
    border-right-color: var(--border-muted);
}

.tiles .tile .stat {
    color: var(--primary);
}

.tiles .tile .title {
    color: var(--text-accented);
}

.tiles .tile i {
    color: var(--neutral-300);
}

.tiles .tile:hover {
    background-color: var(--bg-lifted);
}

.tiles .tile:hover i {
    color: var(--neutral-400);
}

/* *****************************************************
    FIX 4 — Knowledgebase search field

    theme.css:9720-9736 builds the field from a bordered
    wrapper with border:0 children, but leaves the parts
    mismatched: a 4px radius on the wrapper while the inner
    .btn keeps Bootstrap's own 0.25rem corners, a #a5a5a5
    hardcoded icon, and a focus state that only shifts the
    border to another gray — no brand feedback at all.

    Rebuilt to match hostlx.com's inputs: 6px radius
    (--rounding-md), brand navy focus ring, and a search
    icon that picks up the palette instead of a stray gray.
***************************************************** */

header.header .search {
    border-radius: var(--rounding-md);
    background-color: var(--bg);
    overflow: hidden;
    transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}

header.header .search .form-control {
    height: auto;
    padding: 0.5rem 0.75rem 0.5rem 0;
    font-size: 0.9rem;
    color: var(--text);
    background-color: transparent;
    box-shadow: none;
}

header.header .search .form-control::placeholder {
    color: var(--text-muted);
}

header.header .search .btn,
header.header .search .input-group-prepend .btn {
    color: var(--text-lifted);
    border-radius: 0;
    padding-left: 0.75rem;
    padding-right: 0.5rem;
    box-shadow: none;
}

/* theme.css:9731 only swaps one gray for another on focus */
header.header .search:focus-within {
    border-color: var(--primary);
    box-shadow: 0 0 0 3px rgba(21, 65, 122, 0.12);
}

header.header .search:focus-within .btn {
    color: var(--primary);
}

/* Mobile: the in-menu copy (header.tpl:120-129) is full width
   via .w-100, so it only needs breathing room from the items
   below it. */
@media (max-width: 1199.98px) {
    header.header .main-navbar-wrapper .search {
        margin-bottom: 12px;
    }
}

/* *****************************************************
    FIX 5 — Login page

    Markup: login.tpl. Structural problems, not just polish:

    (a) login.tpl:42-52 floats the submit button left and puts
        Remember Me in a text-right block. Two different
        layout mechanisms for one row, with no clearfix — the
        control baselines do not line up, and the float is
        only contained because .card-body happens to have
        py-5. Replaced with flexbox so they align on a shared
        centre line.

    (b) The card sits flush on --bg-lifted with a hairline
        border and no elevation, so it reads as a flat patch
        rather than a focused task. hostlx.com uses 12px radii
        and soft shadows (0 15px 30px rgba(74,86,105,0.1)) —
        matched here via --rounding-lg.

    (c) Inputs give no brand focus feedback, same as the
        search field above.

    Scoped to .login-form so nothing here leaks into other
    forms that share .input-group-merge.
***************************************************** */

.login-form .card {
    border: 1px solid var(--border-muted);
    border-radius: var(--rounding-lg);
    box-shadow: 0 1px 2px rgba(74, 86, 105, 0.04),
                0 15px 30px rgba(74, 86, 105, 0.08);
}

.login-form .card-body {
    border-radius: var(--rounding-lg) var(--rounding-lg) 0 0;
}

.login-form .h3 {
    color: var(--primary);
    font-weight: 600;
}

.login-form .form-control-label {
    font-weight: 500;
    color: var(--text-accented);
    margin-bottom: 0.35rem;
}

.login-form .input-group {
    border: 1px solid var(--border);
    border-radius: var(--rounding-md);
    background-color: var(--bg);
    transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}

.login-form .input-group:focus-within {
    border-color: var(--primary);
    box-shadow: 0 0 0 3px rgba(21, 65, 122, 0.12);
}

.login-form .input-group-text,
.login-form .input-group .form-control,
.login-form .input-group .btn {
    border: 0;
    background-color: transparent;
    box-shadow: none;
}

.login-form .input-group-text {
    color: var(--text-lifted);
    padding-right: 0.5rem;
}

.login-form .input-group .form-control {
    padding-left: 0;
    color: var(--text);
}

.login-form .input-group .form-control::placeholder {
    color: var(--text-muted);
}

.login-form .btn-reveal-pw {
    color: var(--text-lifted);
}

/* (a) — Login button and Remember Me on ONE line.

   login.tpl:42-52 puts the button in a .float-left div and the
   checkbox in a separate .text-right div. The float made their
   baselines disagree, and my first attempt at this dropped the
   checkbox onto its own row — wrong: they belong side by side.

   Both wrappers are made inline-flex and middle-aligned, so
   they share a line and their contents centre against each
   other. The wrappers are targeted via .float-left/.text-right
   because login.tpl gives them no class to hook, and no
   wrapper can be added without forking the template. */
.login-form .card-body > .float-left {
    float: none !important;
    display: inline-flex;
    align-items: center;
    vertical-align: middle;
}

.login-form .card-body > .float-left + .text-right {
    display: inline-flex;
    align-items: center;
    vertical-align: middle;
    text-align: left !important;
    margin-top: 0;
    margin-left: 1rem;
}

.login-form #login {
    padding: 0.5rem 1.75rem;
    font-weight: 600;
    border-radius: var(--rounding-md);
}

.login-form .text-right label {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0;
    color: var(--text-accented);
    cursor: pointer;
}

.login-form .text-right .form-check-input {
    position: static;
    margin: 0;
}

.login-form .card-footer {
    border-radius: 0 0 var(--rounding-lg) var(--rounding-lg);
    background-color: var(--bg-muted);
    border-top: 1px solid var(--border-muted);
    text-align: center;
}

.login-form .card-footer a {
    color: var(--primary);
}

/* =====================================================
   =====================================================

   PART 2 — DESIGN SYSTEM PASS

   Everything above fixes specific reported defects. This
   part addresses the underlying cause of the "everything
   looks slightly off" quality:

   NEXUS IS ONLY HALF-TOKENIZED. It routes ~392 declarations
   through custom properties but leaves Bootstrap 4's entire
   base layer on hardcoded values:

     #6c757d  x37   Bootstrap gray-600
     #007bff  x34   Bootstrap blue (incl. every focus ring)
     #212529  x32   Bootstrap gray-900
     #dee2e6  x27   table + component borders
     #f8f9fa  x19
     #495057  x14   input text
     #e9ecef  x14
     #ced4da  x5    input borders

   Bootstrap's palette is a COOL NEUTRAL gray. The hostLX
   palette is a SLATE BLUE. Both are present on every page,
   a few degrees of hue apart — close enough to read as a
   mistake rather than a choice. No single element looks
   broken, which is exactly why it is hard to point at.

   This part maps that base layer onto the tokens, then
   applies a consistent spacing rhythm and focus treatment.

   =====================================================
   ===================================================== */

/* -----------------------------------------------------
   A. Links

   theme.css:9229 sets `a { color: var(--text) }`, so content
   links render in the same colour as body text with no
   underline — no affordance that they are clickable at all.
   hostlx.com uses #15417a for links.

   Scoped to prose contexts. A blanket `a` rule would also
   repaint nav items, list-group rows and card headers, which
   are anchors too and should stay inheriting.
   ----------------------------------------------------- */

.primary-content p a:not(.btn),
.primary-content li a:not(.btn):not(.list-group-item):not(.dropdown-item):not(.nav-link),
.primary-content td a:not(.btn):not(.dropdown-item),
.alert a:not(.btn),
.markdown-content a:not(.btn),
.md-preview a:not(.btn) {
    color: var(--primary);
    text-decoration: underline;
    text-underline-offset: 0.15em;
    text-decoration-thickness: 1px;
}

.primary-content p a:not(.btn):hover,
.primary-content li a:not(.btn):not(.list-group-item):not(.dropdown-item):not(.nav-link):hover,
.primary-content td a:not(.btn):not(.dropdown-item):hover,
.alert a:not(.btn):hover,
.markdown-content a:not(.btn):hover,
.md-preview a:not(.btn):hover {
    color: var(--primary-lifted);
    text-decoration-thickness: 2px;
}

/* -----------------------------------------------------
   B. Focus states

   Bootstrap's rgba(0,123,255,.25) blue ring appears in ~34
   places, including .form-control:focus (border #80bdff) and
   every .btn-*:focus. On a navy-and-slate theme a cyan-blue
   halo is the single most visible off-brand detail, and it
   shows on literally every interaction.

   One ring, brand-coloured, everywhere.
   ----------------------------------------------------- */

.form-control:focus,
.custom-select:focus,
.custom-file-input:focus ~ .custom-file-label,
.input-group.focus,
.form-control.focus {
    border-color: var(--primary);
    box-shadow: var(--focus-ring);
}

.btn:focus,
.btn.focus,
.btn-primary:focus,
.btn-primary.focus,
.btn-secondary:focus,
.btn-secondary.focus,
.btn-default:focus,
.btn-default.focus,
.btn-danger:focus,
.btn-danger.focus,
.btn-success:focus,
.btn-success.focus,
.btn-info:focus,
.btn-info.focus,
.btn-warning:focus,
.btn-warning.focus,
.btn-light:focus,
.btn-outline-light:focus,
.page-link:focus,
.custom-control-input:focus ~ .custom-control-label::before {
    box-shadow: var(--focus-ring-strong);
}

/* Keyboard users get a visible ring; mouse users do not get a
   lingering one. :focus-visible is well supported now, and the
   :focus rules above remain as the fallback. */
a:focus-visible,
button:focus-visible,
.btn:focus-visible,
[tabindex]:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
}

/* Checkbox / radio accent — Bootstrap paints these blue */
.custom-control-input:checked ~ .custom-control-label::before {
    border-color: var(--primary);
    background-color: var(--primary);
}

input[type="checkbox"],
input[type="radio"] {
    accent-color: var(--primary);
}

/* -----------------------------------------------------
   C. Buttons

   Three defects in the parent, not just polish:

   1. theme.css:10182 gives .btn-primary a navy fill
      (var(--bg-inverted)) but a var(--grayscale) border —
      near-black #1e2632 against navy #15417a. Visible as a
      muddy dark edge on every primary button.

   2. theme.css:10197 sends :hover/:focus/:active to
      var(--grayscale-lifted) — #2c3645 dark SLATE. Hovering
      a navy button turns it grey rather than deeper navy.

   3. theme.css:10211 sets `.btn-link:hover { color: #fff }`
      (twice — once via --text-inverted, once literal). On a
      light page that is white-on-white: the label vanishes
      on hover.

   Also: .btn keeps Bootstrap's hardcoded 0.25rem radius while
   .btn-sm uses 0.2rem and .btn-lg 0.3rem — three different
   corner radii across one button family. Unified on tokens.
   ----------------------------------------------------- */

.btn {
    border-radius: var(--rounding-md);
    font-weight: 500;
    transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out,
                border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}

.btn-sm,
.btn-group-sm > .btn {
    border-radius: var(--rounding-sm);
    padding: 0.3rem 0.65rem;
    font-size: 0.8125rem;
}

.btn-lg,
.btn-group-lg > .btn {
    border-radius: var(--rounding-md);
    padding: 0.625rem 1.25rem;
    font-size: 1.0625rem;
}

/* (1) border now matches the fill */
.btn-primary {
    background: var(--primary);
    border-color: var(--primary);
    color: var(--text-inverted);
}

/* (2) hover deepens the navy instead of going grey */
.btn-primary:hover,
.btn-primary:focus,
.btn-primary:active,
.btn-primary:not(:disabled):not(.disabled):active {
    background: var(--primary-lifted);
    border-color: var(--primary-lifted);
    color: var(--text-inverted);
}

.btn-primary:not(:disabled):not(.disabled):active {
    box-shadow: var(--focus-ring-strong);
}

/* (3) .btn-link stays legible on hover */
.btn-link {
    color: var(--primary);
    font-weight: 500;
}

.btn-link:hover,
.btn-link:focus {
    color: var(--primary-lifted);
    text-decoration: underline;
}

/* .btn-default was #333 on #fff with a #ccc border — three
   off-palette greys in one component */
.btn-default {
    color: var(--text-accented);
    background-color: var(--bg);
    border-color: var(--border);
}

.btn-default:hover,
.btn-default:focus {
    color: var(--text);
    background-color: var(--bg-lifted);
    border-color: var(--border-lifted);
}

/* Touch targets. Bootstrap's .btn is ~38px tall; platform
   guidance asks 44px. Applied only where fingers are the
   input, and only to full buttons — .btn-sm inside table rows
   and card headers would break those layouts. */
@media (max-width: 991.98px) and (pointer: coarse) {
    .btn:not(.btn-sm):not(.btn-xs):not(.close):not(.page-link):not(.g_id_signin) {
        min-height: var(--tap-min);
        padding-top: 0.5rem;
        padding-bottom: 0.5rem;
    }
}

/* Google Sign-In wrapper.

   login.tpl renders <div class="g_id_signin btn btn-social
   btn-google"> as an EMPTY div; Google's GSI library injects
   its own fully-styled button (an iframe) into it. So the
   Bootstrap classes on the wrapper frame Google's button
   inside a second button — border, radius and padding around
   a control that already has all three.

   Worse, .btn-social adds `overflow: hidden` (on top of
   .btn's own), which can clip the injected widget.

   .btn-google has no rules anywhere, so there is nothing to
   preserve. The wrapper is stripped back to a centring box
   and Google's widget is left to render itself. Excluded from
   the touch-target rule above for the same reason. */

.g_id_signin.btn {
    display: flex;
    justify-content: center;
    padding: 0;
    border: 0;
    background: transparent;
    border-radius: 0;
    overflow: visible;
    min-height: 0;
    text-align: center;
    white-space: normal;
}

.g_id_signin.btn:focus,
.g_id_signin.btn:hover {
    box-shadow: none;
    background: transparent;
    border: 0;
}

/* -----------------------------------------------------
   D. Form controls

   .form-control and .custom-select carry Bootstrap's
   #ced4da border, #495057 text and 0.25rem radius — none of
   which come from the palette. The custom-select arrow is an
   inline SVG hardcoded to #343a40.

   Height moves from Bootstrap's calc(1.5em + 0.75rem + 2px)
   (~38px) to 42px: Poppins sits taller in its line box, and
   38px made inputs look pinched next to the type.
   ----------------------------------------------------- */

.form-control,
.custom-select {
    border-color: var(--border);
    border-radius: var(--rounding-md);
    color: var(--text);
    height: calc(1.5em + 0.9rem + 2px);
    padding: 0.45rem 0.75rem;
    font-size: 0.9375rem;
}

.form-control::placeholder {
    color: var(--text-muted);
    opacity: 1;
}

.form-control:disabled,
.form-control[readonly],
.custom-select:disabled {
    background-color: var(--bg-lifted);
    color: var(--text-lifted);
}

/* Arrow recoloured from #343a40 to the palette's --text-lifted
   (#667791). The whole SVG has to be restated — a data URI
   cannot reference a custom property. */
.custom-select {
    background: var(--bg) url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23667791' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right 0.75rem center/8px 10px;
    padding-right: 1.75rem;
}

.input-group-text {
    border-color: var(--border);
    background-color: var(--bg-lifted);
    color: var(--text-lifted);
    border-radius: var(--rounding-md);
}

label,
.form-control-label {
    font-weight: 500;
    color: var(--text-accented);
    margin-bottom: var(--space-1);
}

.form-group {
    margin-bottom: var(--space-4);
}

/* Validation feedback should read as text, not decoration */
.invalid-feedback,
.valid-feedback,
.warning-feedback {
    font-size: 0.8125rem;
    margin-top: var(--space-1);
}

.form-control.is-invalid,
.was-validated .form-control:invalid {
    border-color: var(--error);
}

.form-control.is-invalid:focus,
.was-validated .form-control:invalid:focus {
    border-color: var(--error);
    box-shadow: 0 0 0 3px rgba(205, 49, 0, 0.15);
}

/* iOS zooms the page when a focused input is under 16px.
   0.9375rem (15px) above would trigger it, so inputs go to
   16px on touch devices. */
@media (max-width: 767.98px) {
    .form-control,
    .custom-select,
    textarea.form-control {
        font-size: 1rem;
        height: calc(1.5em + 1rem + 2px);
    }
}

/* -----------------------------------------------------
   E. Cards, list groups, sidebar

   .card-header uses rgba(0,0,0,.03) on rgba(0,0,0,.125), and
   .list-group-item borders the same way. Translucent black
   over a slate background yields a muddy warm-grey rather
   than the palette's cool border.

   .primary-content .card also has margin-bottom: 10px
   (theme.css:9786) — an off-scale value that makes vertical
   rhythm between panels inconsistent with everything else.
   ----------------------------------------------------- */

.card {
    border-color: var(--border-muted);
    border-radius: var(--rounding-md);
}

.card-header {
    background-color: transparent;
    border-bottom-color: var(--border-muted);
    padding: var(--space-3) var(--space-4);
    font-weight: 600;
    color: var(--text);
}

.card-body {
    padding: var(--space-4);
}

.card-footer {
    background-color: var(--bg-muted);
    border-top-color: var(--border-muted);
    padding: var(--space-3) var(--space-4);
}

.primary-content .card,
.primary-content .mc-promo-manage,
.primary-content .mc-promo-login {
    margin-bottom: var(--space-4);
    border-radius: var(--rounding-md);
}

.list-group-item {
    border-color: var(--border-muted);
    color: var(--text);
    padding: var(--space-3) var(--space-4);
}

.list-group-item-action:hover,
.list-group-item-action:focus {
    background-color: var(--bg-lifted);
    color: var(--primary);
}

.list-group-item.active {
    background-color: var(--primary);
    border-color: var(--primary);
    color: var(--text-inverted);
}

.sidebar .list-group-item {
    padding: var(--space-2) var(--space-4);
}

/* -----------------------------------------------------
   F. Tables

   .table sets color:#212529 and every cell border to #dee2e6.
   Cell padding 0.75rem all round is loose vertically and
   tight horizontally for data rows.
   ----------------------------------------------------- */

.table {
    color: var(--text);
}

.table th,
.table td {
    border-top-color: var(--border-muted);
    padding: var(--space-3);
    vertical-align: middle;
}

.table thead th {
    border-bottom-color: var(--border);
    border-top: 0;
    color: var(--text-accented);
    font-weight: 600;
    font-size: 0.8125rem;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    vertical-align: middle;
}

.table-bordered,
.table-bordered th,
.table-bordered td {
    border-color: var(--border-muted);
}

.table-hover tbody tr:hover {
    background-color: var(--bg-muted);
    color: var(--text);
}

.table-striped tbody tr:nth-of-type(odd) {
    background-color: var(--bg-muted);
}

/* Wide tables must scroll in their own box, never push the
   page sideways. WHMCS emits plenty of tables with no
   .table-responsive wrapper. */
@media (max-width: 767.98px) {
    .table-responsive,
    .table-container {
        -webkit-overflow-scrolling: touch;
    }

    .primary-content > .table:not(.table-responsive),
    .card-body > .table:not(.table-responsive) {
        display: block;
        overflow-x: auto;
        white-space: nowrap;
    }
}

/* -----------------------------------------------------
   G. Breadcrumb, pagination, tabs, alerts, badges
   ----------------------------------------------------- */

.master-breadcrumb .breadcrumb {
    padding: var(--space-3) 0;
    font-size: 0.875rem;
}

.breadcrumb-item + .breadcrumb-item::before {
    color: var(--text-muted);
}

.pagination {
    gap: var(--space-1);
}

.page-link {
    border-color: var(--border-muted);
    color: var(--text-accented);
    border-radius: var(--rounding-sm);
    min-width: 2.25rem;
    text-align: center;
}

.page-link:hover {
    background-color: var(--bg-lifted);
    border-color: var(--border);
    color: var(--primary);
}

.page-item.active .page-link {
    background-color: var(--primary);
    border-color: var(--primary);
    color: var(--text-inverted);
}

.page-item.disabled .page-link {
    color: var(--text-muted);
    border-color: var(--border-muted);
}

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

.nav-tabs .nav-link {
    border-radius: var(--rounding-sm) var(--rounding-sm) 0 0;
    color: var(--text-lifted);
    font-weight: 500;
    padding: var(--space-2) var(--space-4);
}

.nav-tabs .nav-link:hover {
    border-color: transparent transparent var(--border);
    color: var(--primary);
}

.nav-tabs .nav-link.active {
    color: var(--primary);
    border-color: var(--border-muted) var(--border-muted) var(--bg);
    font-weight: 600;
}

/* Alerts: Bootstrap's own tinted palette is unrelated to the
   theme's semantic colours, so success/info/warning/danger
   alerts arrive in yet another set of hues. */
.alert {
    border-radius: var(--rounding-md);
    padding: var(--space-3) var(--space-4);
    border-width: 1px;
    border-left-width: 3px;
}

.alert-success {
    background-color: #eafaf0;
    border-color: var(--success);
    color: #04502a;
}

.alert-info {
    background-color: #e8f4fe;
    border-color: var(--info);
    color: #0b4a72;
}

.alert-warning {
    background-color: #fff7e6;
    border-color: var(--warning);
    color: #7a4a00;
}

.alert-danger {
    background-color: #fdeeea;
    border-color: var(--error);
    color: #7d1e00;
}

.badge {
    border-radius: var(--rounding-sm);
    font-weight: 600;
    padding: 0.3em 0.5em;
}

.badge-dark {
    background-color: var(--primary);
}

/* -----------------------------------------------------
   H. Dropdowns, modals, popovers
   ----------------------------------------------------- */

.dropdown-menu {
    border-color: var(--border-muted);
    border-radius: var(--rounding-md);
    box-shadow: var(--shadow-md);
    padding: var(--space-1) 0;
    color: var(--text);
}

.dropdown-item {
    color: var(--text);
    padding: var(--space-2) var(--space-4);
}

.dropdown-item:hover,
.dropdown-item:focus {
    background-color: var(--bg-lifted);
    color: var(--primary);
}

.dropdown-item.active,
.dropdown-item:active {
    background-color: var(--primary);
    color: var(--text-inverted);
}

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

.modal-content {
    border-color: var(--border-muted);
    border-radius: var(--rounding-lg);
    box-shadow: var(--shadow-lg);
}

.modal-header,
.modal-footer {
    border-color: var(--border-muted);
    padding: var(--space-4);
}

.modal-body {
    padding: var(--space-4);
}

.popover {
    border-color: var(--border-muted);
    border-radius: var(--rounding-md);
    box-shadow: var(--shadow-md);
}

.tooltip-inner {
    background-color: var(--grayscale);
    border-radius: var(--rounding-sm);
    padding: var(--space-1) var(--space-2);
    font-size: 0.8125rem;
}

/* -----------------------------------------------------
   I. Order form — standard_cart

   Confirmed live: the active order form is standard_cart
   (the page carries id="order-standard_cart"), and
   theme.css:13459+ already styles it. Its markup is
   dual-classed for Bootstrap 3 and 4 — `panel card
   panel-default`, `panel-body card-body`, `pull-right
   float-right` — so the BS4 classes do the work and the BS3
   names are inert. Except these, which have no BS4 twin and
   no rule anywhere in the theme:

     .panel-body     0 rules (has .card-body, so padding is OK)
     .panel-default  0 rules
     .panel-sidebar  0 rules
     .pull-right     0 rules (BS3 float; .float-right covers it)

   The real spacing problem is the product card. theme.css
   stacks: .product padding 1px 0 10px, .product-desc padding
   12px 20px, footer margin 12px 0 PLUS padding 12px 20px,
   then .product-pricing margin-bottom 24px. Between the
   feature list and the price that compounds to ~60px of
   dead vertical space, and the button then sits another
   24px below the price.
   ----------------------------------------------------- */

body #order-standard_cart .products .product {
    margin-bottom: var(--space-4);
    border-radius: var(--rounding-md);
    padding: 0;
}

body #order-standard_cart .products .product header {
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--border-muted);
}

body #order-standard_cart .products .product div.product-desc {
    padding: var(--space-4);
}

/* Collapse the compounded margin+padding stack */
body #order-standard_cart .products .product footer {
    margin: 0;
    padding: 0 var(--space-4) var(--space-4);
}

body #order-standard_cart .products .product footer .product-pricing {
    margin-bottom: var(--space-3);
}

body #order-standard_cart .products .product footer .btn-order-now {
    background: var(--primary);
    border-color: var(--primary);
    border-radius: var(--rounding-md);
    padding: 0.5rem 1.25rem;
    font-weight: 600;
}

body #order-standard_cart .products .product footer .btn-order-now:hover,
body #order-standard_cart .products .product footer .btn-order-now:focus {
    background: var(--primary-lifted);
    border-color: var(--primary-lifted);
}

/* Feature lists inside product descriptions arrive as bare
   <ul> with browser-default 40px indent and no row rhythm */
body #order-standard_cart .products .product div.product-desc ul {
    padding-left: 1.15rem;
    margin-bottom: 0;
}

body #order-standard_cart .products .product div.product-desc ul li {
    margin-bottom: var(--space-1);
}

/* The actual feature list class. .package-features has ZERO
   rules in theme.css or store.css, so it fell back to the UA
   default 40px indent. */
body #order-standard_cart .product-desc ul.package-features {
    padding-left: 1.15rem;
    margin: 0;
    list-style: disc;
}

body #order-standard_cart .product-desc ul.package-features li {
    margin-bottom: var(--space-1);
    line-height: 1.5;
}

body #order-standard_cart .product-desc ul.package-features li:last-child {
    margin-bottom: 0;
}

/* ---- the unexplained gap between features and price ----

   Verified in the live markup. Each product description ends:

     <ul class="package-features">…</ul><br /> </p> <ul> </ul>

   Two pieces of junk, both from the product description field
   in WHMCS admin (the <p>/<br> pattern is WYSIWYG output):

     - a stray <br /> just before </p>
     - a completely EMPTY <ul></ul> after it

   The empty list still takes the UA default `margin: 1em 0`
   (32px total) and the <br> adds a full line box — roughly
   56px of dead vertical space that no CSS rule accounted for.
   Two per page here, one per product.

   :empty cannot be used — the tag contains a whitespace text
   node — so absence of <li> children is the test.

   Worth cleaning the product descriptions in admin too; this
   just stops bad markup from costing layout.                */

body #order-standard_cart .product-desc ul:not(:has(li)) {
    display: none;
}

body #order-standard_cart .product-desc p > br:last-child,
body #order-standard_cart .product-desc br:last-child {
    display: none;
}

body #order-standard_cart .product-desc p:last-child {
    margin-bottom: 0;
}

/* ---- product recommendation cards ----

   These live in <div class="product-recommendation clonable
   w-hidden hidden"> — a template the JS clones when a product
   has recommendations. Currently hidden, so this is not a
   visible defect today, but .cta, .headline, .btn-add,
   .expander, .breakdown-price and .setup-fee have NO rules in
   any stylesheet. Enable recommendations and they render
   completely unstyled.

   Styled to match the product cards so that does not happen. */

body #order-standard_cart .product-recommendation {
    border: 1px solid var(--border-muted);
    border-radius: var(--rounding-md);
    padding: var(--space-3) var(--space-4);
    margin-bottom: var(--space-3);
    background: var(--bg);
}

body #order-standard_cart .product-recommendation .header {
    display: flex;
    align-items: center;
    gap: var(--space-3);
}

body #order-standard_cart .product-recommendation .cta {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-left: auto;
}

body #order-standard_cart .product-recommendation .cta .price {
    font-weight: 600;
    color: var(--text);
    white-space: nowrap;
}

body #order-standard_cart .product-recommendation .setup-fee,
body #order-standard_cart .product-recommendation .breakdown-price {
    color: var(--text-lifted);
    font-weight: 400;
}

body #order-standard_cart .product-recommendation .btn-add {
    background: var(--primary);
    border-color: var(--primary);
    color: var(--text-inverted);
    border-radius: var(--rounding-sm);
    white-space: nowrap;
}

body #order-standard_cart .product-recommendation .btn-add:hover,
body #order-standard_cart .product-recommendation .btn-add:focus {
    background: var(--primary-lifted);
    border-color: var(--primary-lifted);
    color: var(--text-inverted);
}

body #order-standard_cart .product-recommendation .headline {
    font-weight: 600;
    color: var(--text);
}

body #order-standard_cart .product-recommendation .tagline {
    color: var(--text-lifted);
    font-size: 0.875rem;
}

body #order-standard_cart .product-recommendation .expander {
    cursor: pointer;
    color: var(--text-lifted);
}

body #order-standard_cart .product-recommendation .expander .rotate {
    transition: transform 200ms ease;
}

body #order-standard_cart .product-recommendation .expander .rotate.expanded {
    transform: rotate(90deg);
}

/* Recommendation cards stack on narrow screens — a flex row
   with a price and a button will not fit beside a headline */
@media (max-width: 575.98px) {
    body #order-standard_cart .product-recommendation .header {
        flex-wrap: wrap;
    }

    body #order-standard_cart .product-recommendation .cta {
        margin-left: 0;
        width: 100%;
        justify-content: space-between;
    }
}

/* ---- header search input ----

   header.tpl:97 and :127 use .appended-form-control and
   .prepended-form-control, neither of which has a rule
   anywhere in the theme. Harmless on their own, but the input
   sits inside a bordered .search wrapper, so it must not draw
   its own border or focus ring on top of the parent's. */

.appended-form-control,
.prepended-form-control {
    border: 0;
    box-shadow: none;
}

.appended-form-control:focus,
.prepended-form-control:focus {
    border: 0;
    box-shadow: none;
}

/* Sidebar panels: .panel-default and .panel-sidebar have no
   rules at all, so these lean entirely on .card */
body #order-standard_cart .panel.card,
body #order-standard_cart .panel-sidebar {
    border-color: var(--border-muted);
    border-radius: var(--rounding-md);
    margin-bottom: var(--space-4);
}

body #order-standard_cart .panel-body.card-body {
    padding: var(--space-4);
}

body #order-standard_cart .panel-title {
    font-size: 0.9375rem;
    font-weight: 600;
    margin: 0;
}

/* -----------------------------------------------------
   J. Page rhythm

   section#main-body has 20px vertical padding regardless of
   viewport, and .main-content carries margin-bottom: 60px
   plus min-height: 300px — so short pages get a large empty
   block below the content.
   ----------------------------------------------------- */

section#main-body {
    padding: var(--space-5) 0;
}

.main-content {
    margin-bottom: var(--space-6);
}

@media (max-width: 767.98px) {
    section#main-body {
        padding: var(--space-4) 0;
    }

    .main-content {
        margin-bottom: var(--space-5);
        min-height: 0;
    }

    section#main-content {
        margin-bottom: var(--space-5);
    }
}

/* -----------------------------------------------------
   K. Overflow guard

   Nothing should be able to scroll the page sideways. WHMCS
   emits long unbroken strings — domain names, API keys,
   invoice references — that overflow their container at
   narrow widths.
   ----------------------------------------------------- */

html,
body {
    overflow-x: hidden;
}

@media (max-width: 767.98px) {
    .primary-content,
    .card-body,
    .list-group-item {
        overflow-wrap: break-word;
        word-wrap: break-word;
    }

    pre,
    code {
        white-space: pre-wrap;
        overflow-wrap: break-word;
    }
}

/* Respect users who ask for less motion */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}
