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

    ** Custom Stylesheet **

    Any custom styling you want to apply should be
    defined here.

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

/* ==========================================================================
   Accessibility Styles
   ========================================================================== */

/* Skip to Content Link - Hidden by default, visible on focus */
.skip-to-content {
    position: fixed;
    top: -100px;
    left: 50%;
    transform: translateX(-50%);
    background: #000;
    color: #fff;
    padding: 10px 20px;
    z-index: 100000;
    text-decoration: none;
    font-weight: bold;
    border-radius: 0 0 4px 4px;
}

.skip-to-content:focus {
    top: 0;
}

/* ==========================================================================
   End Accessibility Styles
   ========================================================================== */

.w-hidden {
    display: none;
}
.alert-danger p {
    color: #a94442;
    background-color: #f2dede;
    border-color: #ebccd1;
}
.mt-1 {
    margin-top: 1rem;
}
section#main-menu {
    margin-top: 67px;
    border-bottom: 1px solid #e7e7e7;
}
.navbar-main li#Secondary_Navbar-Account {
    background-color: #f67c0a;
}

.navbar-main .navbar-nav>.active>a, .navbar-main .navbar-nav>.active>a:focus, .navbar-main .navbar-nav>.active>a:hover, .navbar-main .navbar-nav>.open>a, .navbar-main .navbar-nav>.open>a:focus, .navbar-main .navbar-nav>.open>a:hover, .navbar-main .navbar-nav>li>a:focus, .navbar-main .navbar-nav>li>a:hover {
    background-color: #f67c0a;
    color: #fff;
}

.navbar-main li#Secondary_Navbar-Account > a {
    border-bottom: 3px solid #f67c0a;
    color: #fff;
}

.navbar-default .navbar-nav>li>a:hover {
    color: #fff;
}
.navbar-default nav.navigation .navbar-nav>li>a:hover {
    color: #f67c0a;
}
.nav .open>a, .nav .open>a:focus, .nav .open>a:hover {
    border-color: #f67c0a;
}

#main-body .panel-default > .panel-heading, #main-body .panel-success > .panel-heading {
    color: #555;
    border-color: #eee;
    background: #f5f5f5;
    border-radius: 3px 3px 0 0;
    -webkit-border-radius: 3px 3px 0 0;
    -moz-border-radius: 3px 3px 0 0;
    border-bottom: 2px solid #eeeeee;
}
.dropdown:hover .dropdown-menu {
    border: 1px solid #e7e7e7;
}

div.header-lined h1 {
    color: #555;
}
.nopadding {
    padding: 0;
}
section.section-wrap.services .row.hidden-xs .text-center > a.btn.btn-primary {
    border-radius: 0;
    background: #F67C0A;
    border: 1px solid #A75101;
    border-bottom: 2px solid #A75101;
    color: #fff;
    width: auto;
    transition: all 0.3s ease-in-out;
    -moz-transition: all 0.3s ease-in-out;
    -webkit-transition: all 0.3s ease-in-out;
    -o-transition: all 0.3s ease-in-out;
}

.language-form strong {
line-height: 35px;
}
.language-form select {
position: relative;
vertical-align: top;
border: 1px solid #ddd;
display: -moz-inline-stack;
display: inline-block;
color: #626262;
outline: 0;
background: #fff;
height: 36px;
border-radius: 3px;
font-size: 13px;
}
div#solusvmpro_accordion a {
    color: #333;
}

/* --------------------------------------------------------------------------
   FIX 2026-08-02: WHMCS 9.0.6 stock order-form templates hide elements with
   Bootstrap 4+ utility classes, but this theme ships Bootstrap 3.4.1, whose
   hide-class is .hidden — so .d-none did nothing and the checkout page showed
   a permanently visible, EMPTY "Please correct the following errors" box
   (standard_cart/checkout.tpl renders the alert always and relies on .d-none).
   Defining the utility here fixes every 9.x template that uses it, and lives
   in the theme so a future WHMCS upgrade cannot overwrite it.

   EXTENDED 2026-08-02 (later the same day). Defining .d-none ALONE was not
   enough, and had itself introduced a regression. Bootstrap 4 display utilities
   work in PAIRS: the 9.x templates write `d-none d-sm-block` to mean "hidden on
   phones, shown from sm upwards". With only .d-none defined the second half of
   every pair did nothing, so 21 elements across 8 templates were hidden at
   EVERY width instead of just the small ones.

   The visible casualty was the per-row Remove button on cart.php?a=view --
   `<div class="col-sm-1 hidden-xs d-none d-sm-block">` in
   standard_cart/viewcart.tpl (lines 135, 212, 276) and the Qty column header
   (line 73). Products, addons and domains therefore had NO way to be deleted
   from the cart on a desktop browser. Renewal and upgrade rows were unaffected
   because their markup puts the button in a plain `col-sm-1` and only hides its
   text label, so they kept working -- which is why the fault looked intermittent.

   BREAKPOINTS BELOW ARE DELIBERATELY BOOTSTRAP 3'S (768/992/1200), NOT
   BOOTSTRAP 4'S (576/768/992). The visibility classes sit on elements whose
   GRID classes are Bootstrap 3 -- `col-sm-1 hidden-xs d-none d-sm-block`. BS3's
   .col-sm-* only takes effect from 768px. Using BS4's real 576px for d-sm-block
   would reveal that column between 576 and 767px, where col-sm-1 is not yet a
   column, so the button would drop onto its own full-width row under the price
   instead of sitting beside it. Matching BS3's boundaries keeps visibility in
   lockstep with the grid, and as a bonus means the BS3 and BS4 classes on these
   elements can never contradict each other (both carry !important, so a
   disagreement would be settled by source order -- fragile).

   Known, accepted cost: templates/six/store/* (the WP Toolkit, cPanel SEO,
   NordVPN, 360 Monitoring and Xovi addon pages) use d-md-*/d-lg-* WITHOUT a BS3
   partner class, so they were authored against BS4's boundaries and now switch
   one tier later than intended. That is cosmetic on those pages, whereas the
   grid mismatch above is a broken layout on the cart.

   Only the display values the active templates actually use are defined (none,
   inline, inline-block, block). Flex and table utilities are deliberately left
   out rather than shimmed blind; add them here if a template starts needing them.
   -------------------------------------------------------------------------- */
.d-none { display: none !important; }
.d-inline { display: inline !important; }
.d-inline-block { display: inline-block !important; }
.d-block { display: block !important; }

/* Bootstrap 3 "sm" tier. */
@media (min-width: 768px) {
    .d-sm-none { display: none !important; }
    .d-sm-inline { display: inline !important; }
    .d-sm-inline-block { display: inline-block !important; }
    .d-sm-block { display: block !important; }
}

/* Bootstrap 3 "md" tier. */
@media (min-width: 992px) {
    .d-md-none { display: none !important; }
    .d-md-inline { display: inline !important; }
    .d-md-inline-block { display: inline-block !important; }
    .d-md-block { display: block !important; }
}

/* Bootstrap 3 "lg" tier. */
@media (min-width: 1200px) {
    .d-lg-none { display: none !important; }
    .d-lg-inline { display: inline !important; }
    .d-lg-inline-block { display: inline-block !important; }
    .d-lg-block { display: block !important; }
}

/* ---------------------------------------------------------------------------
   View Cart link in the navbar (markup: ifastnet-child/header.tpl)
   2026-08-02

   Lives here rather than in a ClientAreaHeadOutput hook because header.tpl also
   renders on the SITE HOME PAGE, which is not a client area page -- the hook
   never fired there, so the mobile link appeared unstyled and unpositioned in
   the top left. custom.css is loaded on the home page too.

   Breakpoint is 991px, matching where this theme collapses both navbars into
   the hamburger (see css/all.min.css), NOT Bootstrap's default 768px. Exactly
   one of the two links is visible at any width; otherwise the desktop entry
   would also show inside the expanded mobile menu.
   --------------------------------------------------------------------------- */

.cart-nav-count {
    display: inline-block;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    margin-left: 4px;
    border-radius: 9px;
    background-color: #f67c0a;
    color: #fff;
    font-size: 11px;
    font-weight: 700;
    line-height: 18px;
    text-align: center;
    vertical-align: middle;
}

/* Desktop entry: only while the navbars are expanded. */
@media (max-width: 991px) {
    .navbar-main .cart-nav-item {
        display: none;
    }
}

/* Mobile entry: only while the hamburger is showing. It follows the toggle in
   the DOM and floats right, so it lands to the toggle's left. */
.cart-nav-mobile {
    display: none;
}

@media (max-width: 991px) {
    /* Level the cart icon with the hamburger.
       They were misaligned for two reasons: different box heights (the toggle
       is 3 x 2px bars + 2 x 4px gaps + padding + border = 34px, the cart icon
       18px of text + padding = 36px), and different top margins (the theme
       sets the toggle to 15px below 768px but Bootstrap leaves it at 8px
       between 769-991px, while the cart icon was a flat 15px).
       Fixing both: one explicit height, one shared top margin, and the
       contents centred inside each box. */
    .navbar-header .navbar-toggle,
    .navbar-header .cart-nav-mobile {
        display: flex;
        align-items: center;
        justify-content: center;
        float: right;
        height: 36px;
        margin-top: 12px;
        margin-bottom: 0;
        padding-top: 0;
        padding-bottom: 0;
    }

    /* The toggle is now a flex container, so its three bars would sit in a row
       without this. */
    .navbar-header .navbar-toggle {
        flex-direction: column;
    }

    .cart-nav-mobile {
        margin-right: 6px;
        padding-left: 10px;
        padding-right: 10px;
        font-size: 18px;
        line-height: 1;
        color: #333;
    }

    .cart-nav-mobile:hover,
    .cart-nav-mobile:focus {
        color: #f67c0a;
        text-decoration: none;
    }
}

/* ---------------------------------------------------------------------------
   Hide the secondary (WHMCS) navbar on mobile
   2026-08-02

   header.tpl renders two stacked navbars. This one, nav#nav.navbar-main, holds
   the WHMCS primary menu -- Home, Services, Domains, Billing, Support, Open
   Ticket, Affiliates -- plus the language chooser and the account dropdown.

   Below 991px (this theme's collapse point) it renders as nothing but a
   hamburger on a coloured strip. The whole <nav> is hidden rather than just
   .navbar-toggle, because hiding the icon alone would leave that strip behind
   as an empty band.

   Desktop is untouched: above 991px the menu still renders as a full
   horizontal bar.

   TRADE-OFF: this also removes the language chooser and the "Hello, <name>!"
   account dropdown from mobile. The fixed-top navbar above it still carries
   My Account / Login, so the client area stays reachable.
   --------------------------------------------------------------------------- */

@media (max-width: 991px) {
    #nav.navbar-main {
        display: none;
    }
}

/* ---------------------------------------------------------------------------
   Remove-from-cart control on cart.php?a=view
   2026-08-02

   Stock renders this as a bare `btn btn-link btn-xs` holding nothing but a
   fa-times glyph, inside a row whose font-size is 0.8em -- roughly a 10px grey
   × in the far right column, with no label and no hit area. Even once the
   display-utility fix above stops it being hidden outright, it does not read as
   a control. Restyled as a pill so it is unmistakably a button and its target
   is finger-sized.

   One rule covers both variants because the shape is driven by min-width +
   padding rather than a fixed width: the desktop button (icon only) comes out
   as a 30px circle, while the phone button and the renewal/upgrade rows, which
   carry the word "Remove" inside, stretch into a pill. No need to tell them
   apart in the selector.

   SPECIFICITY IS DELIBERATE. templates/orderforms/ifastnet_child_form/css/
   all.min.css is linked from the order form's common.tpl, i.e. from the BODY,
   so it loads AFTER this file and would otherwise win on source order with its
   own `#order-standard_cart .btn-remove-from-cart { color: #444 }`. Adding
   .view-cart-items makes these rules id + 2 classes against its id + 1, so they
   win on specificity regardless of load order.
   --------------------------------------------------------------------------- */

#order-standard_cart .view-cart-items .btn-remove-from-cart {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    min-width: 30px;
    height: 30px;
    padding: 0 9px;
    border: 1px solid #dcdcdc;
    border-radius: 999px;
    background-color: #fff;
    color: #767676;
    font-size: 12px;
    line-height: 1;
    text-decoration: none;
    transition: color .15s ease, background-color .15s ease, border-color .15s ease;
}

#order-standard_cart .view-cart-items .btn-remove-from-cart:hover,
#order-standard_cart .view-cart-items .btn-remove-from-cart:focus {
    border-color: #c0392b;
    background-color: #c0392b;
    color: #fff;
    text-decoration: none;
}

#order-standard_cart .view-cart-items .btn-remove-from-cart:focus {
    outline: none;
    box-shadow: 0 0 0 3px rgba(192, 57, 43, .25);
}

#order-standard_cart .view-cart-items .btn-remove-from-cart:active {
    background-color: #a93226;
    border-color: #a93226;
}

/* The column is `col-sm-1`, which is only a column from 768px up -- the same
   point the button becomes visible. Right-align it there so it sits under the
   header rule's right edge rather than floating mid-column. */
@media (min-width: 768px) {
    #order-standard_cart .view-cart-items .col-sm-1 {
        text-align: right;
    }
}

/* Note on the label span inside the renewal/upgrade buttons: the row sets
   `.item span:not(.caret):not(.renewal-price) { display: block }`, which looks
   like it should stack the word "Remove" under the glyph. It does not, and must
   NOT be "fixed" here -- the button is a flex container, so its children lay out
   along the main axis whatever their own display value is. Overriding it would
   also have to out-specify `.d-sm-none`, which is what correctly strips that
   label on desktop so every row shows the same icon-only circle. */


/* #############################################################################
   #                                                                           #
   #   CLIENT AREA HOME REDESIGN — 2026-08-11                                  #
   #   Integrated by agent D. Backup: custom.css.pre_redesign_20260811         #
   #                                                                           #
   #############################################################################

   WHY EVERYTHING BELOW IS AN ADDITION AND NOTHING ABOVE WAS TOUCHED
   -----------------------------------------------------------------
   custom.css is linked TWICE on every client area page:
       (2) six/includes/head.tpl:11-13   .../css/custom.css        <- NO cache-bust
       (4) ifastnet-child/header.tpl:107 .../css/custom.css?v=...  <- busted
   Both are served `Cache-Control: public, max-age=86400`. A returning visitor can
   therefore be holding a copy of this file that is up to 24h old at position (2).
   Deleting a rule does NOT stop it applying — the stale copy keeps serving it and
   nothing later undoes it. Every rule below is an ADD or an OVERRIDE that wins on
   specificity or source order against a rule that is still physically present.
   NEVER DELETE FROM THIS FILE. ALWAYS OVERRIDE.

   THE FULL CASCADE ON clientareahome (confirmed):
       1. ifastnet-child/css/all.min.css   <- STALE 2023 fork of the parent bundle
       2. ifastnet-child/css/custom.css    <- this file, un-busted copy
       3. ifastnet-child/assets/css/style.css
       4. ifastnet-child/css/custom.css?v= <- this file again, busted, LAST WORD
   ifastnet-child/css/styles.css and everything in six/css/ are never linked; the
   child bundle at (1) is what actually carries their compiled rules.

   ORDER OF THE THREE PARTS BELOW IS DELIBERATE:
       PART 1  agent A  — tiles + KB search      (scoped #main-body .tiles / .home-kb-search)
       PART 2  agent D  — panels, chrome, focus  (scoped #main-body .client-home-panels + site chrome)
       PART 3  agent C  — parent backport        (LAST, at agent C's request, so the
                          #registerDomainPanel flex rules land after part 2's panel
                          column-flex; they nest two levels inside it and never tie)
   A and D were verified not to collide on any selector; only the `#main-body` page
   scope is shared. See the conflict log in PART 2's header for what was arbitrated.
   ========================================================================== */


/* =============================================================================
   PART 1 of 3 — AGENT A — CLIENT AREA HOME TILES + KB SEARCH
   =============================================================================
   Pasted VERBATIM from scratchpad/spec-A-tiles.css (agent A, revision 2), with a
   single one-line addition in A10 marked "INTEGRATOR ADDITION".

   Section 10 history, so the next reader does not re-introduce the bug: agent A's
   first draft positioned the glyph with `#main-body .home-kb-search > i`. Agent B
   then replaced the decorative <i> with a real submit button, making the glyph a
   GRANDCHILD — so A's child combinator matched nothing while the stale bundle's
   `.home-kb-search i` (a DESCENDANT selector) kept matching and its
   float/negative-margin hack survived intact. Agent B caught it, agent D wrote an
   interim patch, and agent A then shipped revision 2, which is strictly better:
   it neutralises the hack with a DESCENDANT selector at (1,1,1) so no future
   wrapping can break it again, pins the button `top:0;bottom:0` instead of
   `height:100%`, and carries a `display:block; line-height:44px` fallback ahead of
   the flex centring because Chrome <62 and older Safari ignore `display:flex` on
   `<button>`. D's interim patch was DISCARDED in favour of A's.

   MARKUP (clientareahome.tpl, as edited by agent B and verified live):
     <div class="tiles clearfix">
       <div class="row">
         <div class="col-sm-4 col-xs-6 tile">
           <a href="..." class="tile-link">
             <div class="icon"><i class="fas fa-cube" aria-hidden="true"></i></div>
             <div class="stat">N</div>
             <div class="title">Label</div>
             <div class="highlight bg-color-blue"></div>
           </a>
         </div>  x3

   Selectors target `.tile > a`, NOT `.tile-link`, so this block is correct both
   before and after the template edit. `onclick` has been removed from `.tile`, so
   the anchor is the only control and the card padding MUST live on the anchor.

   SPECIFICITY LEDGER — what each rule beats in the stale bundle:
     #main-body .tiles                    (1,1,0) > .tiles                     (0,1,0)
     #main-body .tiles .tile              (1,2,0) > .tiles .tile               (0,2,0)
                                                  > @media .tiles .tile:nth-child(1),(2) (0,3,0)
                                                    [an id beats any number of classes]
     #main-body .tiles .tile > a          (1,3,0) > .tiles .tile a             (0,3,0)
                                                  > a:hover / a:focus          (0,1,1)
     #main-body .tiles .tile .icon/.stat/.title (1,3,0) > .tile .icon/...      (0,2,0)
     #main-body .tiles .tile .highlight   (1,3,0) > .tiles .tile .highlight    (0,3,0)

   `.bg-color-gold|green|red|blue` (0,1,0) are deliberately NOT touched — they stay
   the single source of the accent colour on `.highlight`.

   AGENT A'S DELIBERATE DEVIATION, ACCEPTED BY D: this part uses the cascade-native
   flex fallback (`display:block` first, then `-webkit-flex`/`-ms-flexbox`/`flex`)
   rather than PART 2's `@supports (display:flex)` guard. Accepted, not harmonised,
   because the two situations differ: `@supports` is not implemented in IE10/IE11,
   and a simple row of equal-height cards is something those engines DO render
   correctly via `-ms-flexbox`. PART 2's construction (nested column flex plus
   `margin-top:auto`) is the exact pattern IE11 gets wrong, so demoting IE11 to
   floats there is a feature. Rationale recorded so neither is "tidied" into the
   other later. Likewise A's `width:0` row-pseudo fix here vs D's `display:none`
   in PART 2 — see the comment above each; they are NOT interchangeable.
   ========================================================================== */


/* --------------------------------------------------------------------------
   A1. TILE STRIP CONTAINER
   Bundle has `.tiles{margin:0 15px 15px 15px}`, which insets the strip 15px
   relative to `.client-home-panels` below it. Zero it and rebuild the gutters
   from the row so the card edges land flush with the panels underneath.
   -------------------------------------------------------------------------- */

#main-body .tiles {
    margin: 0 0 4px 0;
}

/* Self-contained float containment. The markup carries `.tiles.clearfix`, but
   do not rely on it — this keeps the float fallback (A3) safe even if the class
   is ever dropped from the template. */
#main-body .tiles::before,
#main-body .tiles::after {
    content: " ";
    display: table;
}
#main-body .tiles::after {
    clear: both;
}


/* --------------------------------------------------------------------------
   A2. THE ROW BECOMES A FLEX LINE — equal heights, no float-drop

   `align-items` is left at its initial `stretch`, which is what makes all three
   `.tile` columns resolve to the height of the tallest one. That is the entire
   fix for the ragged bottom edge and for tile 3 float-dropping into the right
   column when tile 1's title wraps.

   `-webkit-box` is INTENTIONALLY OMITTED. The 2009 box model cannot wrap
   (`flex-wrap` has no `-webkit-box` equivalent), so declaring it would force all
   three tiles onto one line on iOS <7 / Android <4.4 and regress the xs layout
   below. Those browsers fall through to the float fallback instead, which is
   correct there. `-webkit-flex` (Safari 6.1-8) and `-ms-flexbox` (IE10) are the
   prefixes that actually matter and both support wrapping.
   -------------------------------------------------------------------------- */

#main-body .tiles > .row {
    display: -webkit-flex;
    display: -ms-flexbox;
    display: flex;
    -webkit-flex-wrap: wrap;
        -ms-flex-wrap: wrap;
            flex-wrap: wrap;
    -webkit-align-items: stretch;
        -ms-flex-align: stretch;
            align-items: stretch;
    margin-left: -8px;
    margin-right: -8px;
}

/* THE CLEARFIX-PSEUDO TRAP.
   Bootstrap 3 gives `.row` a clearfix: `:before/:after { content:" "; display:table }`
   and `:after { clear:both }`. Inside a flex container those two pseudo-elements
   are blockified into real FLEX ITEMS. `content:" "` gives them the intrinsic
   width of a space (~4px each), so the line would total 100% + 8px, forcing all
   three tiles to shrink and leaving a blank sliver at each end of the row.

   Fix with `width:0` rather than `display:none`, because this rule is NOT
   wrapped in `@supports` and must stay harmless on the float path:
     - flex path  -> zero-width flex items, no shrink pressure, no wrap forced.
     - float path -> `clear:both` still works (clearing is independent of width),
                     so the fallback clearfix is fully intact.
   `display:none` would have broken the float path, and putting it behind
   `@supports` would have missed IE10/11, which do flex but not `@supports`. */
#main-body .tiles > .row::before,
#main-body .tiles > .row::after {
    width: 0;
}

/* Defensive: if any agent later adds a Bootstrap spacer div between the tiles,
   neutralise it in browsers that actually flex. Guarded by `@supports` so the
   float fallback — the only place such a div would do any work — keeps it.
   Beats `.visible-xs-block{display:block!important}` (0,1,0) on specificity. */
@supports (display: flex) {
    #main-body .tiles > .row > .clearfix {
        display: none !important;
    }
}


/* --------------------------------------------------------------------------
   A3. THE TILE COLUMN — now a transparent gutter shell, not the visible surface
   The card surface moves to the anchor (A4) so we can have real gutters between
   three cards without an extra wrapper element.

   MOBILE FIRST: full width below 768px. This is the xs-orphan fix — with
   `width:100%` there is no 2+1 grid and therefore no half-width hole and no
   float-drop, on BOTH the flex path and the float path, with zero markup help.
   `clear:left` is belt-and-braces for the float fallback only.
   -------------------------------------------------------------------------- */

#main-body .tiles .tile {
    display: block;             /* float-fallback value; overridden just below */
    display: -webkit-flex;
    display: -ms-flexbox;
    display: flex;
    -webkit-flex-direction: column;
        -ms-flex-direction: column;
            flex-direction: column;

    /* CRITICAL: flex items default to `min-width:auto`, so an unbreakable stat
       or title can force the item wider than its `width` and blow the line into
       a wrap. Without this the equal-height fix reintroduces the drop it cures. */
    min-width: 0;

    width: 100%;
    float: none;
    clear: left;

    padding: 0 8px;             /* was 12px 20px — the gutter, not the surface */
    margin: 0 0 16px 0;
    background-color: transparent;  /* kills `.tiles .tile{background:#f8f8f8}` AND
                                       `.tiles .tile:hover{background:#f2f2f2}`, so the
                                       latched-hover-on-touch bug cannot occur at all */
    background-image: none;
    border: 0;                  /* kills border-right AND the xs border-bottom rules */
    position: relative;
}

@media (min-width: 768px) {
    #main-body .tiles .tile {
        width: 33.3333333%;
        clear: none;
        margin-bottom: 0;
    }
}


/* --------------------------------------------------------------------------
   A4. THE CARD — flat grey strip becomes three distinct white cards
   The anchor is the card: it carries the surface, the padding and the hit area.
   `onclick` is gone from `.tile`, so the anchor is the only control and MUST
   cover the whole clickable surface — hence padding lives here, never on `.tile`.

   CONTAINING BLOCK: `.tile` above is `position:relative` so the tile no longer
   depends on Bootstrap's `.col-*{position:relative}`. The anchor is ALSO relative
   and, being nearer, is the actual containing block for `.icon` and `.highlight`
   — which is what we want, since those must align to the card edge, not to the
   outer gutter edge. Both are set, so removing either `col-sm-4`/`col-xs-6` or
   the card styling still leaves a positioned ancestor.
   -------------------------------------------------------------------------- */

#main-body .tiles .tile > a {
    display: block;             /* float-fallback value — MUST come first, or a
                                   browser without flex leaves the anchor inline
                                   and the whole card collapses */
    display: -webkit-flex;
    display: -ms-flexbox;
    display: flex;
    -webkit-flex-direction: column;
        -ms-flex-direction: column;
            flex-direction: column;
    -webkit-flex: 1 1 auto;
        -ms-flex: 1 1 auto;
            flex: 1 1 auto;
    min-width: 0;

    position: relative;
    /* right padding reserves the icon gutter so a 3-digit stat can never run
       under the glyph at col-xs-6 / 320px */
    padding: 16px 58px 14px 16px;
    min-height: 96px;

    background-color: #fff;
    border: 1px solid #e3e7ec;
    border-radius: 4px;
    -webkit-box-shadow: 0 1px 2px rgba(16, 24, 40, .05);
            box-shadow: 0 1px 2px rgba(16, 24, 40, .05);

    color: #45464b;
    text-decoration: none;
    cursor: pointer;
    -webkit-tap-highlight-color: rgba(14, 80, 119, .12);

    -webkit-transition: border-color .15s ease, box-shadow .15s ease, -webkit-transform .15s ease;
            transition: border-color .15s ease, box-shadow .15s ease, transform .15s ease;
}

/* Beat `a:hover{color:#f67c0a}` and `a:focus{color:#000}` from
   assets/css/style.css:65-73 so the card text never flips orange. */
#main-body .tiles .tile > a:hover,
#main-body .tiles .tile > a:focus,
#main-body .tiles .tile > a:active,
#main-body .tiles .tile > a:visited {
    color: #45464b;
    text-decoration: none;
}


/* --------------------------------------------------------------------------
   A5. ACCENT BAR
   `.highlight` is repurposed from a 2px underline into a 3px top rule, matching
   the `.panel.panel-accent-*{border-top:3px solid}` treatment on the panels below
   so the page reads as one system. Taken out of flow, so it cannot affect the
   equal-height calculation. Negative offsets park it over the 1px border.
   Background colour still comes solely from `.bg-color-*` — untouched.
   -------------------------------------------------------------------------- */

#main-body .tiles .tile .highlight {
    position: absolute;
    top: -1px;
    left: -1px;
    right: -1px;
    height: 3px;
    margin: 0;
    border-radius: 4px 4px 0 0;
}


/* --------------------------------------------------------------------------
   A6. ICON
   Bundle: 48px at right:10px with a 40px `.stat` and no reserved gutter, so a
   3-digit stat ran straight under the glyph at col-xs-6/320px. Two changes: the
   icon is smaller, and A4 reserves 58px of right padding on the card so `.stat`
   and `.title` can never enter the icon's column at any width.
   -------------------------------------------------------------------------- */

#main-body .tiles .tile .icon {
    position: absolute;
    top: 50%;
    right: 16px;
    left: auto;
    width: 34px;
    margin-top: -17px;          /* half of the 34px line-box height; centres the
                                   glyph without needing a transform */
    font-size: 30px;
    line-height: 34px;
    text-align: center;
    color: #dfe4ea;
    pointer-events: none;
    -webkit-transition: color .15s ease;
            transition: color .15s ease;
}


/* --------------------------------------------------------------------------
   A7. STAT + TITLE
   `.stat` colour is pinned so it does not inherit `a:hover{color:#f67c0a}`;
   hover feedback comes from the card chrome instead (A9).
   `tabular-nums` keeps 1/7 the same width so three tiles' numbers line up.
   -------------------------------------------------------------------------- */

#main-body .tiles .tile .stat {
    margin: 0 0 2px 0;
    font-size: 30px;
    line-height: 1.15;
    font-weight: 600;
    color: #1f2933;
    min-width: 0;
    /* last-resort guards: never let a freak value punch out of the card */
    word-wrap: break-word;
    overflow-wrap: break-word;
    -webkit-font-feature-settings: "tnum" 1;
            font-feature-settings: "tnum" 1;
    font-variant-numeric: tabular-nums;
}

#main-body .tiles .tile .title {
    margin: 0;
    font-size: 11px;
    font-weight: 700;
    line-height: 1.35;
    letter-spacing: .055em;
    text-transform: uppercase;
    color: #6b7684;
    min-width: 0;
    word-wrap: break-word;
    overflow-wrap: break-word;
}

@media (min-width: 992px) {
    #main-body .tiles .tile > a {
        min-height: 104px;
        padding-top: 18px;
    }
    #main-body .tiles .tile .stat {
        font-size: 34px;
    }
}


/* --------------------------------------------------------------------------
   A8. TILE FOCUS
   assets/css/style.css:60-73 sets `a{outline:none}` and `a:focus{outline:none}`
   at (0,1,1) and loads before the second custom.css copy. (1,3,1) beats it.

   `:focus` fires unconditionally as the fallback. Where `:focus-visible` is
   actually supported, the always-on ring is withdrawn and re-applied only for
   keyboard focus. The withdrawal is inside `@supports selector(:focus-visible)`,
   so a browser that understands neither keeps the plain `:focus` ring rather than
   silently losing it — the failure mode is a ring too often, never none.

   Deliberately out-specifies PART 2's site-wide ring: the card has a radius and a
   shadow, so it needs `outline-offset:2px` to clear them rather than cut across.
   PART 2 uses the same #0e5077 and the same @supports pattern, so the two focus
   systems are visually one system.
   -------------------------------------------------------------------------- */

#main-body .tiles .tile > a:focus {
    outline: 2px solid #0e5077;
    outline-offset: 2px;
    border-color: #b9c4cf;
}

@supports selector(:focus-visible) {
    #main-body .tiles .tile > a:focus {
        outline: 0;
        outline-offset: 0;
    }
    #main-body .tiles .tile > a:focus-visible {
        outline: 2px solid #0e5077;
        outline-offset: 2px;
        border-color: #b9c4cf;
    }
}


/* --------------------------------------------------------------------------
   A9. HOVER
   Wrapped in `@media (hover:hover)` so touch browsers never latch the state
   after a tap. Anything that cannot parse the query drops the block entirely and
   simply gets no hover, which is the correct degradation for decoration.
   -------------------------------------------------------------------------- */

@media (hover: hover) {
    #main-body .tiles .tile > a:hover {
        border-color: #c6d0da;
        -webkit-box-shadow: 0 3px 8px rgba(16, 24, 40, .09);
                box-shadow: 0 3px 8px rgba(16, 24, 40, .09);
        -webkit-transform: translateY(-1px);
            -ms-transform: translateY(-1px);
                transform: translateY(-1px);
    }
    #main-body .tiles .tile > a:hover .icon {
        color: #c8d0d9;
    }
}

@media (prefers-reduced-motion: reduce) {
    #main-body .tiles .tile > a,
    #main-body .tiles .tile .icon {
        -webkit-transition: none;
                transition: none;
    }
    #main-body .tiles .tile > a:hover {
        -webkit-transform: none;
            -ms-transform: none;
                transform: none;
    }
}


/* --------------------------------------------------------------------------
   A10. KB SEARCH  (agent A REVISION 2 — taken verbatim; supersedes D's patch)
   Bundle: `.home-kb-search i{float:left;margin-top:-30px;margin-left:20px}` — a
   negative-margin overlay hand-tuned to Bootstrap's 46px `.input-lg`. Any
   line-height change (Firefox's "minimum font size" setting, a user stylesheet,
   a font that fails to load) slides the glyph off the field.

   Replaced with a `position:relative` wrapper + an absolutely positioned,
   stretched submit button. `height:auto` + `min-height` on the field lets it grow
   instead of clipping its own text, and the button is pinned `top:0;bottom:0` so
   it tracks the field at whatever height Firefox settles on. 16px font-size also
   stops iOS Safari zooming the viewport on focus.

   MARKUP (live, per Agent B — clientareahome.tpl:66-75):
       <div class="col-md-12 home-kb-search">
         <input class="form-control input-lg" …>
         <button type="submit" class="home-kb-search-btn">
           <i class="fas fa-search" aria-hidden="true"></i>
           <span class="sr-only">Search</span>
         </button>
       </div>
   The glyph is a GRANDCHILD, and it now lives inside a real submit control — it
   is not the decorative overlay it used to be. Two consequences that cost an
   earlier draft of this file its fix, both now defended against below:
     - a `>` combinator on the `<i>` does not match; the neutraliser is a
       descendant selector so nesting depth cannot break it again;
     - the bundle's hack is itself a descendant selector, so it survives any
       amount of wrapping and MUST be explicitly out-specified, not out-nested.

   HORIZONTAL ANCHOR: the containing block is the padding box of
   `.col-md-12.home-kb-search`, whose left edge sits 15px OUTSIDE the input's
   left edge (the Bootstrap column gutter). Hence `left:15px` on the button —
   one contribution only, because the button starts flush with the field's edge
   rather than inset within it. If the column padding is ever removed, drop the
   `left` to 0. The 46px button width is tied to the field's `padding-left:46px`;
   change the two together or the text will run under the glyph.
   -------------------------------------------------------------------------- */

#main-body .home-kb-search {
    position: relative;
    margin-bottom: 18px;
}

#main-body .home-kb-search .form-control {
    height: auto;
    min-height: 44px;
    padding: 11px 14px 11px 46px;
    font-size: 16px;
    line-height: 1.375;
    /* The bundle's `.home-kb-search .form-control` (0,2,0) also sets
       `font-weight:300`, and this override block never claimed it — so the field
       and its placeholder rendered in Light while every other control on the page
       is Regular. It also degrades badly if the Open Sans 300 face fails to load,
       since the browser synthesises a thin face rather than falling back to 400.
       Found by agent A auditing every unclaimed declaration in the rules we
       neutralise, which is the right way to check this. */
    font-weight: 400;
    background-color: #fff;
    border: 1px solid #dfe3e8;
    border-radius: 4px;
    color: #45464b;
    -webkit-box-shadow: none;
            box-shadow: none;
    -webkit-transition: border-color .15s ease, box-shadow .15s ease;
            transition: border-color .15s ease, box-shadow .15s ease;
}

#main-body .home-kb-search .form-control::-webkit-input-placeholder { color: #9aa3ab; }
#main-body .home-kb-search .form-control::-moz-placeholder          { color: #9aa3ab; opacity: 1; }
#main-body .home-kb-search .form-control:-ms-input-placeholder      { color: #9aa3ab; }
#main-body .home-kb-search .form-control::placeholder               { color: #9aa3ab; }

/* Bundle sets `outline:0; box-shadow:none` on focus, leaving the field with no
   focus indication at all. Restore a ring that is not an outline, so it follows
   the input's border-radius. */
#main-body .home-kb-search .form-control:focus {
    border-color: #0e5077;
    -webkit-box-shadow: 0 0 0 3px rgba(14, 80, 119, .16);
            box-shadow: 0 0 0 3px rgba(14, 80, 119, .16);
    outline: 0;
}

/* KILL THE STALE HACK, AT ANY NESTING DEPTH.
   `.home-kb-search i{float:left;margin-top:-30px;margin-left:20px}` in the bundle
   is a DESCENDANT selector (0,1,1), so it keeps matching however deeply the glyph
   is wrapped. This neutraliser is also a descendant selector, at (1,1,1), so it
   cannot be out-manoeuvred by a future markup change the way a `>` combinator can.
   Agent B moved the `<i>` inside a submit <button>; an earlier draft of this file
   used `.home-kb-search > i`, which silently stopped matching while the bundle's
   hack survived — exactly the failure this rule now forecloses. */
#main-body .home-kb-search i {
    float: none;
    margin: 0;
    /* INTEGRATOR ADDITION (agent D, placement corrected by agent A). The bundle
       rule being neutralised is
           .home-kb-search i{float:left;margin-top:-30px;margin-left:20px;color:#777}
       — it sets COLOUR too, directly on the <i> at (0,1,1). Without this the glyph
       kept #777 and ignored the button's #8a939c default and its #45464b
       hover/focus colour, so the hover and focus affordances rendered as no
       visible change at all.
       It lives on THIS rule, not on the narrower `.home-kb-search-btn > i` below,
       for the same reason the float/margin reset does: out-specify, don't
       out-nest. A child combinator stops matching the moment the glyph is
       re-wrapped — which already happened once when the <i> was moved inside the
       submit button — and #777 would silently return. (1,1,1) beats (0,1,1) at
       any nesting depth. */
    color: inherit;
}

/* SUBMIT BUTTON — owns the whole 46px left zone the field's padding reserves,
   so the target is ~46x44 instead of a 16x16 glyph (WCAG 2.5.8 wants >=24x24).
   `top:0;bottom:0` stretches it to the field's real height, so it tracks however
   far Firefox's minimum-font-size grows the input — same goal as the old
   translateY approach, reached without a transform.
   `left:15px` cancels the `.col-md-12` gutter (see the note above); there is no
   second contribution here because the button starts at the field's edge, not
   inset within it. */
#main-body .home-kb-search .home-kb-search-btn {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 15px;
    width: 46px;                /* == .form-control padding-left, so the button
                                   ends exactly where the input text begins */
    z-index: 2;
    padding: 0;
    margin: 0;
    border: 0;
    background: transparent;
    -webkit-appearance: none;   /* iOS Safari styles bare <button> otherwise */
       -moz-appearance: none;
            appearance: none;
    color: #8a939c;
    cursor: pointer;

    /* Non-flex fallback: block + centred line box. Chrome <62 and old Safari
       ignored `display:flex` on <button>, so this must stay as the safety net.
       `line-height` matches .form-control's min-height. */
    display: block;
    text-align: center;
    line-height: 44px;
    display: -webkit-flex;
    display: -ms-flexbox;
    display: flex;
    -webkit-align-items: center;
        -ms-flex-align: center;
            align-items: center;
    -webkit-justify-content: center;
        -ms-flex-pack: center;
            justify-content: center;

    -webkit-transition: color .15s ease;
            transition: color .15s ease;
}

/* (1,3,1) — beats the bundle's `.home-kb-search i` (0,1,1). */
#main-body .home-kb-search .home-kb-search-btn > i {
    float: none;
    margin: 0;
    font-size: 16px;
    line-height: 1;
    /* INTEGRATOR ADDITION (agent D). The stale bundle rule that this block
       neutralises also carries `color:#777`, and it targets the <i> DIRECTLY at
       (0,1,1) — so the glyph would keep #777 and simply ignore the button's
       #8a939c default and its #45464b hover/focus colour, silently losing the
       hover and focus affordance A designed. `inherit` hands the colour back to
       the button. One line, completes A's intent, changes nothing else. */
    color: inherit;
    /* On the GLYPH ONLY, never on the button: it stops the <i> from swallowing
       the click so the event lands on the <button> and submits the form.
       (This is NOT the old "let clicks fall through to the input" behaviour —
       the button is a real submit control now. Do not move this up a level.) */
    pointer-events: none;
}

#main-body .home-kb-search .home-kb-search-btn:focus {
    outline: 2px solid #0e5077;
    outline-offset: -2px;       /* inset, so the ring sits inside the field */
    color: #45464b;
}

@supports selector(:focus-visible) {
    #main-body .home-kb-search .home-kb-search-btn:focus {
        outline: 0;
    }
    #main-body .home-kb-search .home-kb-search-btn:focus-visible {
        outline: 2px solid #0e5077;
        outline-offset: -2px;
        color: #45464b;
    }
}

@media (hover: hover) {
    #main-body .home-kb-search .home-kb-search-btn:hover {
        color: #45464b;
    }
}

@media (prefers-reduced-motion: reduce) {
    #main-body .home-kb-search .form-control,
    #main-body .home-kb-search .home-kb-search-btn {
        -webkit-transition: none;
                transition: none;
    }
}



/* =============================================================================
   PART 2 of 3 — AGENT D — PANELS, PAGE CHROME, FOCUS, STICKY FOOTER
   =============================================================================

   CONFLICTS ARBITRATED HERE (recorded so nobody re-litigates them):

   1. PANEL-BODY PADDING — NOT CHANGED, deliberately. The bundle sets
      `.client-home-panels .panel>.panel-body{padding:0}` and compensates inside
      each panel's own content (`.panel-body p{padding:10px 15px}`, and agent C's
      backported `.sitejet-panel-container{margin:10px 15px 20px}`). Restoring
      padding on .panel-body would double-inset Sitejet to 30px and force C's
      margins to be rewritten. Upstream's contract is kept.

   2. PANEL-FOOTER PADDING — NOT SET HERE, deliberately. Agent C backports
      `div[menuitemname='Active Products/Services'] .panel-footer{padding:4px 15px}`
      at (0,2,1). A generic `#main-body .client-home-panels .panel>.panel-footer`
      padding would be (1,4,0) and would silently beat it. This block therefore
      sets only background and border on the footer and leaves padding to
      Bootstrap's `.panel-footer{padding:10px 15px}` (0,1,0), which C's scoped
      rule correctly overrides for the one panel that needs it.

   3. PANEL BORDER COLOUR — set per-SIDE, never with the `border-color`
      shorthand. `.panel.panel-accent-gold{border-top:3px solid #f0ad4e}` is
      (0,2,0); a shorthand `border-color` at (1,2,0) here would overwrite the
      accent's top colour and silently destroy the entire accent palette the
      brief says to keep. right/bottom/left only.

   4. FOCUS COLOUR — harmonised on agent A's #0e5077, not the brand orange this
      block originally proposed. #0e5077 on white is 8.6:1 (WCAG 2.2 SC 1.4.11
      wants 3:1); #a75101 was only 5.5:1 and clashed with A's two tile/search
      rules, which would have left two different focus colours on one page.
      A's colour adopted wholesale. White is substituted on the dark navbar,
      where #0e5077 on #0e5077 would be invisible.

   5. `:focus-visible` NEVER shares a comma list with a plain `:focus` selector.
      One unrecognised selector invalidates an ENTIRE rule, so mixing them would
      silently delete the fallback ring in older browsers. Every `:focus-visible`
      selector below lives inside `@supports selector(:focus-visible)`, matching
      the pattern A used in A8.
   ========================================================================== */


/* --------------------------------------------------------------------------
   D1. REMOVE THE 170px SCROLLBOX  (user complaint U3, and the cause of U1)

   Bundle, compiled from the never-linked styles.css:559-575 —
       .client-home-panels .panel>.panel-body{padding:0;max-height:170px;overflow:auto}
       .client-home-panels .panel>.list-group{max-height:170px;overflow:auto;
                                              border-top:1px solid #ddd;border-bottom:1px solid #ddd}
   Both are (0,3,0); `#main-body` in front makes these (1,3,0) and an id beats any
   number of classes, so this wins regardless of source order.

   Symptoms removed: ~5 of N rows visible with the 6th sliced mid-row; no
   `-webkit-overflow-scrolling:touch`, so iOS/macOS Safari draw overlay scrollbars
   and give ZERO affordance that content is hidden, while Windows/Linux
   Firefox/Chrome eat 15-17px and render the two col-sm-6 panels at different
   content widths. Also, and separately worth having: `overflow:auto` was clipping
   any `.dropdown-menu` that escaped the panel — the Active Products rows have
   real dropdowns (`.div-service-item .dropdown-menu`), which were being cut off.

   Height is now driven by content. Agent C's backported `nth-child(n+5){display:none}`
   caps the Active Products list at 4 rows with a working "View More" button, and
   the Sitejet panel needs 162px (desktop) / 244px (mobile stacked) / up to 306px
   with an error alert — all of which this allows.
   -------------------------------------------------------------------------- */

#main-body .client-home-panels .panel > .panel-body,
#main-body .client-home-panels .panel > .list-group {
    max-height: none;
    overflow: visible;
}

/* The heading now draws the rule above the list, so the list-group's own top
   border would double it. Bottom border softened to match the new palette. */
#main-body .client-home-panels .panel > .list-group {
    border-top: 0;
    border-bottom: 1px solid #ececec;
}


/* --------------------------------------------------------------------------
   D2. EQUAL-HEIGHT PANELS WITHIN EACH ROW PAIR

   Scoped to `.client-home-panels-row`, the class agent B puts on rows holding a
   PAIR of col-sm-6 panels. Rows holding a single full-width colspan panel carry
   `.client-home-panels-row-full` instead and are deliberately NOT matched — there
   is nothing to equalise against, and flexing a lone item would only risk it.

   WHY `@supports` HERE BUT NOT IN PART 1: this construction is nested column flex
   (`col` is a column flex container, `.panel` is another one inside it) plus
   `margin-top:auto` on the footer. That is precisely the combination IE10/IE11
   mis-compute. `@supports` is not implemented in IE, so IE falls through to the
   float path and gets today's behaviour — unequal heights, nothing broken. That
   is the correct degradation. Part 1's simple row of cards has no such hazard,
   which is why it uses the cascade-native fallback instead. Do not harmonise.

   ONLY AT >=768px: below that, `.col-sm-6` has no `width`, so as a flex item it
   would shrink to its content width and the two panels would sit side by side
   crushed together instead of stacking. The float/block path is correct on mobile.
   -------------------------------------------------------------------------- */

@media (min-width: 768px) {
    @supports (display: flex) {

        #main-body .client-home-panels .client-home-panels-row {
            display: -webkit-flex;
            display: flex;
            -webkit-flex-wrap: wrap;
                    flex-wrap: wrap;
            -webkit-align-items: stretch;
                    align-items: stretch;
        }

        /* THE CLEARFIX-PSEUDO TRAP, again — but the opposite fix to A2's.
           `display:none` is correct HERE because this whole block is inside
           `@supports`, so the float path never sees it and keeps its clearfix
           intact. A2 could not do this because it is unguarded. Left as two
           different fixes on purpose; see PART 1's header. */
        #main-body .client-home-panels .client-home-panels-row:before,
        #main-body .client-home-panels .client-home-panels-row:after {
            display: none;
        }

        /* `min-width:0` is load-bearing: flex items default to `min-width:auto`,
           and a long unbreakable domain name in the Active Products list would
           otherwise force the column past its 50% width and wrap the pair. */
        #main-body .client-home-panels .client-home-panels-row > [class*="col-"] {
            display: -webkit-flex;
            display: flex;
            -webkit-flex-direction: column;
                    flex-direction: column;
            min-width: 0;
        }

        /* `flex: 1 1 auto`, never `flex: 1`. The latter expands to `1 1 0%`, which
           IE11 and older Safari mis-size in column direction. */
        #main-body .client-home-panels .client-home-panels-row > [class*="col-"] > .panel {
            -webkit-flex: 1 1 auto;
                    flex: 1 1 auto;
            display: -webkit-flex;
            display: flex;
            -webkit-flex-direction: column;
                    flex-direction: column;
        }

        /* Pins the footer to the bottom of the stretched panel so the two
           "View More" bars in a pair line up. When a panel has no footer at all
           (agent B now emits it conditionally) the slack simply falls at the
           bottom of the panel, which is the desired result. */
        #main-body .client-home-panels .client-home-panels-row .panel > .panel-footer {
            margin-top: auto;
        }
    }
}


/* --------------------------------------------------------------------------
   D3. PANEL HEADING — resolving the specificity war

   custom.css:76 `#main-body .panel-default > .panel-heading{background:#f5f5f5;
   border-bottom:2px solid #eee;border-radius:3px 3px 0 0}` is (1,2,0) and was
   BEATING the intended `.client-home-panels .panel > .panel-heading
   {background-color:#fff;border-bottom:0}` at (0,3,0), because an id outranks any
   number of classes. The dashboard was getting the generic grey client-area
   heading instead of the flat white one the design intends.

   Resolved at (1,3,0) — one class more than custom.css:76, so it wins cleanly on
   specificity rather than on source order, and it stays scoped to the dashboard:
   the grey heading is still correct everywhere else under #main-body (services,
   invoices, tickets) and is deliberately left alone there.

   THE 3px-vs-4px RADIUS SLIVER IS RESOLVED BY CONSTRUCTION, NOT BY ARITHMETIC.
   `.panel` has `border-radius:4px`; `.panel-accent-*` puts a 3px border on the
   top edge only. The correct inner radius is 1px at the top but 3px at the sides,
   which a single `border-radius` value cannot express — any value leaks a sliver
   of panel background at the top corners. Setting the heading's background to
   #fff, the same as `.panel`'s own background, makes the mismatch invisible
   because there is no colour difference left to leak. `border-radius:0` is then
   set only so a future hover/active background on the heading cannot resurrect it.
   -------------------------------------------------------------------------- */

#main-body .client-home-panels .panel > .panel-heading {
    background: #fff;
    background-image: none;
    border-bottom: 1px solid #ececec;
    border-radius: 0;
    color: #333;
    padding: 12px 15px;
    font-weight: 400;   /* the weight belongs on the title, not the whole bar */
}

#main-body .client-home-panels .panel > .panel-heading .panel-title {
    font-size: 15px;
    font-weight: 600;
    line-height: 1.4;
    color: #2f3a44;
}

/* The heading's optional right-hand button. six/css/overrides.css:214 sets
   `.btn{overflow:hidden}` globally, which guillotines a long label mid-glyph with
   no ellipsis; restore an ellipsis so a long translation degrades legibly. */
#main-body .client-home-panels .panel > .panel-heading .panel-title .btn {
    max-width: 100%;
    text-overflow: ellipsis;
    white-space: nowrap;
}


/* --------------------------------------------------------------------------
   D4. PANEL FOOTER

   Agent B has made the markup conditional, so a footerless panel no longer emits
   the div at all and the ~41px grey bar is gone at source.

   `:empty` IS INCLUDED BUT IS NOT THE FIX, AND MUST NOT BE RELIED ON: the old
   template emitted `<div class="panel-footer">\n    \n</div>`, and `:empty` does
   NOT match an element containing a whitespace text node. There is no pure-CSS
   selector for "contains only whitespace". It is kept only for the genuinely
   empty case. What actually makes a stray footer harmless is the white background
   below: an empty white strip at the bottom of a white panel is invisible, whereas
   Bootstrap's #f5f5f5 default read as a deliberate grey slab.

   Padding is deliberately NOT set here — see conflict 2 in this part's header.
   -------------------------------------------------------------------------- */

#main-body .client-home-panels .panel > .panel-footer {
    background-color: #fff;
    border-top: 1px solid #ececec;
}

#main-body .client-home-panels .panel > .panel-footer:empty {
    display: none;
}


/* --------------------------------------------------------------------------
   D5. PANEL SURFACE + LIST ROW RHYTHM

   Border colour and shadow match PART 1's tile cards exactly (#e3e7ec, the same
   1px/2px shadow) so the tiles and the panels read as one system.

   BORDER COLOUR IS SET PER SIDE. See conflict 3 in this part's header — the
   `border-color` shorthand would wipe out `.panel-accent-*`'s top colour.

   List rows: the bundle has `padding:4px 10px`, which is both cramped vertically
   and 5px out of alignment with the heading's 15px horizontal padding, so the
   panel had two different left edges down its length. 9px/15px fixes both.
   -------------------------------------------------------------------------- */

#main-body .client-home-panels .panel {
    border-right-color: #e3e7ec;
    border-bottom-color: #e3e7ec;
    border-left-color: #e3e7ec;
    border-radius: 4px;
    -webkit-box-shadow: 0 1px 2px rgba(16, 24, 40, .05);
            box-shadow: 0 1px 2px rgba(16, 24, 40, .05);
}

#main-body .client-home-panels .panel > .list-group .list-group-item {
    padding: 9px 15px;
    border-color: #f0f0f0;
    /* a long domain or product name must wrap, never punch out of a 50% column */
    word-wrap: break-word;
    overflow-wrap: break-word;
}


/* --------------------------------------------------------------------------
   D6. THE DOMAIN NAME ON ACTIVE PRODUCTS/SERVICES  (user complaint U1)

   U1 is NOT a missing-markup problem and does NOT need a hook. The parent's
   six/includes/active-products-services-item.tpl:16 already emits
       <span class="text-domain">{$service->domain}</span>
   the child does not override that template (its includes/ holds only navbar.tpl
   and sidebar.tpl), and `.text-domain{font-size:12px;color:#006687}` IS present
   in the served bundle. The domain has been in the DOM the whole time.

   THE ACTUAL CAUSE, from the served bundle:
       .div-service-name{flex:1;min-width:0;display:flex;flex-direction:column;...}
       .div-service-name>span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
   The row is already a two-line column layout, but every span in it is
   `nowrap + ellipsis`. Inside a col-sm-6 panel, sharing the row with
   `.div-service-status` and `.div-service-buttons`, the name column is narrow
   enough that the domain is ellipsised away to nearly nothing — which is exactly
   what "does not show the domain name" looks like from the outside.

   Fix: let the domain WRAP instead of being truncated. Applied only to
   `.text-domain`, so the product-name line above it keeps its single-line ellipsis
   and the row stays visually tidy. (1,3,1) beats `.div-service-name>span` (0,1,1).
   Row height growing is now harmless — D1 removed the 170px cap, and agent C's
   backport caps the list at 4 rows with a View More button.

   Upstream's 12px/#006687 is kept (6.5:1 on white); only the truncation changes.
   -------------------------------------------------------------------------- */

#main-body .client-home-panels .div-service-name > span.text-domain {
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
    word-wrap: break-word;
    overflow-wrap: break-word;
    /* Progressive enhancement, must stay AFTER break-word: `anywhere` also lets
       the flex item's min-content size shrink, which `break-word` does not, so a
       long unbroken free-hosting subdomain (user123.byethost7.com — the typical
       value on this install) can actually reflow inside a col-sm-6 panel instead
       of forcing the column wider. Browsers that don't know the keyword drop this
       one declaration and keep break-word. */
    overflow-wrap: anywhere;
    line-height: 1.35;
}

/* CONFIRMED BY AGENT E, who traced it end-to-end: the amplifier here is
   six/css/styles.css:4160-4174, a `@media (min-width:768px)` block that swaps the
   buttons column from compact icons to FULL TEXT labels. That is authored for a
   FULL-WIDTH panel; inside col-sm-6 it eats 150-270px and is worst at 768-991px.

   E proposed also re-asserting the compact-icon treatment inside
   .client-home-panels to reclaim that width. NOT SHIPPED, for three reasons:
     1. As specified it would produce EMPTY BUTTONS. The same upstream block also
        contains `.div-service-buttons i:not(.fa-spinner){display:none}` — at
        >=768px the icons are hidden BECAUSE the text is shown. Hiding the text
        without explicitly re-showing the icon leaves a button with no content.
     2. E flagged that core may mark this panel `colspan` (full width) and that the
        child template dropped colspan support, which agent B is restoring. If so
        the panel gets its intended full width and this is moot.
     3. It overrides a deliberate upstream desktop design, which is a bigger call
        than U1 needs — the wrap above already makes the domain visible.
   FOLLOW-UP: revisit once B confirms colspan. If it is still wanted, it needs the
   icon re-shown in the same rule, not just the label hidden. */


/* --------------------------------------------------------------------------
   D6b. "DOMAINS EXPIRING SOON" (U2) — INERT UNTIL AGENT E'S HOOK IS INSTALLED

   Agent E's ClientAreaHomepagePanels hook is written but NOT installed — writing
   to includes/hooks/ was blocked by E's permissions and E has correctly routed
   that to the user rather than working around it. Nothing here is a substitute
   for that hook and nothing here installs it.

   These two selectors match nothing today, so shipping them is free. The reason
   to ship them now rather than later: if the hook lands with no CSS in place, both
   spans are bare inline elements and the row renders as
   "example.comExpires 12 Sep 2026" with no separation — which would look like a
   new bug. This makes the hook correct on arrival.

   Markup contract, quoted from E verbatim (labels are echoed raw, so the hook
   emits its own markup; domain is htmlspecialchars-escaped by E):
       <i class="far fa-clock" aria-hidden="true"></i>
       <span class="ca-item-domain">example.com</span>
       <span class="ca-item-meta">Expires 12 Sep 2026</span>
   on a `.list-group-item` carrying `.ca-expiring-domain`.

   NOTE the role difference from D6 above: here `.ca-item-domain` is the PRIMARY
   text, not a subtitle, so it is left at inherited size/weight and only the meta
   line is demoted. Scoped to `.ca-expiring-domain` so it can never leak into the
   Active Products rows, which use `.text-domain` and the opposite hierarchy.
   -------------------------------------------------------------------------- */

#main-body .client-home-panels .ca-expiring-domain .ca-item-domain {
    word-wrap: break-word;
    overflow-wrap: break-word;
    overflow-wrap: anywhere;
}

#main-body .client-home-panels .ca-expiring-domain .ca-item-meta {
    display: block;
    margin-top: 1px;
    font-size: 11px;
    line-height: 1.35;
    color: #7b8794;
}


/* --------------------------------------------------------------------------
   D7. FIXED-HEADER CLEARANCE  —  replaces custom.css:48's flat 67px

   `section#main-menu` is the only spacer between the fixed navbar and
   `#main-body`, and 67px did not match the navbar at ANY width. The navbar height
   is deterministic because the logo is a fixed-size PNG (logo.png, 240x75):

     >1024px : .navigation margin-top 3  + .logo padding 8 + img 55 + padding 8
               + .navbar-fixed-top bottom border 1                        = 75px
               -> 67px left an 8px OVERLAP; the navbar covered the top of the strip.
     <=1024px: assets/css/style.css:1206 drops .logo img to max-height:45px
               3 + 8 + 45 + 8 + 1                                          = 65px
               -> 67px left a 2px GAP. The defect inverted across the breakpoint.
     <=768px : assets/css/style.css:1292 adds .navbar-header border-bottom 1px
               65 + 1                                                      = 66px

   Same selector as custom.css:48, so this wins on source order, and it wins in
   both cache states: these rules exist only in the busted copy at cascade
   position 4, which is after the un-busted copy at position 2 either way.

   BELOW 991px the border is removed. custom.css:311 hides `#nav.navbar-main` but
   not its `section#main-menu` parent, so the section renders as nothing but its
   own 1px bottom rule — a stray full-width grey line floating above the tiles on
   every phone. The margin-top is NOT removed there: it is the fixed header's
   clearance and is load-bearing.
   -------------------------------------------------------------------------- */

/* Each rule declares the constant FIRST, then the measured value. Browsers
   without custom-property support take the constant and ignore the second
   declaration; browsers with support use assets/js/nav-height.js's measurement
   and fall back to the same constant if the script did not run. Behaviour is
   therefore identical to the pre-JS version in every failure mode. The
   constants must stay per-breakpoint: a single shared fallback would be wrong
   at 1024px and below, where the logo caps to 45px. */
section#main-menu {
    margin-top: 75px;
    margin-top: var(--nav-h, 75px);
}

@media (max-width: 1024px) {
    section#main-menu {
        margin-top: 65px;
        margin-top: var(--nav-h, 65px);
    }
}

@media (max-width: 991px) {
    /* the nav inside is display:none here, so this element is now only a rule */
    section#main-menu {
        border-bottom: 0;
    }
}

@media (max-width: 768px) {
    section#main-menu {
        margin-top: 66px;
        margin-top: var(--nav-h, 66px);
    }
}


/* --------------------------------------------------------------------------
   D8. FOCUS RINGS, SITE-WIDE  —  overriding assets/css/style.css:60-73

       a       . . . . . outline: none;                    -- specificity (0,0,1)
       a:focus . . . . . outline: none; color: #000;        -- specificity (0,1,1)

   NB: those two lines are written without braces or comment markers on purpose.
   CSS comments do NOT nest, so an inner close-delimiter would terminate THIS
   comment early and turn the quoted `a:focus` line into a live rule — which would
   silently re-break the exact bug this section exists to fix.

   Those declarations removed every focus indicator on the site, with no replacement — `a:focus` only
   changed the colour to #000 against a #45464b default, which is imperceptible.
   That is a WCAG 2.4.7 failure on every link on the page, and it matters more now
   that agent B has removed the tile `onclick` and made the anchor the only control.

   This block loads at cascade position 4, after style.css at position 3, and ties
   it on specificity — later wins. Agent A's tile and search-field rings
   deliberately out-specify this and are the intended treatment for those two
   controls; this is the floor for everything else.

   PROGRESSIVE ENHANCEMENT: the plain `:focus` ring is unconditional. Only inside
   `@supports selector(:focus-visible)` is it withdrawn and re-applied for keyboard
   focus alone. A browser that supports neither keeps the always-on ring. The
   failure mode is a ring too often, never no ring. `:focus-visible` is never
   comma-joined to a plain `:focus` selector — one unknown selector invalidates the
   whole rule, which would silently delete the fallback.
   -------------------------------------------------------------------------- */

a:focus,
button:focus,
input:focus,
select:focus,
textarea:focus,
summary:focus,
[tabindex]:focus {
    outline: 2px solid #0e5077;
    outline-offset: 2px;
}

/* List rows sit flush with the panel's side borders, so a +2px ring would spill
   outside the panel. Inset it instead. */
#main-body .client-home-panels .list-group-item:focus {
    outline-offset: -2px;
}

/* #0e5077 on the navy navbar would be invisible. White is 9.7:1 there. */
.navbar-main .navbar-nav > li > a:focus,
.topbar .top-menu a:focus {
    outline-color: #fff;
}

@supports selector(:focus-visible) {
    a:focus,
    button:focus,
    input:focus,
    select:focus,
    textarea:focus,
    summary:focus,
    [tabindex]:focus {
        outline: 0;
        outline-offset: 0;
    }

    a:focus-visible,
    button:focus-visible,
    input:focus-visible,
    select:focus-visible,
    textarea:focus-visible,
    summary:focus-visible,
    [tabindex]:focus-visible {
        outline: 2px solid #0e5077;
        outline-offset: 2px;
    }

    #main-body .client-home-panels .list-group-item:focus-visible {
        outline-offset: -2px;
    }

    .navbar-main .navbar-nav > li > a:focus-visible,
    .topbar .top-menu a:focus-visible {
        outline-color: #fff;
    }
}


/* --------------------------------------------------------------------------
   D9. STICKY-FOOTER HACK — the conservative correction

   assets/css/style.css:34-46 implements the classic Ryan Fault sticky footer:
       html, body       { height: 100%; }
       .wrapper_content { min-height: 100%; padding-bottom: 354px; }
       .wrapper_footer  { margin-top: -354px; }   <- and NO height

   The construction is only correct when the footer is exactly the reserved
   height. `.wrapper_footer` was never given one, so the 354px is an unbacked
   assertion.

   CORRECTION TO MY OWN EARLIER AUDIT, stated plainly: I previously reported this
   as an active "dead white band". It is not, today. Measured against the real
   markup — .footer-get-started ~109px, .footer-parts 40px padding + a 7-item
   column at 25px line-height + h5 ~= 305px, .bottom-footer ~53px — the footer is
   roughly 467px on desktop and taller still on mobile, where the col-md-3 columns
   restack. Because it already exceeds 354px at every breakpoint, the negative
   margin and the padding currently cancel out and nothing is visibly wrong.

   So this is inoculation against a latent defect, not a repair. It is two
   declarations, changes no layout today, and cannot regress: `min-height` only
   binds if the footer ever shrinks below the reserved space (someone trimming a
   footer menu column would be enough), and the background means that if it ever
   does bind, the reserved strip reads as footer rather than as a white band —
   `.wrapper_footer` is otherwise transparent, so `min-height` alone would have
   produced empty white space and fixed nothing.

   The negative margin and the padding are deliberately left untouched: this
   affects every page on the site, and rewriting a working sticky footer to chase
   a defect that is not currently visible is not worth the blast radius.
   -------------------------------------------------------------------------- */

.wrapper_footer {
    min-height: 354px;
    background-color: #1b1c1f;   /* == #footer, so any bound strip is not white */
}


/* =============================================================================
   PART 3 of 3 — AGENT C — SURGICAL BACKPORT FROM six/css/styles.css (2025)
   =============================================================================
   The child's css/all.min.css is a verbatim 2023 fork of the parent bundle with
   zero customisation, so it is missing selectors the parent has gained since.
   Confirmed absent from the served child bundle by the integrator, not just
   asserted:
       grep -c sitejet             ifastnet-child/css/all.min.css -> 0
       grep -c btn-view-more       ifastnet-child/css/all.min.css -> 0
       grep -c "Active Products"   ifastnet-child/css/all.min.css -> 0
       grep -c registerDomainPanel ifastnet-child/css/all.min.css -> 0
   Every rule below was diffed against the parent source line ranges cited in its
   comment and matches, apart from the `gap` substitutions, which are flagged.

   Placed LAST at agent C's request so the #registerDomainPanel flex rules land
   after PART 2's panel column-flex. They nest two levels inside it, touch none of
   `.panel` / `.panel-body` / `.panel-footer`, and do not tie with anything above.
   ========================================================================== */


/* -----------------------------------------------------------------------------
   C1. SITEJET PANEL  (user complaint U3)
   -----------------------------------------------------------------------------
   Nothing matching "sitejet" exists in the served bundle, so the two child divs
   of six/includes/sitejet/homepagepanel.tpl stacked as plain blocks at every
   width — 224px against the bundle's 170px cap, which is the scrollbar the user
   reported. D1 removed the cap; this gives the panel its intended layout.

   NOTE ON `gap`: upstream uses `gap:20px`. Per the agreed design direction (no
   flex gap — Safari <14.1 drops it silently) it is replaced by margins on the
   preview item, reproducing the identical 20px gutter for this two-item layout in
   every browser. This is the only deviation from upstream in this block.
   -------------------------------------------------------------------------- */

/* from six/css/styles.css:4176-4181 — lays the panel out; upstream `gap:20px` replaced by margins */
.sitejet-panel-container {
    display: -webkit-flex;
    display: flex;
    -webkit-flex-wrap: wrap;
            flex-wrap: wrap;
    margin: 10px 15px 20px 15px;
}

/* replaces upstream `gap:20px` on the container — horizontal gutter, side-by-side */
.sitejet-preview-item {
    margin-right: 20px;
}

/* from six/css/styles.css:4182-4185 — lets the select+button column take the remaining width */
.sitejet-panel-container .sitejet-actions-item {
    display: -webkit-flex;
    display: flex;
    -webkit-flex: 1 1 60%;
            flex: 1 1 60%;
}

/* from six/css/styles.css:4186-4191 — below 767px preview and actions each take a full row */
@media (max-width: 767px) {
    .sitejet-panel-container .sitejet-preview-item,
    .sitejet-panel-container .sitejet-actions-item {
        -webkit-flex-basis: 100%;
                flex-basis: 100%;
        display: -webkit-flex;
        display: flex;
        -webkit-justify-content: center;
                justify-content: center;
    }
    /* replaces upstream `gap:20px` — vertical gutter once the items have wrapped */
    .sitejet-panel-container .sitejet-preview-item {
        margin-right: 0;
        margin-bottom: 20px;
    }
}

/* NOT UPSTREAM (a): homepagepanel.tpl:15 sets `min-width:250px` inline on the
   select+button row. Without min-width:0 that flex item's automatic minimum size
   is content-based, so it refuses to shrink and pushes the panel-body into a
   HORIZONTAL scrollbar on a narrow col-sm-6 panel. A second, independent
   contributor to U3's "uses a scroll bar" that the 170px cap was masking. */
.sitejet-panel-container .sitejet-actions-item {
    min-width: 0;
}

/* NOT UPSTREAM (b): the preview <img> carries only `max-width:100%`, so a wide
   preview can crowd the actions column out. Cap it so the split stays near 40/60. */
@media (min-width: 768px) {
    .sitejet-panel-container .sitejet-preview-item {
        max-width: 40%;
    }
}

/* NOT UPSTREAM (c): SAFARI <14.1 FLEX-GAP FALLBACK for the INLINE
   `display:flex;gap:6px` at six/includes/sitejet/homepagepanel.tpl:15. That gap
   is in an inline style attribute no stylesheet can edit, and browsers without
   flex-gap drop it silently, butting the select against the button with 0px
   between them. Zero the inline gap everywhere and re-create it with a margin, so
   the spacing is exactly 6px in every browser rather than 6px in some and 0px in
   others. The !important is required to beat an inline style; the margin needs
   none, because the inline style does not set one. */
.sitejet-actions-item > div > div[style*="flex"] {
    gap: 0 !important;
}
#sitejetServiceSelect {
    margin-right: 6px;
}


/* -----------------------------------------------------------------------------
   C2. ACTIVE PRODUCTS/SERVICES — "show 4 + View More"
   -----------------------------------------------------------------------------
   Verbatim from six/css/styles.css:4065-4083. The !important flags are upstream's
   and MUST be kept: this selector is (0,2,1) while the bundle's
   `.client-home-panels .panel>.list-group` is (0,3,0) and would otherwise win.

   ATTRIBUTE CASE: lowercase `menuitemname` is correct even though
   clientareahome.tpl emits camelCase `menuItemName=`. The HTML parser
   ASCII-lowercases attribute names and CSS attribute-name matching is
   case-insensitive for HTML elements in an HTML document. Shipping WHMCS already
   bets on this — six/js/scripts.min.js contains
   `jQuery('div[menuitemname="Active Products/Services"] ...')` and that handler
   works today. Defined in the lowercase form ONLY; do not double-define.

   THE VIEW-MORE BUTTON IS NOT A DEAD END — verified before shipping the
   truncation, because hiding rows with no way to reveal them would have been a
   worse regression than the scrollbar. six/includes/head.tpl:31 loads
   `{assetPath file='scripts.min.js'}`; there is no ifastnet-child/js/ directory,
   so that resolves to the PARENT six/js/scripts.min.js (mtime 2025-07-07, i.e.
   NOT stale — only css/all.min.css was forked into the child).
   `grep -c btn-view-more six/js/scripts.min.js` -> 1. The handler reveals 8 per
   click, disables itself when the pool empties, and redraws the bottom border on
   the last visible row.

   `border-bottom:0px !important` is load-bearing: the JS applies an inline bottom
   border to the last VISIBLE item, so without it you get two borders.

   n+5 (four visible rows) is upstream's value and is kept. The rows are two-line
   today — see D6 — and upstream authored this cut against exactly that row shape.
   -------------------------------------------------------------------------- */

/* from six/css/styles.css:4065-4069 */
div[menuitemname='Active Products/Services'] .list-group {
    overflow: initial !important;
    max-height: initial !important;
    border-bottom: 0px !important;
}

/* from six/css/styles.css:4070-4072 — the "show only the first 4" half of the design */
div[menuitemname='Active Products/Services'] .list-group .list-group-item:nth-child(n+5) {
    display: none;
}

/* from six/css/styles.css:4073-4075 — tightens the footer holding the View More button */
div[menuitemname='Active Products/Services'] .panel-footer {
    padding: 4px 15px;
}

/* from six/css/styles.css:4076-4078 */
div[menuitemname='Active Products/Services'] .btn-view-more {
    font-size: 12px;
}

/* from six/css/styles.css:4079-4083 — spent state, set by the JS when nothing is left to reveal */
div[menuitemname='Active Products/Services'] .btn-view-more.disabled {
    cursor: default;
    text-decoration: none;
    color: #6c757d;
}


/* -----------------------------------------------------------------------------
   C3. REGISTER A NEW DOMAIN PANEL — verbatim from six/css/styles.css:655-676.
   Without these, Bootstrap 3's `.input-group` table layout mis-sizes the field
   and the button inside a col-sm-6 panel.
   -------------------------------------------------------------------------- */

/* from six/css/styles.css:655-658 — flex instead of BS3's display:table so field and button can wrap */
.client-home-panels #registerDomainPanel .panel-body .input-group {
    display: -webkit-flex;
    display: flex;
    -webkit-flex-wrap: wrap;
            flex-wrap: wrap;
}

/* from six/css/styles.css:660-664 — min-width:0 lets the field shrink instead of overflowing */
.client-home-panels #registerDomainPanel .panel-body .input-group .form-control {
    -webkit-flex: 1 1 40%;
            flex: 1 1 40%;
    min-width: 0;
    width: auto;
}

/* from six/css/styles.css:666-671 — keeps the TLD select and Search button on one line */
.client-home-panels #registerDomainPanel .panel-body .input-group-btn {
    display: -webkit-flex;
    display: flex;
    -webkit-flex: 1 1 auto;
            flex: 1 1 auto;
    -webkit-flex-wrap: nowrap;
            flex-wrap: nowrap;
    width: auto;
}

/* from six/css/styles.css:673-675 — lets the Search input share the remaining space */
.client-home-panels #registerDomainPanel .panel-body .input-group-btn input {
    -webkit-flex: 1 1 auto;
            flex: 1 1 auto;
}


/* -----------------------------------------------------------------------------
   C4. `.d-none` AND FRIENDS — DELIBERATELY OMITTED. DO NOT ADD.
   Upstream has only `.d-none{display:none}` (six/css/styles.css:4195), with no
   !important and none of the responsive tiers. custom.css:173-200 above already
   carries a hand-written shim that is a strict superset, with the d-sm-/d-md-/
   d-lg- tiers deliberately mapped to Bootstrap 3's 768/992/1200 breakpoints
   rather than Bootstrap 4's 576/768/992 (rationale at custom.css:152-161).
   Re-adding upstream's version would be a no-op at best and misleading at worst.
   RECONCILIATION = leave custom.css:128-200 exactly as it is.
   -------------------------------------------------------------------------- */

/* =============================================================================
   D10. REPAIR: `.d-none` HAS BEEN DEAD SINCE 2026-08-02
   =============================================================================
   FOUND INCIDENTALLY while brace-checking this file. Not part of the dashboard
   brief, but it is a live production bug on the CHECKOUT page and the fix is one
   additive rule, so it is repaired here rather than left to rot.

   WHAT IS WRONG
   -------------
   The explanatory comment block at custom.css:128-172 contains, on line 164, a
   reference to the two responsive utility classes written as an abbreviated pair:
   the token "d-md-" plus a star, immediately followed by a slash, then "d-lg-"
   plus a star. Read the raw line with `sed -n '164p' custom.css` — it is NOT
   reproduced literally here, for the reason given at the bottom of this note.

   A star immediately followed by a slash is the comment CLOSE delimiter. CSS
   comments do not nest and provide no escaping mechanism, so that sequence ends
   the comment 36 lines earlier than its author intended. (Line 163's
   "templates/six/store/" plus a star is harmless by comparison — an OPEN delimiter
   inside an already-open comment is just text.)

   Everything from `d-lg-* WITHOUT a BS3` through the intended terminator on line
   172 is therefore parsed as CSS, not as prose. The parser reads it as the prelude
   of a qualified rule and keeps accumulating until the next `{` — which is the one
   belonging to `.d-none`. So the effective rule is:

       <36 lines of English prose> .d-none { display: none !important; }

   That prelude contains an apostrophe (`BS4's`) which opens a string that hits a
   newline, producing a <bad-string-token>, plus stray semicolon and close-comment
   tokens (again, not written literally here — see the note below). The
   selector is invalid, and per CSS error recovery an invalid selector discards the
   ENTIRE rule — including its declaration block.

   NET EFFECT: `.d-none` is not defined. Verified it exists nowhere else that is
   actually served (`grep -c '\.d-none'` -> 0 in both ifastnet-child/css/all.min.css
   and ifastnet-child/assets/css/style.css). `.d-inline`, `.d-inline-block` and
   `.d-block` on the following lines parse cleanly and are unaffected, as are all
   three `@media` tiers — `.d-sm-block` and friends work. Only `.d-none` is lost,
   which is the worst possible one to lose: it is the "hide" half of every
   Bootstrap 4 `d-none d-sm-block` pair.

   LIVE CONSEQUENCES (133 `d-none` occurrences across the active templates)
   - templates/orderforms/standard_cart/checkout.tpl:43 renders
       <div class="alert alert-danger checkout-error-feedback {if !$errormessage}d-none{/if}">
     so with `.d-none` undefined the checkout page shows a permanently visible,
     EMPTY red "Please correct the following errors" box. That is precisely the
     symptom the 2026-08-02 comment says it was written to fix — the fix has never
     once worked.
   - checkout.tpl:49 `<li class="vat-error d-none">` likewise.
   - Every `d-none d-sm-*` pair is unhidden BELOW 768px, because the `d-sm-*` half
     survives and the `d-none` half does not.

   WHY THE FIX IS A RE-DECLARATION AND NOT AN EDIT TO THE COMMENT
   Repairing line 164 (inserting one space: `d-md-* / d-lg-*`) would revive the
   original rule, and that is worth doing as a separate reviewed change. But it
   would NOT fix returning visitors for up to 24h: the un-busted copy of this file
   at cascade position 2 would still carry the broken comment and still drop the
   rule. Re-declaring `.d-none` down here fixes it in the busted copy at position
   4, which is later in the cascade and fetched fresh — so it works in BOTH cache
   states, immediately. It is also purely additive, per the standing no-delete rule
   at the top of this section.

   Identical value to the shadowed original, so reviving line 173 later is a no-op
   and the two can never disagree.
   -------------------------------------------------------------------------- */

.d-none { display: none !important; }

/* ############ END CLIENT AREA HOME REDESIGN — 2026-08-11 ############ */
