/* ═══════════════════════════════════════════════════════════════════════════
   ivo-brand-rules-1.css - the brand's element rules for the WHMCS/Bootstrap
   markup: the client area, cart, login, register, invoice and marketing.
   Split out of ivo-tokens-6.css on 2026-09-18 (sections 4-8, verbatim).

   Every token it reads is defined in ivo-tokens-7.css, which loads immediately
   before this file and on EVERY surface. This file loads only where its markup
   exists, which is why it is still behind {if $smarty.get.m != 'ivo'} in
   header.tpl: the SPA has none of this markup and measurably does not want
   these rules (see the note in ivo-tokens-7.css for the numbers).

   LOADED LAST, DELIBERATELY. Equal-specificity rules here win on order. Where a
   rule below is more specific than it looks it is because it has to out-rank a
   vendor rule; those are commented individually.

   Cloudflare caches /_v4css by PATH and ignores ?v=: RENAME to publish.
   Guarded by tools/brand_css_guard.sh, which asserts both links are present.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── 4. FAMILY ──────────────────────────────────────────────────────────────
   Form controls do not inherit font-family; they must be named explicitly.   */
body,
button, input, select, textarea, optgroup,
.btn, .form-control, .form-select,
h1, h2, h3, h4, h5, h6{
  font-family:var(--ivo-font);
}

/* ── 5. BASE TYPE ───────────────────────────────────────────────────────── */
body{
  font-size:var(--fs-base);          /* 15px canonical, was 16px */
  line-height:var(--lh-normal);
  font-weight:var(--fw-body);
}
p{ font-size:var(--fs-base); line-height:var(--lh-normal); }
.lead, .lede{ font-size:var(--fs-lg); line-height:1.5; }   /* 17px */
small, .small{ font-size:var(--fs-sm); }                   /* 12px */

h1,h2,h3,h4,h5,h6{
  font-weight:var(--fw-display);
  line-height:var(--lh-snug);
  letter-spacing:-.02em;
  text-wrap:balance;
}
h1{ font-size:var(--fs-display); line-height:var(--lh-tight); letter-spacing:-.03em; }
h2{ font-size:var(--fs-hero); }
h3{ font-size:var(--fs-xl); }
h4{ font-size:var(--fs-lg); }
h5{ font-size:var(--fs-md); }
h6{ font-size:var(--fs-base); }

/* Marketing hero takes the display step. Scoped to the marketing chrome so an
   app page never inherits a 66px heading. */
#v5top .hero h1,
.v3x .hero h1,
h1.hero{ font-size:var(--fs-display-hero); }

/* App surfaces take a smaller step of the SAME scale. #main-body is the WHMCS
   content wrapper, so this covers client area, auth and cart. */
#main-body h1{ font-size:var(--fs-hero); letter-spacing:-.02em; }   /* 26px */
#main-body h2{ font-size:var(--fs-xl); }                            /* 22px */
#main-body h3{ font-size:var(--fs-lg); }                            /* 17px */

/* ── 6. FORM CONTROLS ───────────────────────────────────────────────────── */
/* :not(.field-icon) is load-bearing, not defensive tidiness. Nexus builds the
   register form's input icons as <label class="field-icon"> and centres each
   glyph with #registration .prepend-icon .field-icon{line-height:36px}. Without
   the exclusion, the rule below (two IDs) out-ranks that (one ID + two classes),
   line-height collapses 36px -> 1.4, and the icon sits high in all 15 fields.
   Shipped that way on 2026-08-25 and was reported as "looks broken" within the
   hour. A label is not always a caption in this theme. */
label:not(.field-icon),
.col-form-label,
#main-body label:not(.field-icon){
  font-size:var(--fs-meta);      /* 13px, styleguide .field label */
  font-weight:var(--fw-strong);  /* 600 */
  line-height:1.4;
}
/* Out-ranks the vendor rule templates/nexus/css/theme.min.css
   {#registration label} 13px/300, which is what made the register form read as
   a different typeface - the original report. */
#registration label:not(.field-icon),
#main-body #registration label:not(.field-icon){
  font-size:var(--fs-meta);      /* 13px, styleguide .field label */
  font-weight:var(--fw-strong);  /* 600 */
  line-height:1.4;
}

.form-control, .form-select, select, textarea,
input[type="text"], input[type="email"], input[type="password"],
input[type="tel"], input[type="number"], input[type="search"],
#main-body .form-control, #main-body .form-select{
  font-size:var(--fs-base);      /* 15px canonical */
  line-height:1.5;
  border-radius:var(--ivo-radius-sm);
}

/* Nexus gives the register form TWO control classes with different metrics:
   #registration .field  -> 13px, padding 1px 2px 1px 36px
   #registration .form-control -> 13px, padding 6px 12px 6px 36px
   Both at (1,1,0), which out-ranks a bare input[type=...] selector - so the
   generic rule above reached only nine of the fourteen controls and left four
   at 13px with tight padding. Mixed sizes in one column is what "not aligned"
   looks like. Match their specificity and normalise.

   Only the vertical and right padding are set: padding-left carries the 36px
   icon offset on some fields and 12px on those without an icon, so writing the
   shorthand would shove the icon-less controls out of line. */
#registration .field,
#registration .form-control,
#registration select,
#main-body #registration .field{
  font-size:var(--fs-base);      /* 15px canonical */
  padding-top:6px;
  padding-bottom:6px;
  padding-right:12px;
}

/* ── 7. BUTTONS ─────────────────────────────────────────────────────────────
   Selector list covers all three scopes at their own specificity so this file
   wins on load order rather than on !important.                              */
.btn,
.v3x .btn,
#main-body .btn,
input[type="submit"],
button[type="submit"],
#main-body input[type="submit"],
#main-body button[type="submit"]{
  font-family:var(--ivo-font);
  font-size:var(--ivo-btn-fs);
  font-weight:var(--ivo-btn-fw);
  line-height:1.2;
  padding:var(--ivo-btn-pad);
  border-radius:var(--ivo-btn-radius);
  letter-spacing:-.01em;
}

.btn-primary,
.v3x .btn-primary,
#main-body .btn-primary,
input[type="submit"],
button[type="submit"],
#main-body input[type="submit"],
#main-body button[type="submit"]{
  background:var(--ivo-accent);
  border:1px solid var(--ivo-accent);
  color:var(--ivo-accent-ink);
}
.btn-primary:hover, .btn-primary:focus,
.v3x .btn-primary:hover,
#main-body .btn-primary:hover,
input[type="submit"]:hover,
button[type="submit"]:hover{
  background:var(--ivo-accent-deep);
  border-color:var(--ivo-accent-deep);
  color:var(--ivo-accent-ink);
}

/* Small variant keeps the same radius and family - only the metrics shrink. */
.btn-sm, .v3x .btn-sm, #main-body .btn-sm{
  font-size:var(--ivo-btn-fs-sm);
  padding:var(--ivo-btn-pad-sm);
  border-radius:var(--ivo-radius-sm);
}

/* Kill the purchased theme's demo CSS. .promo-banner.nordvpn .btn (3 classes)
   was setting #4687ff on real client-area buttons. */
.promo-banner .btn,
.promo-banner.nordvpn .btn,
#main-body .promo-banner .btn{
  background:var(--ivo-accent);
  border-color:var(--ivo-accent);
  color:var(--ivo-accent-ink);
}

/* Visible keyboard focus on every control - none of the competing button rules
   defined one. */
.btn:focus-visible,
input[type="submit"]:focus-visible,
button:focus-visible,
a:focus-visible,
.form-control:focus-visible,
select:focus-visible{
  outline:2px solid var(--ivo-accent);
  outline-offset:2px;
}

/* ── 8. MODAL SCROLL POSITION ───────────────────────────────────────────────
   Opening any Bootstrap modal jumped the page to the top - reported on the
   register form's "Generate Password", but it affects EVERY modal on the site.

   Mechanism, measured rather than guessed: the vendor theme sets
       templates/nexus/css/theme.min.css   body, html{height:100%}
   and Bootstrap adds `overflow:hidden` to <body> while a modal is open. With
   body pinned to one viewport height, hiding its overflow collapses the
   scrollable content to 627px, so html (the scrolling element) has nothing left
   to scroll and clamps scrollTop to 0. Adding the .modal-open class ALONE
   reproduces it; the modal JS is innocent.

   height:auto stops the collapse, so the scroll position survives. The lock on
   <html> then still prevents the background scrolling behind the modal, because
   html keeps its full content height and only loses its scrollbar.

   Verified A/B on live with a control: 725 -> 725 with these rules, 725 -> 0
   without. Do not "simplify" by dropping the height override; that is the half
   that does the work. */
body.modal-open{
  height:auto;
  min-height:100%;
}
html:has(body.modal-open){
  overflow:hidden;
}
