/* ============================================================================
   Vantage Client Area — Layout v2
   ----------------------------------------------------------------------------
   Loaded AFTER custom.css, so it overrides by cascade order rather than by
   !important wherever possible. Nothing here is destructive: removing the
   <link> in includes/head.tpl restores the previous layout exactly.

   Problems this fixes, observed on the dashboard:
   1. The content area sat inside a constrained container, so with the 280px
      nav rail taking space the dashboard's `2fr 1fr` grid collapsed its
      second column to ~145px. Card content then overlapped — the invoice
      amount printed on top of the due date, service names truncated to
      "access.19pa...".
   2. There was no right-hand context rail, so account/status information had
      to compete for the same cramped column.
   Design intent, carried over from the proposal surface on :4188:
      [ nav 280 ][ content 1fr (min 0) ][ inspector 320 ]
   full-bleed width, and columns that are allowed to wrap rather than crush.
   The footer is deliberately left in the theme's own normal flow — see the
   note in section 1.
   ========================================================================== */

:root {
  --vantage-nav-w: 280px;
  --vantage-inspector-w: 320px;
  --vantage-gutter: 24px;
  /* Never let a dashboard column go below this. This single value is what
     prevents the overlapping-text failure above. */
  --vantage-col-min: 320px;
}

/* ---------------------------------------------------------------- 1. Shell */
/* The width cap is Bootstrap's .container, not any vantage-* class. The theme's
   client-area DOM is:
     <div class="container"> <div class="row">
       <div class="col-lg-4 col-xl-3"><div class="sidebar">…
       <div id="main-content" class="col-lg-8 col-xl-9 primary-content">…
   so full-bleed means overriding that one container — scoped with :has() so the
   header and breadcrumb containers keep their own alignment. */
.container:has(> .row > #main-content) {
  max-width: none;
  width: 100%;
  padding-left: 22px;
  padding-right: 22px;
}

/* Replace Bootstrap's fixed 25/75 split with :4188's `280px 1fr`: a fixed nav
   rail and a fluid work surface. Below xl the theme's own stacking applies. */
@media (min-width: 1200px) {
  .container:has(> .row > #main-content) > .row > [class*="col-xl-3"] {
    flex: 0 0 var(--vantage-nav-w);
    max-width: var(--vantage-nav-w);
    width: var(--vantage-nav-w);
  }
  .container:has(> .row > #main-content) > .row > #main-content {
    flex: 1 1 0%;
    max-width: none;
    width: auto;
    min-width: 0;
  }
}

/* Fallback for engines without :has() — slightly broader, same intent. */
@supports not selector(:has(*)) {
  #main-content { max-width: none; }
}

/* NOTE: an earlier revision made <body> a flex column and set the footer to
   position:sticky; bottom:0. That was wrong twice over — `sticky` pins the
   footer to the viewport bottom *while the page scrolls*, so it floated over
   the dashboard mid-page, and re-flexing <body> disturbed a layout this theme
   builds with its own containers. Both rules are removed. The footer keeps
   the theme's own normal-flow behaviour. */

/* ------------------------------------------------- 2. Dashboard grid rebuild */
/* The core fix. `minmax(0, …)` lets the wide column shrink; the fixed floor on
   the second column stops it collapsing. auto-fit means it wraps to one column
   on its own, so the media query below is a refinement, not a crutch. */
/* Column assignment is explicit rather than DOM-order dependent.
   .vantage-dashboard-main   holds Your Services + Recent Invoices
   .vantage-dashboard-sidebar holds Support Tickets + Quick Actions
   Tickets are the actionable surface, so they take the wide column and the
   services/invoices summary becomes the right-hand context rail — matching the
   proposal surface on :4188 (nav | work surface | inspector). */
.vantage-dashboard-grid {
  display: grid;
  grid-template-columns: minmax(0, 2.2fr) minmax(var(--vantage-col-min), 1fr);
  grid-template-areas: "surface rail";
  gap: var(--vantage-gutter);
  align-items: start;
}
.vantage-dashboard-sidebar { grid-area: surface; }
.vantage-dashboard-main    { grid-area: rail; }

/* Stack before the columns get uncomfortable rather than at an arbitrary
   device width. 1180px is where the 320px floor starts to squeeze the main
   column below a readable measure. */
@media (max-width: 1180px) {
  .vantage-dashboard-grid {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "surface" "rail";
  }
}

.vantage-dashboard-main,
.vantage-dashboard-sidebar { min-width: 0; }

/* Right rail behaves like the :4188 inspector: sticks while the main column
   scrolls, scrolls internally when it is taller than the viewport. */
@media (min-width: 1181px) {
  .vantage-dashboard-main {
    position: sticky;
    top: 84px;
    max-height: calc(100vh - 108px);
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
  }
  .vantage-dashboard-main::-webkit-scrollbar { width: 8px; }
  .vantage-dashboard-main::-webkit-scrollbar-thumb {
    background: var(--vantage-border, var(--secondary));
    border-radius: 4px;
  }
}

/* ------------------------------------------------------- 3. Card contents */
/* The overlapping amount/date was a flex row with no wrapping and no min-width.
   Let rows wrap and let children shrink. */
.vantage-card-row,
.vantage-invoice-row,
.vantage-service-row,
.vantage-account-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
  min-width: 0;
}
.vantage-card-row > *,
.vantage-invoice-row > *,
.vantage-service-row > *,
.vantage-account-row > * { min-width: 0; }

/* Amounts stay on one line and align right; everything else may wrap. */
.vantage-invoice-amount,
.vantage-amount,
.vantage-price {
  white-space: nowrap;
  margin-left: auto;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

/* Long identifiers (domains, hostnames, refs) truncate with a tooltip rather
   than pushing the layout. */
.vantage-service-domain,
.vantage-truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100%;
  display: block;
}

/* Card headers were wrapping to two lines in the narrow column ("Your
   Services" breaking after "Your"). Give them room and stop the wrap. */
.vantage-card-header,
.vantage-panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-width: 0;
}
.vantage-card-title,
.vantage-panel-title {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

/* -------------------------------------------------------- 4. Stat tiles */
/* Auto-fit so four tiles never crush; they reflow to 2x2 then 1 column. */
.vantage-stats,
.vantage-stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 16px;
}

/* --------------------------------------------------------- 5. Quick actions */
.vantage-quick-actions,
.vantage-actions-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 12px;
}

/* ------------------------------------------------------------- 6. Density */
/* Slightly tighter vertical rhythm so more fits above the fold now that the
   columns are wider. */
.vantage-card,
.vantage-panel { margin-bottom: var(--vantage-gutter); }
.vantage-card:last-child,
.vantage-panel:last-child { margin-bottom: 0; }

/* ------------------------------------------------------------- 7. Print */
@media print {
  .vantage-sidebar,
  .vantage-footer,
  .vantage-dashboard-sidebar { display: none !important; }
  .vantage-dashboard-grid { grid-template-columns: 1fr; }
}

/* --------------------------------------------- 8. Reduced motion / a11y */
@media (prefers-reduced-motion: reduce) {
  .vantage-dashboard-sidebar { scroll-behavior: auto; }
}

/* ============================================================================
   9. Order forms / store
   ----------------------------------------------------------------------------
   The templates under templates/orderforms/* were never themed — they ship with
   hardcoded light values (#fff, #f8f8f8, #f2f2f2) and Bootstrap's green success
   button, which read as broken against the dark Vantage theme: a white product
   card, a black price block, and a green CTA.

   These rules re-skin those surfaces with the existing tokens. Scoped to the
   order-form containers so nothing else inherits them. !important is used
   sparingly and only where the shipped rule is equally specific.
   ========================================================================== */

#order-standard_cart,
#order-boxes,
#order-premium_comparison,
#order-slider,
.order-form-container,
#main-body .products,
.product-group-container {
  color: var(--vantage-text, var(--foreground));
}

/* Product cards ---------------------------------------------------------- */
#order-standard_cart .product,
#order-boxes .product,
.product-group-container .product,
#main-body .products .product,
.product-box,
.pricing-plan {
  background: var(--vantage-background-card, var(--card)) !important;
  border: 1px solid var(--vantage-border, var(--border)) !important;
  border-radius: 10px;
  overflow: hidden;
  color: var(--vantage-text, var(--foreground));
}

/* Card headers were light panels with dark text. */
#order-standard_cart .product header,
#order-boxes .product header,
.product-box header,
.product .product-name,
.pricing-plan .plan-name {
  background: var(--vantage-secondary, var(--secondary)) !important;
  border-bottom: 1px solid var(--vantage-border, var(--border)) !important;
  color: var(--vantage-text, var(--foreground)) !important;
  font-weight: 600;
}

/* Stage C 2026-07-31 layout restyle: `.panel-heading` used to be the last
   selector in the group ABOVE, sharing its `--vantage-secondary` fill. Split
   out because the two want different things now: store product/plan tiles
   keep the tinted header (that is the intended product-tile treatment),
   while portal panel headings move to --card so they read as a
   hairline-separated band.

   This is also the rule that ACTUALLY won on every panel heading in the
   portal -- it ties custom.css's `.panel-heading` on specificity (0,1,0) and
   both are !important, so source order decided and this file loads later.
   Changing only custom.css left every heading still measuring rgb(26,26,37)
   live on cart.php. */
.panel-heading {
  background: var(--vantage-background-card, var(--card)) !important;
  border-bottom: 1px solid var(--vantage-border, var(--border)) !important;
  color: var(--vantage-text, var(--foreground)) !important;
  font-weight: 600;
}

/* The price block rendered as black-on-white. */
.product .product-pricing,
.product-box .price,
.pricing-plan .plan-price,
.product-pricing {
  background: transparent !important;
  color: var(--vantage-link) !important;
  font-variant-numeric: tabular-nums;
}
.product .product-pricing .price,
.product-pricing span.price {
  color: var(--vantage-link) !important;
}

/* Body copy inside cards. */
.product .product-desc,
.product ul,
.product li,
.product-box p,
.pricing-plan li {
  color: var(--vantage-text-muted, var(--muted-foreground)) !important;
}

/* CTA: Bootstrap success green -> Vantage gold, to match every other primary
   action in the portal. */
#order-standard_cart .btn-success,
#order-boxes .btn-success,
.product .btn-success,
.product-box .btn-success,
.pricing-plan .btn-success,
.order-button.btn-success {
  background: var(--vantage-primary, #c9a227) !important;
  border-color: var(--vantage-primary, #c9a227) !important;
  color: var(--vantage-primary-foreground, #0d0d0d) !important;
  font-weight: 600;
}
#order-standard_cart .btn-success:hover,
.product .btn-success:hover,
.product-box .btn-success:hover,
.pricing-plan .btn-success:hover {
  filter: brightness(1.08);
  color: var(--vantage-primary-foreground, #0d0d0d) !important;
}

/* Category / actions panels in the store sidebar. */
#order-standard_cart .panel,
.order-form-container .panel,
#main-body .panel {
  background: var(--vantage-background-card, var(--card)) !important;
  border: 1px solid var(--vantage-border, var(--border)) !important;
}
#order-standard_cart .list-group-item,
.order-form-container .list-group-item {
  background: transparent !important;
  border-color: var(--vantage-border, var(--border)) !important;
  color: var(--vantage-text-muted, var(--muted-foreground)) !important;
}
#order-standard_cart .list-group-item.active,
.order-form-container .list-group-item.active {
  background: var(--vantage-primary, #c9a227) !important;
  color: var(--vantage-primary-foreground, #0d0d0d) !important;
  border-color: var(--vantage-primary, #c9a227) !important;
  font-weight: 600;
}

/* Any residual light surface inside the store area. */
#main-body .well,
#main-body .card,
.order-form-container .well {
  background: var(--vantage-background-card, var(--card)) !important;
  border-color: var(--vantage-border, var(--border)) !important;
  color: var(--vantage-text, var(--foreground)) !important;
}

/* ============================================================================
   10. Client-area subpages (product details, services, invoices, quotes,
       ticket view)
   ----------------------------------------------------------------------------
   Exemplar defect (product details, WHMCS v8.7.3 Twenty-One stock template):
     1. Product name renders in `.card-header`/`.panel-heading` <h3>, which
        ships with Bootstrap's light-grey header background. Something
        upstream already sets client-area headings to white for the dashboard
        cards, so on this *unthemed* header the name goes white-on-light-grey
        -> invisible. Worst issue; fixed structurally in 10.1/10.2 by theming
        the header surface itself rather than patching the text colour alone.
     2. The product image column is WHMCS's stock "no image" placeholder: a
        light-grey box with a white circular icon, unthemed. 10.3 wraps it in
        an intentional dark frame instead of trying to recolour raster/SVG
        placeholder content (which would risk mis-colouring a real product
        photo too).
     3. The meta column (Registration Date, First Payment Amount, Recurring
        Amount, Quantity, Billing Cycle, Next Due Date, Payment Method) is the
        stock `.row.text-center > [col-*]` pattern -- each stat a centred
        <p>label</p><p><strong>value</strong></p> pair. 10.4 re-flows it into
        a left-aligned, themed label/value stack.
     4. None of it inherits the dark Vantage surface tokens the dashboard
        cards use. 10.1/10.5 apply the same card/table/list-group re-skin
        already used for order forms (section 9) to #main-content generally,
        so services, invoices, quotes and the ticket view get the same fix
        for the same class of light-on-light regression without needing
        page-specific selectors.

   Everything here is scoped to #main-content, so it cannot reach the admin
   area, and is additive (removing the <link> in includes/head.tpl restores
   the previous, broken appearance exactly). Hedges both the Bootstrap 3
   `.panel*` and Bootstrap 4 `.card*` idioms because Twenty-One's stock
   templates mix vocabulary across pages.
   ========================================================================== */

/* ---- 10.1 Panel / card surfaces -> dark Vantage card ---- */
#main-content .panel,
#main-content .card,
#main-content .well {
  background: var(--vantage-background-card, var(--card));
  border: 1px solid var(--vantage-border, var(--border));
  color: var(--vantage-text, var(--foreground));
  border-radius: 10px;
}
#main-content .panel-heading,
#main-content .card-header {
  /* Stage C 2026-07-31 layout restyle: was `--vantage-secondary`, a tinted
     bar. Now matches the card body so the heading reads as a hairline-
     separated band, consistent with the base .card-header/.panel-heading
     change in custom.css. This ID-specificity rule is what actually WINS on
     every in-content panel -- the class-level rule in custom.css cannot beat
     it -- so the restyle is incomplete without changing it here too
     (confirmed live on cart.php: headings still measured rgb(26,26,37)).
     The explicit `color` is retained: 10.2 exists to guarantee legibility
     regardless of what the page ships, and that requirement is unchanged. */
  background: var(--vantage-background-card, var(--card));
  border-bottom: 1px solid var(--vantage-border, var(--border));
  color: var(--vantage-text, var(--foreground));
}

/* ---- 10.2 Requirement 1: the heading must never depend on an image or a
   light background for legibility. Force it onto the themed header above in
   high-contrast text (WCAG AA), regardless of any inline style or utility
   class shipped by the page. ---- */
#main-content .panel-heading .panel-title,
#main-content .panel-heading h1,
#main-content .panel-heading h2,
#main-content .panel-heading h3,
#main-content .panel-heading h4,
#main-content .card-header .card-title,
#main-content .card-header h1,
#main-content .card-header h2,
#main-content .card-header h3,
#main-content .card-header h4 {
  color: var(--vantage-text, var(--foreground)) !important;
  background: transparent !important;
  text-shadow: none;
  font-weight: 600;
}

/* Status badges in the header keep their own semantic colour (success/
   danger/warning), but Bootstrap's neutral `.label-default`/`.badge-secondary`
   is grey-on-grey against the new dark header and needs a themed floor. */
#main-content .panel-heading .label-default,
#main-content .card-header .label-default,
#main-content .panel-heading .badge-secondary,
#main-content .card-header .badge-secondary {
  background: var(--vantage-secondary, var(--secondary));
  color: var(--vantage-text, var(--foreground));
  border: 1px solid var(--vantage-border, var(--border));
}

/* ---- 10.3 Requirement 2: product image / status block ---- */
/* Give the image's own grid column an intentional themed frame so a bare
   placeholder reads as a designed panel rather than a broken light box. The
   :has() selector targets only a column whose sole content is the image (so
   columns that mix an image with other content are left alone); browsers
   without :has() get the broader, still-non-destructive fallback below. */
#main-content .card-body > .row > [class*="col-"]:has(> img.img-responsive:only-child),
#main-content .panel-body > .row > [class*="col-"]:has(> img.img-responsive:only-child) {
  background: var(--vantage-secondary, var(--secondary));
  border: 1px solid var(--vantage-border, var(--border));
  border-radius: 10px;
  padding: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
}
#main-content img.img-responsive {
  border-radius: 8px;
  max-width: 100%;
}
@supports not selector(:has(*)) {
  #main-content .card-body > .row > [class*="col-"],
  #main-content .panel-body > .row > [class*="col-"] {
    background: var(--vantage-secondary, var(--secondary));
    border-radius: 10px;
  }
}

/* ---- 10.4 Requirement 3: meta column -> left-aligned themed definition
   list ---- */
/* Stock markup: `.row.text-center > [col-*]`, each column a centred
   <p>label</p><p><strong>value</strong></p> pair. Re-flow into a left-aligned
   label/value stack with clear hierarchy -- muted uppercase label, bold
   value -- matching the dashboard's stat-card rhythm, with tabular figures so
   amounts line up. */
#main-content .card-body .row.text-center,
#main-content .panel-body .row.text-center {
  text-align: left;
  row-gap: 16px;
}
#main-content .card-body .row.text-center > [class*="col-"],
#main-content .panel-body .row.text-center > [class*="col-"] {
  text-align: left;
  padding: 12px 16px;
  border-left: 2px solid var(--vantage-border, var(--border));
}
#main-content .card-body .row.text-center > [class*="col-"] p:first-child,
#main-content .panel-body .row.text-center > [class*="col-"] p:first-child {
  margin: 0 0 4px;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--vantage-text-muted, var(--muted-foreground));
}
#main-content .card-body .row.text-center > [class*="col-"] p:last-child,
#main-content .panel-body .row.text-center > [class*="col-"] p:last-child {
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
  color: var(--vantage-text, var(--foreground));
  font-variant-numeric: tabular-nums;
}

/* ---- 10.5 Requirement 4: body copy, tables and list-groups inherit the
   dark surface (services, invoices, quotes, ticket view) ---- */
#main-content .panel-body,
#main-content .card-body,
#main-content .well {
  color: var(--vantage-text, var(--foreground));
}
#main-content .table,
#main-content .table > * {
  color: var(--vantage-text, var(--foreground));
}
#main-content .table > tbody > tr > td,
#main-content .table > tbody > tr > th,
#main-content .table-list > tbody > tr > td {
  border-color: var(--vantage-border, var(--border));
}
#main-content .list-group-item {
  background: transparent;
  border-color: var(--vantage-border, var(--border));
  color: var(--vantage-text, var(--foreground));
}
/* Scoped to inline body copy inside the re-skinned surfaces, not the whole
   of #main-content -- an ID-level `#main-content a` rule would outrank the
   .vantage-btn button classes used throughout the dashboard/sidebar (ID beats
   class in specificity) and could repaint button text to match its own
   background, re-introducing the same low-contrast defect this section
   fixes. .vantage-btn is excluded explicitly as a second guard. */
#main-content .panel-body a:not(.vantage-btn),
#main-content .card-body a:not(.vantage-btn),
#main-content .well a:not(.vantage-btn) {
  color: var(--vantage-link);
}
#main-content .text-muted {
  color: var(--vantage-text-muted, var(--muted-foreground)) !important;
}

/* Amounts inside these re-skinned surfaces (invoice/quote line items, ticket
   metadata) get the same one-line, right-aligned, tabular treatment as the
   dashboard cards in section 3. */
#main-content .card-body .vantage-amount,
#main-content .card-body .vantage-price,
#main-content .table .text-right {
  font-variant-numeric: tabular-nums;
}

/* ---- 10.6 Vantage KB launch action ---- */
/* Rendered only where modules/addons/vantage_kb/hooks.php publishes
   $vantage_kb_launch_url via the ClientAreaPage hook (see
   clientareahome.tpl); the {if} guard there means the anchor is simply
   absent otherwise, so no CSS-side hiding is required. This rule only
   ensures it reads as the primary Vantage action alongside the theme's
   other .vantage-btn instances. */
.vantage-welcome-actions .vantage-btn.vantage-btn-primary[target="_blank"] {
  order: -1;
}

/* ---- 10.7 Print ---- */
@media print {
  #main-content .panel,
  #main-content .card {
    background: #ffffff !important;
    color: var(--foreground) !important;
    border-color: var(--border) !important;
  }
  #main-content .panel-heading,
  #main-content .card-header {
    background: #f5f5f5 !important;
    color: var(--foreground) !important;
  }
  #main-content .panel-heading h1,
  #main-content .panel-heading h2,
  #main-content .panel-heading h3,
  #main-content .card-header h1,
  #main-content .card-header h2,
  #main-content .card-header h3 {
    color: var(--foreground) !important;
  }
}

/* ---- 10.8 Reduced motion ---- */
@media (prefers-reduced-motion: reduce) {
  #main-content .card,
  #main-content .panel {
    transition: none;
  }
}

/* ---- 10.9 Product-details REAL-DOM corrections -------------------------------
   Verified against the live clientareaproductdetails.tpl on web.3vs.io (WHMCS
   8.7.3 Twenty-One). There is NO .card-header on this page: the product name is
   `.product-icon > h3`, the group name is `.product-icon > h4`, and the meta
   column is `.col-md-6.text-center` with <h4> labels + inline value text nodes.
   10.2's .card-header rules therefore no-op here; these target the real markup
   and are the actual fix for the "invisible product name" defect. ---------- */

/* The light placeholder island holding the stacked icon + product name. Theme it
   to a dark surface so the (white) icon and heading are legible. */
#main-content .product-icon {
  background: var(--vantage-secondary, var(--secondary));
  border: 1px solid var(--vantage-border, var(--border));
  border-radius: 10px;
  padding: 24px 16px;
}
#main-content .product-icon h3 {
  color: var(--vantage-text, var(--foreground)) !important;   /* the product name — worst defect */
  margin-top: 10px;
}
#main-content .product-icon h4 {
  color: var(--vantage-text-muted, var(--muted-foreground)) !important;   /* the group name */
}
#main-content .product-icon .fa-stack,
#main-content .product-icon .fa-stack .fa-inverse {
  color: var(--vantage-link);
}
#main-content .product-status-text { color: var(--vantage-text, var(--foreground)); }

/* Meta column: left-align for hierarchy, muted uppercase labels, legible values. */
#main-content .product-details .col-md-6.text-center { text-align: left; color: var(--vantage-text, var(--foreground)); }
#main-content .product-details .col-md-6.text-center h4 {
  color: var(--vantage-text-muted, var(--muted-foreground));
  font-size: .78rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  margin: 16px 0 2px;
  font-weight: 600;
}

/* ================================================================
   STAGE C 2026-07-31 — LAYOUT / CHROME RESTYLE
   ----------------------------------------------------------------
   Colour was already handled by the token pass (report-tokens.css
   [data-theme] blocks). This block changes STRUCTURE only: full-bleed
   chrome, a slim header, and hairline separators in place of card
   chrome. Nothing here references a literal colour — every value is a
   token, so both `strategic` and `vantage-light` inherit it.

   Why this file and not custom.css: custom.css is almost entirely
   `!important`, so a later stylesheet cannot beat it on cascade order
   alone. vantage-layout-v2.css loads AFTER custom.css, so an equally
   specific `!important` here wins. Every `!important` below is
   load-bearing for that reason and is annotated where the rule it has
   to outrank is non-obvious.

   Measured at 1440w before this block (see report): header 153px
   logged-in / 118px logged-out, over three stacked rows.
   ================================================================ */

/* ---------------------------------------------- C.1 Full-bleed chrome */
/* Section 1 above already un-caps the CONTENT container via :has(), but
   the header's and breadcrumb's own .container elements still hit
   theme.css's 1140px cap — so without this the slim header renders
   visibly narrower than the content beneath it. 22px matches the
   content container's padding exactly (section 1), which puts the brand
   on the same optical left edge as the sidebar rail below it. */
header.header > .navbar > .container,
.master-breadcrumb > .container {
  max-width: none;
  width: 100%;
  padding-left: 22px;
  padding-right: 22px;
}

/* The 22px above only aligns if it is the ONLY horizontal padding in the
   chain. It was not: measured after the first pass, Bootstrap's .navbar
   contributes 1rem and .master-breadcrumb 30px on the OUTER element, so
   the brand landed at 38px and the breadcrumb text at 52px against
   content at 22px. Zeroing the outer padding makes the container's 22px
   authoritative for all three strips. */
header.header > .navbar,
.master-breadcrumb,
/* custom.css:1021 declares this padding as `padding: 10px 30px !important`
   on the selector LIST `.master-breadcrumb, nav[aria-label="breadcrumb"]`.
   The attribute selector scores 0,1,1 and so outranks a bare
   `.master-breadcrumb` (0,1,0) no matter how late this file loads --
   verified live: the nav still measured padding-left 30px until this
   selector was matched. Repeating the attribute selector ties the
   specificity, and then source order decides in our favour. */
nav[aria-label="breadcrumb"].master-breadcrumb {
  padding-left: 0 !important;
  padding-right: 0 !important;
}

/* ------------------------------------------- C.2 Slim header, row one */
/* Row one is brand + knowledgebase search + toolbar. The old 76px came
   from the 60px logo box plus .navbar's default .5rem vertical padding.
   min-height (not height) so the row can still grow if a template drops
   an unexpectedly tall control in rather than clipping it. */
header.header .navbar.navbar-light {
  min-height: 50px;
  padding-top: 0;
  padding-bottom: 0;
}
header.header .navbar.navbar-light > .container {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  min-height: 50px;
}

/* Logo: was rendering 50px tall, which alone exceeded the 50px target
   row. width:auto keeps the aspect ratio (the source asset is ~159x50). */
header.header .navbar-brand {
  padding-top: 0;
  padding-bottom: 0;
}
header.header .navbar-brand img,
header.header .logo-img {
  max-height: 28px;
  width: auto;
}

/* Toolbar controls were bordered pills with .5rem 1rem padding, which is
   what forced the row tall. !important is REQUIRED here, not defensive:
   custom.css:1609 sets `padding-bottom: 8px !important` on
   `.navbar-nav .nav-link`, which this element matches. */
header.header .toolbar {
  align-items: center;
  flex-wrap: nowrap;
}
header.header .toolbar > .nav-item {
  margin-left: 8px !important;   /* replaces the .ml-3 (16px) utility */
}
header.header .toolbar .nav-link {
  padding: 0 8px !important;
  border: 0 !important;
  border-radius: 0 !important;
  display: inline-flex;
  align-items: center;
}

/* Knowledgebase search: tightened so brand + search + toolbar + the
   folded-in account block all fit one 50px row at desktop width. The
   input-group is only visible at >=xl (d-none d-xl-flex in header.tpl). */
header.header .navbar .search {
  width: 220px;
  flex: 0 0 auto;
}
header.header .navbar .search .form-control,
header.header .navbar .search .btn {
  height: 32px;
  padding-top: 0;
  padding-bottom: 0;
}

/* The account/notifications block folded up from the removed .topbar row.
   It keeps the `.topbar` class so custom.css:889-916 still colours its
   buttons, but it must NOT keep .topbar's own band styling (a --muted
   fill and a bottom border) or it would render as a tinted slab floating
   inside the toolbar. Both of those are !important at custom.css:883. */
header.header .toolbar .topbar {
  background-color: transparent !important;
  border-bottom: 0 !important;
  padding: 0 !important;
}
header.header .toolbar .topbar .btn {
  padding-top: 2px;
  padding-bottom: 2px;
  line-height: 1.3;
}
/* Long company names ("19TH AND PARK INC") would otherwise push the
   toolbar wider than the row and force a wrap. */
header.header .toolbar .btn-active-client span {
  display: inline-block;
  max-width: 200px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: middle;
}

/* Below xl there is not enough width for brand + account + theme picker +
   cart + hamburger on one line: measured at 390w after the fold, the toolbar
   was 430px inside a 390px viewport and the document scrolled to 557px --
   a real horizontal-overflow regression introduced by the fold, because the
   account block used to have its own full-width row. Rather than hiding the
   account controls (switch-account and return-to-admin are functional, and
   admins do use them on phones), the block is allowed to wrap onto its own
   line at these widths. That restores the pre-existing two-line behaviour on
   mobile only; the desktop single row is unaffected. */
@media (max-width: 1199.98px) {
  header.header .navbar.navbar-light > .container {
    flex-wrap: wrap;
  }
  header.header .toolbar {
    flex-wrap: wrap;
    justify-content: flex-end;
  }
  header.header .toolbar .vantage-hdr-account {
    order: 10;
    flex: 1 0 100%;
    justify-content: flex-end;
    margin-left: 0 !important;
    margin-top: 2px;
    margin-bottom: 2px;
  }
}

/* ------------------------- C.3 Account menu, folded into row one */
/* 2026-07-31 nav consolidation. The whole of the previous C.3 (the
   `.main-navbar-wrapper` second row, its `.container`, the #mainNavbar
   desktop padding reset and the row-two `.nav-link` padding) has been
   DELETED, not overridden: header.tpl no longer emits any of that
   markup, so those four rules matched nothing. Header is now a single
   ~50px row.

   What replaces it is styling for $secondaryNavbar -- the
   "Hello, <name>!" account dropdown -- which moved up into the
   `.toolbar` list in row one.

   Note the selector: includes/navbar.tpl emits `<li class="d-block
   dropdown no-collapse">` with NO `nav-item` class, so the existing
   `header.header .toolbar > .nav-item` spacing rule at C.2 does not
   reach it. Matching `> li` covers both shapes rather than duplicating
   the spacing value. */
header.header .toolbar > li {
  margin-left: 8px !important;
}
/* The account menu's <a> is a plain `.dropdown-toggle`, not a
   `.nav-link`, so C.2's `.toolbar .nav-link` padding/border reset misses
   it too and it would render taller than its neighbours, growing the
   50px row. `pr-4` (1.5rem) is suppressed for the same reason: it is a
   primary-nav gutter and is dead weight at the toolbar's right edge. */
header.header .toolbar > li.dropdown > a.dropdown-toggle {
  padding: 0 8px !important;
  border: 0 !important;
  display: inline-flex;
  align-items: center;
  white-space: nowrap;
}
/* The dropdown is the last control on the right; without an explicit
   right-anchor its menu overflows the viewport at narrow widths.
   `dropdown-menu-right` is already applied by navbar.tpl via
   rightDrop=true -- this only guarantees it wins over custom.css's
   left-anchored default. */
header.header .toolbar > li.dropdown > .dropdown-menu {
  right: 0;
  left: auto;
}
/* Long account names would otherwise push the toolbar wider than the row
   and force a wrap, the same failure the `.btn-active-client` clamp in
   C.2 exists to prevent. */
header.header .toolbar > li.dropdown > a.dropdown-toggle {
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Mobile packing. Measured at 390w straight after the fold: the toolbar
   wrapped to THREE lines (theme picker 140px alone pushed the cart and
   hamburger onto their own line, with the account block on a third),
   giving a 130px header. The account menu that moved up from row two is
   the extra content that tipped it over.

   Rather than hide controls, the two elastic ones are clamped so line
   one fits account-menu + theme + cart + hamburger inside 346px, leaving
   the existing full-width `.vantage-hdr-account` wrap (C.2) as the only
   second line. Nothing is removed: every control stays tappable. */
@media (max-width: 767.98px) {
  header.header .toolbar .vantage-theme-picker select {
    max-width: 96px;
  }
  header.header .toolbar > li.dropdown > a.dropdown-toggle {
    max-width: 132px;
  }
  header.header .toolbar > li {
    margin-left: 6px !important;
  }
}

/* ------------------------------------------------- C.4 Breadcrumb strip */
/* Was 62px logged-in. Bootstrap's .breadcrumb ships a 1rem margin-bottom
   and .75rem/1rem padding plus a background fill; this reduces it to a
   hairline-separated strip. */
/* Same specificity tie as C.1: the 10px vertical half of custom.css:1021's
   `padding: 10px 30px !important` needs the attribute selector to beat.
   The border-bottom and `position: sticky; top: 0` from that rule are left
   alone -- the hairline is wanted and the sticky strip is existing,
   intentional behaviour. */
nav[aria-label="breadcrumb"].master-breadcrumb {
  padding-top: 0 !important;
  padding-bottom: 0 !important;
}
.master-breadcrumb .breadcrumb {
  padding: 6px 0 !important;
  margin-bottom: 0 !important;
  font-size: 12px !important;
  background-color: transparent !important;
  border-radius: 0 !important;
}

/* ------------------------------------------ C.5 Hairline, not card chrome */
/* custom.css now sets the four-sided hairline on .card/.panel/.vantage-card/
   .vantage-widget. These are the selectors it does NOT reach: the dashboard
   widget headers use `.vantage-card-header`, not `.card-header`, and were
   still painting a `--vantage-background-muted` tinted bar — the most
   visible remaining piece of the old look. */
.vantage-card-header,
.vantage-dashboard .vantage-card-header,
.vantage-panel-header {
  background-color: var(--card) !important;
  border-bottom: 1px solid var(--border) !important;
}

/* ------------------------------------------------------- C.6 Sidebar rail */
/* NOTE: the brief specified `.list-group-item` here. That markup does not
   exist in this template — includes/sidebar.tpl emits exclusively
   .vantage-nav-* / .vantage-sidebar-* (verified: zero occurrences of
   "list-group" in the file), matching the Stage A note at custom.css:1059.
   The equivalent treatment is applied to the real markup below.
   Width is untouched: it stays on the --vantage-nav-w token. */
#main-body .sidebar {
  background-color: var(--card) !important;   /* beats custom.css:1056 `transparent !important` */
  border-right: 1px solid var(--border);
  /* C.7/C.9 REPLACED 2026-07-31 (v2): the sticky+z-index chrome stack below
     this comment (two prior same-day passes) is superseded by the
     fixed-viewport model in the new "C.9 Fixed-viewport shell" block further
     down this file. That model makes `body` itself non-scrolling, so
     position:sticky here is meaningless -- height/overflow now come from
     flex sizing against the fixed-height #main-body row instead. Left as
     `position: static` explicitly (not just omitted) so it's obvious this
     was a deliberate removal, not an oversight, if someone greps for
     "sticky" later. */
  position: static;
  height: 100%;
  overflow-y: auto;
}
/* Items become hairline-separated rows rather than discrete chips. The
   last item's rule is dropped so the list does not double up with the
   container edge. */
#main-body .sidebar .vantage-nav-item {
  border: 0 !important;
  border-radius: 0 !important;
  background-color: transparent !important;
  border-bottom: 1px solid var(--border) !important;
}
#main-body .sidebar .vantage-nav-item:last-child {
  border-bottom: 0 !important;
}

/* --------------------------------------------------------- C.8 Slim footer */
/* footer.tpl no longer renders the newsletter block or the four-column
   marketing grid in the client area — .vantage-footer-bottom is now the
   ENTIRE footer. Its own border-top (custom.css) duplicated .vantage-footer's
   outer border-top once those sections were removed, and its 24px padding
   was sized for a bar sitting below 96px of grid content, not for being the
   whole footer. Tightened to match the slim-chrome target used for the
   header. */
.vantage-footer-slim .vantage-footer-bottom {
  border-top: 0 !important;
  padding: 12px 0 !important;
}

/* ------------------------------------------------ C.9 Fixed-viewport shell */
/* Superseding two same-day sticky-chrome passes (kept in git history /
   the .bak files, not repeated here). Explicit design decision (user,
   2026-07-31): the whole client-area shell should fit the viewport with NO
   page-level scroll -- header, breadcrumb, and footer always visible;
   sidebar and main content each scroll independently within the space
   between them. This is a cleaner solve than sticky-positioning every
   chrome element individually (no z-index stacking to get wrong, no
   sticky-offset arithmetic to keep in sync with header/breadcrumb height
   if either ever changes again).
   SCOPED to `body:not(.vantage-cart)` deliberately -- WHMCS is a
   page-reload app, not an SPA, and standard_cart/checkout can render
   payment-gateway iframes and 3-D Secure challenges that may not tolerate
   a viewport-clipped ancestor. header.tpl now emits a `vantage-cart` body
   class when `$inShoppingCart` is true (see header.tpl body tag), so the
   cart path keeps ordinary document-flow scrolling and none of this
   applies there. Verify the cart path explicitly after any change here. */
body:not(.vantage-cart) {
  height: 100vh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
body:not(.vantage-cart) header.header,
body:not(.vantage-cart) .master-breadcrumb,
body:not(.vantage-cart) footer.vantage-footer {
  flex: 0 0 auto; /* natural height, always visible, never scrolled away */
}
body:not(.vantage-cart) .master-breadcrumb {
  /* custom.css sets `position: sticky !important; top: 0 !important;` on
     this element (predates this pass). Sticky is meaningless once `body`
     itself can't scroll, but leaving it in place is harmless -- top:0
     inside a flex item that never moves relative to its own flow position
     has no visible effect. Not overridden to `static` to avoid yet another
     specificity fight over a rule that no longer does anything. */
}
body:not(.vantage-cart) #main-body {
  flex: 1 1 auto;
  min-height: 0; /* required: without this, a flex child won't shrink below
                    its content's natural height, so overflow-y:auto on its
                    descendants below would never actually engage -- the
                    row would just push #main-body taller instead. */
  overflow: hidden;
  padding-top: 0;    /* stock theme.css `padding: 20px 0` on #main-body no
                          longer serves a purpose in this model -- sidebar
                          and main-content are now each their own bounded,
                          independently-scrolling box at exactly the
                          available height, and their own internal
                          padding/margins provide breathing room instead. */
  padding-bottom: 0;
}
body:not(.vantage-cart) #main-body > .container,
body:not(.vantage-cart) #main-body > .container > .row {
  height: 100%;
}
body:not(.vantage-cart) #main-content {
  height: 100%;
  overflow-y: auto;
}
body:not(.vantage-cart) #main-body .row > [class*="col-xl-3"] {
  /* The sidebar's OWN column wrapper (.col-lg-4.col-xl-3) is a SEPARATE
     element from `.sidebar` (nested one level deeper) -- unlike
     #main-content, which IS its own column (no wrapper to forget). Giving
     height:100% to `.sidebar` alone was not enough: its parent column had
     no explicit height, and a flex item whose height depends on
     align-items:stretch while a percentage-height DESCENDANT depends on
     that same not-yet-resolved height creates a circular sizing case --
     browsers commonly bail out of stretch in that situation and fall back
     to sizing the column by its content instead (measured live: column
     grew to 1567.77px, matching the nav list's natural height, instead of
     stretching to the row's actual 1059px). min-height:0 overrides the
     flex-item default of min-height:auto, which is what was blocking the
     shrink-to-fit-container behavior; height:100% makes the intent
     explicit rather than relying on stretch alone. */
  height: 100%;
  min-height: 0;
}

/* --------------------------------- C.10 Dashboard card body vs. addon leak */
/* 2026-08-24. Dashboard .vantage-card widgets (Support Tickets, Your
   Services, Recent Invoices, Quick Actions, Account Summary, Announcements)
   painted a WHITE body under the dark theme while their headers stayed
   correctly dark -- measured live: card background rgb(255,255,255) with
   #f0f0f0 body text = 1.14:1 contrast, effectively unreadable.

   Cause is a class-name COLLISION, not a theme bug. Two independently-owned
   CSS systems both define a component literally named `.vantage-card`:
     - this theme (custom.css:564/1644/1909) for dashboard widgets, and
     - modules/addons/vantage_reports/assets/vantage-report.css:759 for its
       own report-page card primitive.
   The addon's stylesheet is injected on EVERY client-area page (via the
   vantage_integrations_clientarea.php / vantage_addon_widgets.php hooks),
   not just report-detail routes, so its rule reaches the dashboard. Both
   declarations are !important at equal specificity (0,1,0), so the cascade
   resolves by source order and the addon -- emitted after this theme's
   <head> links -- wins.

   Its value `var(--vr-bg-elevated)` only resolves dark inside
   `.vantage-reports.vr-report` or under `@media (prefers-color-scheme:
   dark)`. The dashboard is in neither: this install's dark mode is the
   app-level `data-theme="strategic"` toggle, and matchMedia
   (prefers-color-scheme: dark) is FALSE here (verified live). So
   --vr-bg-elevated falls through to its bare :root default, #ffffff.

   Fix is theme-side only. Raising the selector to (0,2,0) beats the addon's
   (0,1,0) regardless of stylesheet load order, so it stays correct even if
   the hook injection order changes later. This mirrors the identical
   header-specificity fix already at C.5 above, rather than introducing a
   new technique.

   Deliberately NOT fixed by editing vantage-report.css: that rule is
   legitimate for its own report-page cards and is owned by the
   vantage_reports workstream. Only the leak into the dashboard is a defect.
   Scoped to `.vantage-dashboard` so report-detail pages are untouched.

   Revert = delete this block. */
.vantage-dashboard .vantage-card {
  background-color: var(--vantage-background-card, var(--card)) !important;
}
