/*
 * Webdev Zimbabwe — shared page primitives (v2026)
 * Load AFTER webdev-antler-design.css (tokens) and webdev-fonts.css.
 * Load BEFORE any page stylesheet (webdev-home.css, webdev-upgrades.css).
 *
 * Everything here is page-agnostic: the container, section rhythm, heading
 * scale, eyebrows, icons, card surface and the Antler theme overrides. Page
 * files add only their own blocks.
 *
 * Scope class is `.wd-page`. Pages add a second class for their own rules,
 * e.g. <main class="wd-page wd-home"> / <main class="wd-page wd-upgrades">.
 */

/*
 * Tokens all live in webdev-antler-design.css — colours, the container width,
 * card radius/shadow and the semantic 800 shades. Nothing is redeclared here so
 * each value has exactly one definition.
 */

.wd-page {
  --wd-section-y: clamp(3.5rem, 6vw, 6rem);
  background: var(--wd-warm-050);
  color: var(--wd-charcoal-900);
  font-family: var(--wd-font-sans);
  line-height: 1.6;
}

.wd-page *,
.wd-page *::before,
.wd-page *::after {
  box-sizing: border-box;
}

/* ---------- layout ---------- */

.wd-shell {
  margin: 0 auto;
  max-width: var(--wd-container, 1320px);
  padding: 0 clamp(1rem, 3vw, 1.5rem);
  width: 100%;
}

.wd-section {
  padding: var(--wd-section-y) 0;
}

.wd-section--flush {
  padding: 0;
}

.wd-section--tight {
  padding: clamp(2.5rem, 4vw, 3.5rem) 0;
}

.wd-section__head {
  margin: 0 auto clamp(2rem, 3.5vw, 3rem);
  max-width: 44rem;
  text-align: center;
}

.wd-panel--white {
  background: var(--wd-white);
  border-block: 1px solid var(--wd-grey-200);
}

/* Lightly tinted section so white cards and their shadows read against it —
   the treatment the previous homepage used behind "Why Choose Webdev?". */
.wd-panel--tint {
  background: var(--wd-grey-100);
}

.wd-panel--dark {
  background: var(--wd-slate-600);
  color: var(--wd-white);
}

/* Near-black variant, where a panel needs to read as heavier than slate. */
.wd-panel--black {
  background: var(--wd-charcoal-950);
  color: var(--wd-white);
}

.wd-panel--brand {
  background: var(--wd-orange-050);
}

/* ---------- typography ---------- */

.wd-page h1,
.wd-page h2,
.wd-page h3,
.wd-page h4 {
  color: inherit;
  font-family: var(--wd-font-sans);
  letter-spacing: -0.015em;
  margin: 0;
}

.wd-page h1 {
  font-size: clamp(2.375rem, 5.2vw, 3.75rem);
  font-weight: 700;
  line-height: 1.08;
}

.wd-page h2 {
  font-size: clamp(1.875rem, 3.2vw, 2.25rem);
  font-weight: 700;
  line-height: 1.18;
}

.wd-page h3 {
  font-size: clamp(1.25rem, 1.8vw, 1.5rem);
  font-weight: 700;
  line-height: 1.25;
}

.wd-page h4 {
  font-size: 1.0625rem;
  font-weight: 650;
  line-height: 1.3;
}

.wd-lead {
  color: var(--wd-grey-700);
  font-size: clamp(1.0625rem, 1.3vw, 1.125rem);
  margin: 1rem 0 0;
}

.wd-body {
  color: var(--wd-grey-700);
  margin: 0.75rem 0 0;
}

.wd-eyebrow {
  color: var(--wd-grey-500);
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  margin: 0 0 0.75rem;
  text-transform: uppercase;
}

.wd-eyebrow--brand {
  color: var(--wd-orange-600);
}

/* Short orange rule, usually above an eyebrow. */
.wd-rule {
  background: var(--wd-orange-500);
  border-radius: 2px;
  display: block;
  height: 3px;
  margin: 0 auto clamp(1rem, 2vw, 1.5rem);
  width: 48px;
}

.wd-rule--start {
  margin-inline: 0;
}

/* ---------- skip link ---------- */

.wd-skip-link {
  background: var(--wd-charcoal-900);
  border-radius: 0 0 var(--wd-radius-sm) 0;
  color: var(--wd-white);
  font-weight: 600;
  left: 0;
  padding: 0.75rem 1.25rem;
  position: absolute;
  text-decoration: none;
  top: 0;
  transform: translateY(-120%);
  z-index: 2000;
}

.wd-skip-link:focus {
  color: var(--wd-white);
  transform: translateY(0);
}

/* ---------- icons ---------- */

.wd-icon {
  fill: none;
  flex: 0 0 auto;
  height: 1.5rem;
  stroke: currentColor;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-width: 1.5;
  width: 1.5rem;
}

.wd-icon--sm {
  height: 1.125rem;
  width: 1.125rem;
}

.wd-icon--lg {
  height: 2rem;
  width: 2rem;
}

.wd-icon--xl {
  height: 2.5rem;
  width: 2.5rem;
}

/*
 * Card-leading mark. The previous site led its cards with a large, thin, muted
 * line icon rather than a tinted plate, so the "plate" now carries no fill —
 * the class name is kept because it is used across every page.
 */
.wd-icon-plate {
  align-items: center;
  background: none;
  border-radius: 0;
  color: var(--wd-grey-500);
  display: inline-flex;
  height: 2.75rem;
  justify-content: flex-start;
  width: 2.75rem;
}

.wd-icon-plate .wd-icon {
  height: 2.75rem;
  stroke-width: 1.1;
  width: 2.75rem;
}

/* On dark surfaces the mark takes the brand orange so it still reads. */
.wd-panel--dark .wd-icon-plate,
.wd-panel--black .wd-icon-plate {
  color: var(--wd-orange-500);
}

/*
 * Body and lead copy carry their own dark colour, which beats the white the
 * dark panels set on their container — a direct rule always wins over an
 * inherited one. Without this, paragraphs inside a dark card render nearly
 * invisible. Applies to every dark panel rather than being fixed per page.
 */
.wd-panel--dark .wd-body,
.wd-panel--dark .wd-lead,
.wd-panel--black .wd-body,
.wd-panel--black .wd-lead {
  color: var(--wd-grey-200);
}

/* ---------- card surface ---------- */

/*
 * A soft shadow carries the elevation instead of a hairline border. The border
 * stays in the box (transparent) so the interactive hover state can still
 * colour it without shifting layout by a pixel.
 */
.wd-page .wd-card {
  border-color: transparent;
  border-radius: var(--wd-card-radius);
  box-shadow: var(--wd-card-shadow);
  padding: clamp(1.5rem, 2.6vw, 2.25rem);
}

@media (hover: hover) and (pointer: fine) {
  .wd-page .wd-card--interactive:hover {
    box-shadow: 0 10px 26px 0 rgb(110 110 110 / 18%);
  }
}

/*
 * Must come after the rules above and outrank them: `.wd-page .wd-card` (0,2,0)
 * would otherwise beat `.wd-card--interactive:focus-visible` (0,2,0) on source
 * order — the design stylesheet loads first — and silently remove the keyboard
 * focus ring from every card link.
 */
.wd-page .wd-card--interactive:focus-visible {
  box-shadow: var(--wd-focus);
}

/* ---------- sub-page hero ---------- */

/*
 * Shared dark banner for every page below the homepage. The artwork is anchored
 * right and a left-to-right scrim supplies the text contrast, so the image can
 * be swapped without retesting legibility.
 *
 * Lives in base because /upgrades and all four migration pages use exactly the
 * same treatment — it was duplicated per-template until a third page needed it.
 */
/*
 * Artwork is a variable so a page can swap it without restating the gradient —
 * `--wd-subhero-art: url("../img/whatever.jpg")` on a modifier class. The scrim
 * is what guarantees text contrast, so it must not be duplicated per page and
 * allowed to drift.
 */
.wd-subhero {
  --wd-subhero-art: url("../img/subhero.jpg");
  /*
   * Focal point for the artwork. A variable because a photograph of PEOPLE
   * cannot use the default: the band is wide and short, so `cover` crops the
   * top and bottom, and centring a portrait-ish group shot slices the faces off
   * entirely. Variants set this to keep heads in frame.
   */
  --wd-subhero-art-pos: right center;

  background-color: var(--wd-charcoal-950);
  background-image:
    linear-gradient(
      100deg,
      var(--wd-charcoal-950) 0%,
      var(--wd-charcoal-950) 24%,
      rgb(17 20 22 / 80%) 42%,
      rgb(17 20 22 / 30%) 66%,
      rgb(17 20 22 / 0%) 100%
    ),
    var(--wd-subhero-art);
  background-position: center, var(--wd-subhero-art-pos);
  background-repeat: no-repeat, no-repeat;
  background-size: cover, cover;
  color: var(--wd-white);
}

/*
 * Scrim for a LIGHT photograph. The default fades to fully transparent, which
 * is right over dark artwork but leaves a hard dark-to-bright seam over a light
 * one. This keeps a floor of tint across the whole width so the two halves read
 * as one image, and holds heavier cover under the copy.
 */
.wd-subhero--light-art {
  background-image:
    linear-gradient(
      100deg,
      var(--wd-charcoal-950) 0%,
      var(--wd-charcoal-950) 26%,
      rgb(17 20 22 / 90%) 44%,
      rgb(17 20 22 / 62%) 68%,
      rgb(17 20 22 / 42%) 100%
    ),
    var(--wd-subhero-art);
}

/*
 * Shared hero artwork. Per-page art normally lives in the page stylesheet, but
 * /hosting (router template) and /web-hosting (product template) use the same
 * image, and base is the only layer both of them load.
 *
 * A dark server aisle: flat wall on the left, lit racks on the right — the same
 * direction as the default scrim, so the copy sits over the plain wall and the
 * racks stay visible where the gradient clears. No --light-art variant needed.
 *
 * NB: `server-room.jpg` is a DIFFERENT, older asset still used by about.html,
 * email-hosting.html, vps-server-hosting.html and four other legacy pages. This
 * file is named separately so neither overwrites the other.
 */
.wd-subhero--servers {
  --wd-subhero-art: url("../img/server-room-hero.jpg");
}

/*
 * The upgrade-journey artwork: someone planning a rebuild at a desk. Shared by
 * /upgrades (its own template) and by /email-office-upgrade and
 * /managed-website-upgrade (the migration template), so it lives here for the
 * same reason --servers does.
 *
 * BRIGHT photograph — a lit desk with windows behind it and no dark region
 * anywhere. Always pair it with .wd-subhero--light-art: the default scrim fades
 * to fully transparent on the right, which is right over dark art but leaves a
 * hard seam and an unreadably bright half over a light one. The pairing is
 * applied in the markup so it is visible at the point of use.
 *
 * Weight: this REPLACES the default subhero.jpg (144K) rather than adding a
 * request — 153K against 144K — so the /upgrades brief's load budget is
 * unaffected.
 */
.wd-subhero--upgrades {
  --wd-subhero-art: url("../img/upgrades-hero.jpg");
}

/*
 * The WordPress artwork, shared by /wordpress-hosting (product template) and
 * /wordpress-hosting-upgrade (migration template) — here for the same reason as
 * the two above.
 *
 * Dark desk on the left, a laptop showing the WordPress mark on the right. That
 * matches the default scrim's direction, so no --light-art variant: the bright
 * screen sits where the gradient has already cleared, which is what makes it
 * readable rather than blown out.
 */
.wd-subhero--wordpress {
  --wd-subhero-art: url("../img/wordpress-hero.jpg");
}

/*
 * The Websites-category artwork, shared by all three pages in that category:
 * /websites (router), /managed-websites (product) and /custom-websites
 * (consult). Three different page stylesheets, so base is the only layer all of
 * them load — the same reason the three variants above live here.
 *
 * The JPEG, not the supplied PNG: the original is 1.6MB at 1942x809. Re-encoded
 * at q82 it is 134KB, in line with the other heroes (126-177KB). The PNG is
 * left in place untouched.
 *
 * DARK photograph — an unlit wall filling the left half, lit monitor, tablet
 * and phone on the right. That runs the same direction as the DEFAULT scrim, so
 * this variant must NOT take .wd-subhero--light-art: the heading sits over the
 * plain dark wall, and the gradient has cleared by the time it reaches the
 * screens, which is what keeps them bright rather than muddied. All three pages
 * previously borrowed the bright `--upgrades` desk photo and did need it.
 */
.wd-subhero--websites {
  --wd-subhero-art: url("../img/websitespage.jpg");
}

/* .wd-subhero--support MOVED to webdev-contact.css and folded into
 * .wd-subhero--contact — /contact-us is the only subhero using that artwork now
 * that /careers has taken the developer photograph. The homepage uses the same
 * image, but declares it directly on .wd-hero__bg in webdev-home.css, not
 * through this modifier. */

/* Never combined with .wd-shell — a max-width on the shell element itself
   overrides its container width and centres the block. */
.wd-subhero__inner {
  max-width: 46rem;
  padding: clamp(2.75rem, 5vw, 4.25rem) 0 clamp(2.25rem, 4vw, 3.25rem);
}

/*
 * HERO TYPE INVERSION (client direction).
 *
 * The eyebrow is the dominant line at 40px and the h1 sits under it at a
 * smaller size. This is only in the .wd-subhero -- section eyebrows elsewhere on
 * every page keep the normal 13px treatment.
 *
 * Two things the size change forces:
 *   · tracking drops from 0.08em to 0.01em. Letter-spacing is tuned for 13px
 *     caps; carried to 40px it pushed "HOSTING & SERVERS" past the viewport.
 *   · both values are clamps, so 40px is the DESKTOP size and it scales down on
 *     narrow screens. A flat 40px overflowed at 390px.
 */
.wd-subhero .wd-eyebrow {
  /*
   * The token, not a bare `Poppins`: it resolves to the same face but keeps the
   * Inter / Open Sans / system-ui fallback chain, so the hero does not drop to
   * a serif default on the first paint or if the webfont fails.
   */
  font-family: var(--wd-font-sans);
  font-size: clamp(1.5rem, 3.4vw, 2.5rem);
  font-weight: 700;
  letter-spacing: 0.01em;
  line-height: 1.15;
  margin-bottom: 0.625rem;
  max-width: 20ch;
}

.wd-subhero h1 {
  font-size: clamp(1.375rem, 2.2vw, 1.75rem);
  max-width: 34ch;
}

.wd-subhero .wd-lead {
  color: var(--wd-grey-200);
  max-width: 54ch;
}

.wd-subhero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: clamp(1.5rem, 2.5vw, 2rem);
}

/* Secondary button on a dark surface needs a light outline, not the light fill
   the token default assumes. */
.wd-on-dark .wd-btn--secondary,
.wd-subhero .wd-btn--secondary {
  background: transparent;
  border-color: rgb(255 255 255 / 45%);
  color: var(--wd-white);
}

@media (hover: hover) and (pointer: fine) {
  .wd-on-dark .wd-btn--secondary:hover,
  .wd-subhero .wd-btn--secondary:hover {
    background: rgb(255 255 255 / 10%);
    border-color: var(--wd-white);
    color: var(--wd-white) !important;
  }
}

@media (max-width: 991.98px) {
  /* The artwork's detail sits right, so pull the focal point in and deepen the
     scrim rather than cropping to empty background. */
  .wd-subhero {
    background-image:
      linear-gradient(
        170deg,
        var(--wd-charcoal-950) 0%,
        rgb(17 20 22 / 86%) 48%,
        rgb(17 20 22 / 60%) 100%
      ),
      var(--wd-subhero-art);
    background-position: center, 74% center;
  }
}

@media (max-width: 575.98px) {
  .wd-subhero__actions .wd-btn {
    width: 100%;
  }
}

/* ---------- reassurance chips ---------- */

/* Labels, not actions. Used on dark hero surfaces. */
.wd-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  list-style: none;
  margin: clamp(1.5rem, 3vw, 2rem) 0 0;
  padding: 0;
}

.wd-chips li {
  align-items: center;
  background: rgb(255 255 255 / 8%);
  border: 1px solid rgb(255 255 255 / 18%);
  border-radius: var(--wd-radius-pill, 999px);
  color: var(--wd-white);
  display: inline-flex;
  font-size: 0.875rem;
  font-weight: 600;
  gap: 0.5rem;
  padding: 0.4375rem 0.875rem;
}

.wd-chips .wd-icon {
  color: var(--wd-orange-500);
  height: 1.0625rem;
  width: 1.0625rem;
}

/* ---------- status badge ---------- */

.wd-badge {
  align-items: center;
  border-radius: var(--wd-radius-pill, 999px);
  display: inline-flex;
  font-size: 0.75rem;
  font-weight: 600;
  gap: 0.375rem;
  letter-spacing: 0.01em;
  max-width: 100%;
  padding: 0.3125rem 0.6875rem;
  white-space: nowrap;
}

.wd-badge::before {
  border-radius: 50%;
  content: "";
  height: 6px;
  width: 6px;
}

/* Required / mandatory — amber, never red: this is a scheduled change, not an error. */
.wd-badge--required {
  background: var(--wd-warning-050);
  color: var(--wd-warning-800);
}

.wd-badge--required::before {
  background: var(--wd-warning-600);
}

.wd-badge--optional {
  background: var(--wd-grey-100);
  color: var(--wd-grey-700);
}

.wd-badge--optional::before {
  background: var(--wd-grey-500);
}

.wd-badge--available {
  background: var(--wd-success-050);
  color: var(--wd-success-800);
}

.wd-badge--available::before {
  background: var(--wd-success-600);
}

/* The single recommended default in a decision set. Orange, so it never reads as
   the amber "required" status. */
.wd-badge--recommended {
  background: var(--wd-orange-050);
  color: var(--wd-orange-700);
}

.wd-badge--recommended::before {
  background: var(--wd-orange-500);
}

/* ---------- descriptive tag ---------- */

/*
 * Plain label for describing an option ("Outlook & Teams", "Lowest cost").
 * Deliberately NOT a .wd-badge: badges carry account status (required /
 * optional / available) and must keep that meaning across pages.
 */
.wd-tag {
  background: var(--wd-grey-050);
  border: 1px solid var(--wd-grey-200);
  border-radius: var(--wd-radius-pill, 999px);
  color: var(--wd-grey-700);
  display: inline-flex;
  font-size: 0.75rem;
  font-weight: 600;
  padding: 0.25rem 0.625rem;
  white-space: nowrap;
}

/* ---------- Antler theme compatibility ----------
 * style.css sets `a { text-decoration: none !important }` and custom.css sets
 * `a:hover { color: #f0682a !important }`. Both would break legibility on the
 * dark and orange surfaces, so re-assert token values inside .wd-page.
 * Scoped and deliberate — not a blanket reset.
 */

.wd-page a:hover {
  color: inherit !important;
}

/*
 * Button hover colours are deliberately NOT scoped to `.wd-page`. The header and
 * footer are injected outside it, so a scoped rule left the header's Client Area
 * button to custom.css's `a:hover { color: #f0682a !important }` — orange label
 * on an orange fill.
 *
 * `.wd-btn--primary:hover` is (0,2,0) and `a:hover` is (0,1,1), so this wins the
 * !important contest on specificity. `.wd-on-dark .wd-btn--secondary:hover`
 * (0,3,0) still outranks these, which is what the dark surfaces need.
 */
.wd-btn--primary:hover,
.wd-btn--primary:active,
.wd-btn--dark:hover {
  color: var(--wd-white) !important;
}

.wd-btn--secondary:hover,
.wd-btn--ghost:hover {
  color: var(--wd-charcoal-950) !important;
}

/* ---------- motion ---------- */

@media (prefers-reduced-motion: reduce) {
  .wd-page *,
  .wd-page *::before,
  .wd-page *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

  .wd-page .wd-card,
  .wd-page .wd-card--interactive {
    transform: none !important;
  }
}

/* ---------- shared page blocks ----------
 * Promoted here once a third template needed them. Class names are unchanged,
 * so the pages that already use them are unaffected — only the file they live
 * in moved. Placed after the card rules above so `.wd-final` still wins its
 * padding against `.wd-card` on source order.
 */

/* Pillar row on a dark surface (homepage compliance, category trust blocks). */
.wd-pillars {
  display: grid;
  gap: clamp(1.5rem, 3vw, 2.5rem);
  grid-template-columns: repeat(4, minmax(0, 1fr));
  list-style: none;
  margin: 0;
  padding: 0;
}

.wd-pillars li + li {
  border-left: 1px solid rgb(255 255 255 / 12%);
  padding-left: clamp(1.5rem, 3vw, 2.5rem);
}

.wd-pillars .wd-icon {
  color: var(--wd-orange-500);
  margin-bottom: 0.875rem;
}

.wd-pillars h3 {
  font-size: 1.0625rem;
}

.wd-pillars p {
  color: var(--wd-grey-200);
  font-size: 0.9375rem;
  margin: 0.5rem 0 0;
}


/* FAQ accordion — native <details>/<summary>: keyboard operable and openable
   with no JavaScript, so answers are reachable even if scripts fail. */
.wd-faq {
  display: grid;
  gap: 0.75rem;
  margin: 0 auto;
  max-width: 52rem;
}

.wd-faq__item {
  background: var(--wd-white);
  border: 1px solid var(--wd-grey-200);
  border-radius: var(--wd-radius-md);
}

.wd-faq__item[open] {
  border-color: var(--wd-orange-500);
}

.wd-faq__item summary {
  align-items: center;
  cursor: pointer;
  display: flex;
  font-weight: 650;
  gap: 1rem;
  justify-content: space-between;
  list-style: none;
  min-height: 56px;
  padding: 0.875rem 1.125rem;
}

.wd-faq__item summary::-webkit-details-marker {
  display: none;
}

.wd-faq__item summary::after {
  border-bottom: 2px solid var(--wd-orange-600);
  border-right: 2px solid var(--wd-orange-600);
  content: "";
  flex: 0 0 auto;
  height: 0.5rem;
  rotate: 45deg;
  transition: rotate var(--wd-duration) var(--wd-ease);
  width: 0.5rem;
}

.wd-faq__item[open] summary::after {
  rotate: 225deg;
}

.wd-faq__item summary:focus-visible {
  border-radius: var(--wd-radius-md);
  box-shadow: var(--wd-focus);
  outline: 0;
}

.wd-faq__item > div {
  border-top: 1px solid var(--wd-grey-100);
  padding: 1rem 1.125rem 1.125rem;
}

.wd-faq__item p {
  color: var(--wd-grey-700);
  margin: 0;
}

.wd-faq__item p + p {
  margin-top: 0.75rem;
}

/* Banner: icon / copy / action. Used for final CTAs and mid-page callouts. */
.wd-final {
  align-items: center;
  display: grid;
  gap: clamp(1.25rem, 2.5vw, 2.5rem);
  grid-template-columns: auto minmax(0, 1fr) auto;
  padding: clamp(1.5rem, 3vw, 2.25rem);
}

/* Same icon / copy / action layout reused as a mid-page callout. */
.wd-final--brand {
  background: var(--wd-orange-050);
}

.wd-final__art {
  color: var(--wd-orange-500);
}

.wd-final h2 {
  font-size: clamp(1.375rem, 2.2vw, 1.75rem);
}

.wd-final__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
}


@media (max-width: 991.98px) {
  /* Stacks the banner. This must live with .wd-final in base — left behind in a
     page stylesheet it silently stopped applying on pages that don't load that
     file, and the three-column grid overflowed the viewport. */
  .wd-final {
    grid-template-columns: minmax(0, 1fr);
    text-align: center;
  }

  .wd-final__art {
    display: none;
  }

  .wd-final__actions {
    justify-content: center;
  }
}

@media (max-width: 575.98px) {
  .wd-final__actions .wd-btn {
    width: 100%;
  }
}

@media (max-width: 1099.98px) {
  /* Pillar responsive lives with the component. Left in a page stylesheet it
     stopped applying on pages that don't load that file, and the four-column
     grid overflowed the viewport. */
  .wd-pillars {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    row-gap: 2rem;
  }

  .wd-pillars li:nth-child(odd) {
    border-left: 0;
    padding-left: 0;
  }
}

@media (max-width: 575.98px) {
  .wd-pillars {
    grid-template-columns: minmax(0, 1fr);
  }

  .wd-pillars li + li {
    border-left: 0;
    padding-left: 0;
  }
}

/* ---------- plan / tier cards ----------
 * Promoted from the migration template once the product template needed the
 * same tier grid. Class names unchanged, so existing pages are unaffected.
 * The matching @media rules are at the bottom of this file — keeping a
 * component's responsive rules in a page stylesheet has silently broken layout
 * twice on this project.
 */
/* ---------- BLOCK C — plan options ---------- */

.wd-plans {
  display: grid;
  gap: clamp(1rem, 2vw, 1.5rem);
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.wd-plans--three {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

/* Tier feature list inside a plan card. */
.wd-plan__features {
  display: grid;
  gap: 0.625rem;
  list-style: none;
  margin: 0;
  padding: 0;
}

.wd-plan__features li {
  color: var(--wd-grey-700);
  display: grid;
  font-size: 0.9375rem;
  gap: 0.625rem;
  grid-template-columns: 1.125rem 1fr;
}

.wd-plan__features .wd-icon {
  color: var(--wd-success-600);
  height: 1.125rem;
  margin-top: 0.1875rem;
  width: 1.125rem;
}

.wd-plan {
  display: flex;
  flex-direction: column;
  gap: 0.875rem;
  position: relative;
}

/*
 * `flex-wrap` matters: a long badge ("Recommended when you need help") plus a
 * tier name could not fit on one line at 390px and pushed the page 11px wide.
 * Wrapping lets the badge drop below the name instead, and the max-width on
 * .wd-badge lets its own text wrap rather than forcing a wide box.
 */
.wd-plan__top {
  align-items: flex-start;
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  justify-content: space-between;
}

.wd-plan__logo {
  align-items: center;
  display: inline-flex;
  height: 2.75rem;
  justify-content: flex-start;
}

.wd-plan__logo img {
  height: 100% !important;
  max-width: 130px;
  object-fit: contain;
  width: auto;
}

.wd-plan h3 {
  font-size: clamp(1.125rem, 1.5vw, 1.25rem);
}

.wd-plan__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
}

.wd-plan .wd-body {
  margin-top: 0;
}

/* One recommended default per cohort — stated in text, not colour alone. */
.wd-plan--recommended {
  outline: 2px solid var(--wd-orange-500);
  outline-offset: -2px;
}

.wd-plan__price {
  border-top: 1px solid var(--wd-grey-100);
  margin-top: auto;
  padding-top: 0.875rem;
}

.wd-plan__price span {
  color: var(--wd-grey-500);
  display: block;
  font-size: 0.8125rem;
}

/* Dynamic token only — never a remembered dollar value. */
.wd-plan__price b {
  color: var(--wd-orange-700);
  font-size: 1rem;
  font-weight: 700;
  overflow-wrap: anywhere;
}

.wd-plan__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.625rem;
}

.wd-plan__actions .wd-btn {
  flex: 1 1 9rem;
}

/* Escape hatches: complex estates, and the approval-only local hosting case.
   Local Hosted Email is never presented as a normal product option. */
.wd-plans__notes {
  display: grid;
  gap: 0.5rem;
  margin: clamp(1.5rem, 2.5vw, 2rem) 0 0;
  text-align: center;
}

.wd-plans__notes p {
  color: var(--wd-grey-700);
  font-size: 0.9375rem;
  margin: 0;
}

.wd-plans__notes a {
  color: var(--wd-orange-700);
  font-weight: 600;
}

.wd-plans__notes a:hover,
.wd-plans__notes a:focus-visible {
  text-decoration: underline !important;
  text-underline-offset: 0.22em;
}


/* ---------- numbered process steps (dark surface) ---------- */
/* ---------- BLOCK D — how the migration works ---------- */

.wd-steps {
  background: var(--wd-slate-600);
  color: var(--wd-white);
}

.wd-steps .wd-section__head p {
  color: var(--wd-grey-200);
}

.wd-steps__list {
  counter-reset: wd-step;
  display: grid;
  gap: clamp(1.5rem, 3vw, 2.5rem);
  grid-template-columns: repeat(4, minmax(0, 1fr));
  list-style: none;
  margin: 0;
  padding: 0;
}

.wd-steps__list li {
  position: relative;
}

.wd-steps__list li::before {
  align-items: center;
  background: var(--wd-orange-500);
  border-radius: 50%;
  color: var(--wd-white);
  content: counter(wd-step);
  counter-increment: wd-step;
  display: flex;
  font-size: 1rem;
  font-weight: 700;
  height: 2.25rem;
  justify-content: center;
  margin-bottom: 1rem;
  width: 2.25rem;
}

.wd-steps__list h3 {
  font-size: 1.0625rem;
}

.wd-steps__list p {
  color: var(--wd-grey-200);
  font-size: 0.9375rem;
  margin: 0.375rem 0 0;
}

.wd-steps__note {
  border-top: 1px solid rgb(255 255 255 / 14%);
  color: var(--wd-grey-200);
  margin: clamp(2rem, 3.5vw, 3rem) 0 0;
  padding-top: clamp(1.5rem, 2.5vw, 2rem);
  text-align: center;
}

.wd-steps__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  justify-content: center;
  margin-top: 1.25rem;
}
.wd-final--brand {
  background: var(--wd-orange-050);
}

@media (max-width: 1099.98px) {
  .wd-steps__list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    row-gap: 2rem;
  }

  .wd-plans--three {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 991.98px) {
  .wd-plans,
  .wd-plans--three {
    grid-template-columns: minmax(0, 1fr);
  }
}

@media (max-width: 575.98px) {
  .wd-steps__list {
    grid-template-columns: minmax(0, 1fr);
  }

  .wd-steps__actions .wd-btn {
    width: 100%;
  }
}

/* ---------- comparison table ----------
 * Promoted from the router template once the product template needed it too.
 * Class names unchanged, so /email-office is unaffected.
 */
/* ---------- comparison table ---------- */

/*
 * A real table, because comparison IS the task here (design-system §12).
 * It scrolls inside its own container rather than pushing the page wide.
 */
.wd-ctable__scroll {
  -webkit-overflow-scrolling: touch;
  overflow-x: auto;
}

.wd-ctable {
  background: var(--wd-white);
  border-collapse: collapse;
  border-radius: var(--wd-radius-md);
  min-width: 44rem;
  overflow: hidden;
  width: 100%;
}

.wd-ctable th,
.wd-ctable td {
  border-bottom: 1px solid var(--wd-grey-100);
  padding: 0.875rem 1rem;
  text-align: left;
  vertical-align: middle;
}

.wd-ctable thead th {
  background: var(--wd-grey-050);
  border-bottom: 1px solid var(--wd-grey-200);
  font-size: 0.9375rem;
  font-weight: 700;
}

/* Row label column */
.wd-ctable tbody th {
  background: var(--wd-grey-050);
  color: var(--wd-grey-700);
  font-size: 0.875rem;
  font-weight: 600;
  white-space: nowrap;
}

.wd-ctable td {
  color: var(--wd-grey-700);
  font-size: 0.9375rem;
}

.wd-ctable tbody tr:last-child th,
.wd-ctable tbody tr:last-child td {
  border-bottom: 0;
}

/* Ticked cell — the icon is paired with text, never colour alone. */
.wd-ctable__yes {
  align-items: center;
  color: var(--wd-charcoal-900);
  display: flex;
  gap: 0.5rem;
}

.wd-ctable__yes .wd-icon {
  color: var(--wd-success-600);
  height: 1.0625rem;
  width: 1.0625rem;
}

/* ---------- fit / not-a-fit ----------
 * Promoted from the migration template once the product template needed it for
 * /web-hosting. Class names unchanged, so /email-office-upgrade and the other
 * migration pages are unaffected.
 *
 * The responsive rule moved WITH the component — leaving a component's @media
 * rules behind in a page stylesheet has silently broken layout twice here.
 */

/*
 * Honest qualification: says who this is NOT for and points them elsewhere,
 * rather than pushing every visitor at the same product.
 */
.wd-fit {
  display: grid;
  gap: clamp(1rem, 2vw, 1.5rem);
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.wd-fit h3 {
  font-size: clamp(1.0625rem, 1.5vw, 1.25rem);
}

.wd-fit ul {
  display: grid;
  gap: 0.75rem;
  list-style: none;
  margin: 1rem 0 0;
  padding: 0;
}

.wd-fit li {
  color: var(--wd-grey-700);
  display: grid;
  font-size: 0.9375rem;
  gap: 0.75rem;
  grid-template-columns: 1.25rem 1fr;
}

.wd-fit .wd-icon {
  height: 1.25rem;
  margin-top: 0.125rem;
  width: 1.25rem;
}

.wd-fit__yes .wd-icon {
  color: var(--wd-success-600);
}

.wd-fit__other {
  background: var(--wd-orange-050);
}

.wd-fit__other .wd-icon {
  color: var(--wd-orange-600);
}

/*
 * Text link with a trailing arrow. Standalone rather than scoped: it started
 * inside .wd-fit__other, then a third page wanted the same thing beside a
 * button, so it is a component now.
 *
 * `text-decoration` is !important because custom.css carries a global
 * `a:hover { text-decoration: none }` that would otherwise win.
 */
.wd-link-arrow {
  align-items: center;
  color: var(--wd-orange-700);
  display: inline-flex;
  font-weight: 600;
  gap: 0.5rem;
  min-height: 44px;
}

.wd-link-arrow:hover,
.wd-link-arrow:focus-visible {
  color: var(--wd-orange-700) !important;
  text-decoration: underline !important;
  text-underline-offset: 0.22em;
}

/* Inside the not-a-fit card it closes a list, so it needs the separation. */
.wd-fit__other .wd-link-arrow {
  margin-top: 1.25rem;
}

/*
 * Rows of "condition -> better page" inside the not-a-fit card. A grid rather
 * than a list of links, so the condition and its destination stay on one line
 * and the arrows align down the right edge.
 */
.wd-fit__routes {
  border-top: 1px solid rgb(244 124 32 / 22%);
  display: grid;
  gap: 0;
  list-style: none;
  margin: 1rem 0 0;
  padding: 0;
}

.wd-fit__routes li {
  align-items: center;
  border-bottom: 1px solid rgb(244 124 32 / 22%);
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  justify-content: space-between;
  padding: 0.75rem 0;
}

.wd-fit__routes li:last-child {
  border-bottom: 0;
}

.wd-fit__routes a {
  align-items: center;
  color: var(--wd-orange-700);
  display: inline-flex;
  font-weight: 600;
  gap: 0.625rem;
  min-height: 44px;
}

.wd-fit__routes a:hover,
.wd-fit__routes a:focus-visible {
  color: var(--wd-orange-700) !important;
  text-decoration: underline !important;
  text-underline-offset: 0.22em;
}

@media (max-width: 991.98px) {
  .wd-fit {
    grid-template-columns: minmax(0, 1fr);
  }
}


/* ============================================================================
 * PROMOTED COMPONENTS
 *
 * These began life in webdev-product.css and moved here once the consultative
 * template (/enterprise-infrastructure) needed the same pieces. Class names are
 * unchanged, so /web-hosting, /wordpress-hosting, /vps-hosting and /managed-vps
 * did not have to change.
 *
 * Their @media rules moved WITH them. Leaving a component's responsive rules
 * behind in a page stylesheet has silently broken layout twice on this project.
 * ==========================================================================*/

/* ---------- resource specification rows ----------
 * The VPS tiers sell on resources, so the card body is a spec sheet rather than
 * a benefit list. Only the figure the tier is NAMED for is stated here; every
 * other value defers to WHMCS, because resources and add-on availability change
 * and a remembered number on a marketing page goes stale silently.
 */
.wd-plan__specs {
  display: grid;
  list-style: none;
  margin: 0;
  padding: 0;
}

.wd-plan__specs li {
  align-items: center;
  border-bottom: 1px solid var(--wd-grey-100);
  display: flex;
  font-size: 0.875rem;
  gap: 0.625rem;
  padding: 0.6875rem 0;
}

.wd-plan__specs li:last-child {
  border-bottom: 0;
}

.wd-plan__specs .wd-icon {
  color: var(--wd-grey-500);
  flex: 0 0 auto;
  height: 1.0625rem;
  width: 1.0625rem;
}

.wd-plan__specs span {
  color: var(--wd-grey-700);
}

/* The named figure — the one thing that differs between tiers. */
.wd-plan__specs b {
  color: var(--wd-charcoal-900);
  font-weight: 600;
  margin-left: auto;
  text-align: right;
}

/* Deferred to checkout. Quieter than the named figure on purpose. */
.wd-plan__specs em {
  color: var(--wd-grey-500);
  font-style: normal;
  margin-left: auto;
  text-align: right;
}


/* ---------- responsibility split ----------
 * Two facing columns: what the customer owns and what Webdev owns. Setting this
 * out plainly BEFORE checkout is what stops an unmanaged sale turning into a
 * support expectation nobody agreed to.
 */
.wd-split {
  display: grid;
  gap: clamp(1rem, 2vw, 1.5rem);
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.wd-split h3 {
  align-items: center;
  display: flex;
  font-size: 1.0625rem;
  gap: 0.625rem;
}

/*
 * `color` is not decoration here. This card sits on a dark section, which sets
 * white text on its container — a white card inheriting that renders its heading
 * white on white. Any light surface placed inside a dark panel has to re-state
 * its ink.
 */
.wd-split__card {
  background: var(--wd-white);
  border-radius: var(--wd-card-radius);
  box-shadow: var(--wd-card-shadow);
  color: var(--wd-charcoal-900);
  padding: clamp(1.25rem, 2vw, 1.75rem);
}

.wd-split__card .wd-icon {
  color: var(--wd-orange-600);
}

/* Outlined rather than filled: on a dark section a second solid card would read
   as the same surface twice. */
.wd-split__card--outline {
  background: transparent;
  border: 1px solid var(--wd-orange-500);
  box-shadow: none;
  color: var(--wd-white);
}

.wd-split__card--dark {
  background: var(--wd-charcoal-950);
  box-shadow: none;
  color: var(--wd-white);
}

.wd-split__card--outline h3,
.wd-split__card--dark h3 {
  color: var(--wd-orange-500);
}

.wd-split__card--outline .wd-icon,
.wd-split__card--dark .wd-icon {
  color: var(--wd-orange-500);
}

/* Ticked list. Orange rather than the green of .wd-plan__features: these are
   responsibilities and inclusions, not features being sold. */
.wd-checklist {
  display: grid;
  gap: 0.5rem;
  list-style: none;
  margin: 0.875rem 0 0;
  padding: 0;
}

.wd-checklist li {
  align-items: start;
  color: var(--wd-grey-700);
  display: grid;
  font-size: 0.9375rem;
  gap: 0.625rem;
  grid-template-columns: 1.125rem 1fr;
}

.wd-checklist .wd-icon {
  color: var(--wd-orange-600);
  height: 1.125rem;
  margin-top: 0.1875rem;
  width: 1.125rem;
}

.wd-split__card--outline .wd-checklist li,
/*
 * `.wd-body` sets its own --wd-grey-700, which beats the white inherited from
 * the card. Base already fixes this for .wd-panel--dark / --black, but a dark
 * card sitting on a LIGHT section is not inside either of those, so the
 * paragraph rendered dark-grey on near-black — a contrast failure, not just a
 * cosmetic one. Same reason .wd-lead is covered here.
 */
.wd-split__card--dark .wd-body,
.wd-split__card--dark .wd-lead,
.wd-split__card--outline .wd-body,
.wd-split__card--outline .wd-lead {
  color: var(--wd-grey-200);
}

.wd-split__card--dark .wd-checklist li {
  color: var(--wd-grey-200);
}

.wd-split__card--outline .wd-checklist .wd-icon,
.wd-split__card--dark .wd-checklist .wd-icon {
  color: var(--wd-orange-500);
}

/*
 * Sub-label above a checklist, where the column already has a section h2 and the
 * list needs its own quieter heading.
 *
 * Scoped to .wd-page for specificity: base sets `.wd-page h3 { color: inherit }`
 * at (0,2,0), which beats a bare class at (0,1,0) — an unscoped rule here left
 * the label inheriting the body colour instead of taking the brand orange.
 */
.wd-page .wd-split__lead {
  color: var(--wd-orange-700);
  margin: 1.5rem 0 0;
}

/* The split's own mark. Base only brightens .wd-icon-plate on dark panels, and
   this block sits on the cream one. */
.wd-split .wd-icon-plate {
  color: var(--wd-orange-500);
}

.wd-split__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  grid-column: 1 / -1;
  justify-content: center;
  margin-top: 0.25rem;
}

@media (max-width: 767.98px) {
  .wd-split {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ---------- full-width closing CTA ---------- */

/*
 * The orange band. Buttons on it are white-filled rather than orange, since an
 * orange button on orange has no edge.
 */
.wd-ctaband {
  background: var(--wd-orange-500);
  color: var(--wd-white);
  text-align: center;
}

.wd-ctaband h2 {
  color: var(--wd-white);
}

/*
 * `.wd-lead` sets its own --wd-grey-700, which beats the white inherited from
 * the band — dark grey on orange, a contrast failure. Same trap as the dark
 * panels above: a direct rule always wins over an inherited one. Four pages put
 * a lead in this band, so it is fixed once here rather than per page.
 */
.wd-ctaband .wd-lead,
.wd-ctaband .wd-body {
  color: rgb(255 255 255 / 92%);
}

.wd-ctaband__actions {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  justify-content: center;
  margin-top: clamp(1.25rem, 2.5vw, 1.75rem);
}

.wd-ctaband .wd-btn--primary {
  background: var(--wd-white);
  border-color: var(--wd-white);
  color: var(--wd-orange-700);
}

@media (hover: hover) and (pointer: fine) {
  .wd-ctaband .wd-btn--primary:hover {
    background: var(--wd-white);
    border-color: var(--wd-white);
    color: var(--wd-orange-700) !important;
    transform: translateY(-2px);
  }
}

.wd-ctaband .wd-btn--primary:focus-visible {
  box-shadow:
    0 0 0 2px var(--wd-orange-500),
    0 0 0 5px var(--wd-white);
}

/*
 * Second action on the band. The page-wide .wd-btn--secondary is a dark outline
 * on white, which disappears on orange — this re-cuts it as a white outline so
 * the two actions stay clearly ranked without a second solid button competing
 * with the first.
 */
.wd-ctaband .wd-btn--secondary {
  background: transparent;
  border-color: var(--wd-white);
  color: var(--wd-white);
}

@media (hover: hover) and (pointer: fine) {
  .wd-ctaband .wd-btn--secondary:hover {
    background: rgb(255 255 255 / 14%);
    border-color: var(--wd-white);
    color: var(--wd-white) !important;
  }
}

.wd-ctaband .wd-btn--secondary:focus-visible {
  box-shadow:
    0 0 0 2px var(--wd-orange-500),
    0 0 0 5px var(--wd-white);
}

/* Text link beside the button, underlined so it is not colour-only. */
.wd-ctaband__link {
  align-items: center;
  color: var(--wd-white);
  display: inline-flex;
  font-weight: 700;
  gap: 0.5rem;
  min-height: 44px;
  text-decoration: underline !important;
  text-underline-offset: 0.22em;
}

.wd-ctaband__link:hover {
  color: var(--wd-white) !important;
}

.wd-ctaband__link:focus-visible {
  border-radius: var(--wd-radius-sm);
  box-shadow:
    0 0 0 2px var(--wd-orange-500),
    0 0 0 5px var(--wd-white);
  outline: 0;
}

/* The band's own responsive rule — moved here with it rather than left behind in
   the page stylesheet. */
@media (max-width: 575.98px) {
  .wd-ctaband__actions .wd-btn {
    width: 100%;
  }
}

/* ---------- six-step process ----------
 * Promoted from webdev-router.css once the consultative template needed it too
 * (/websites uses it, /custom-websites now does as well). Class name unchanged.
 *
 * These MUST sit after the .wd-steps__list @media blocks earlier in this file.
 * Media queries add no specificity, so --six (0,1,0) and .wd-steps__list (0,1,0)
 * tie and source order decides the winner. Breakpoints mirror the base ones so
 * nothing is left half-applied.
 */
.wd-steps__list--six {
  grid-template-columns: repeat(6, minmax(0, 1fr));
}

@media (max-width: 1099.98px) {
  .wd-steps__list--six {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    row-gap: 2rem;
  }
}

@media (max-width: 575.98px) {
  .wd-steps__list--six {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* ---------- dark "strong fit" card ----------
 * Promoted from webdev-product.css once the consultative template needed the
 * same treatment. /managed-websites and /custom-websites both use it.
 *
 * The fit block itself is above. When the positive column is dark, its ink has
 * to be re-stated — a light surface's colours do not carry over.
 */
.wd-fit__yes--dark {
  background: var(--wd-charcoal-950);
  color: var(--wd-white);
}

.wd-fit__yes--dark h3 {
  color: var(--wd-white);
}

.wd-fit__yes--dark li {
  color: var(--wd-grey-200);
}

/* Small label above a fit card's heading. */
.wd-fit__label {
  color: var(--wd-orange-500);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  margin: 0 0 0.5rem;
  text-transform: uppercase;
}

.wd-fit__other .wd-fit__label {
  color: var(--wd-orange-700);
}

/* ---------- factual proof band ----------
 * Promoted from webdev-portfolio.css once /website-builder needed the same
 * band. Figures only, no adjectives — every number must be traceable to the
 * approved source, so pages carry their own note about provenance.
 */
.wd-stats {
  display: grid;
  gap: clamp(1.5rem, 3vw, 2.5rem);
  grid-template-columns: repeat(4, minmax(0, 1fr));
  list-style: none;
  margin: 0;
  padding: 0;
  text-align: center;
}

.wd-stats li + li {
  border-left: 1px solid rgb(255 255 255 / 12%);
}

.wd-stats b {
  color: var(--wd-orange-500);
  display: block;
  font-size: clamp(1.5rem, 3vw, 2rem);
  font-weight: 700;
  line-height: 1.1;
}

.wd-stats span {
  color: var(--wd-grey-200);
  display: block;
  font-size: 0.875rem;
  margin-top: 0.375rem;
}

@media (max-width: 767.98px) {
  .wd-stats {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    row-gap: 2rem;
  }

  .wd-stats li:nth-child(odd) {
    border-left: 0;
  }
}

@media (max-width: 419.98px) {
  .wd-stats {
    grid-template-columns: minmax(0, 1fr);
  }

  .wd-stats li + li {
    border-left: 0;
  }
}

/* ---------- SOLID BRAND SURFACE ----------
 * The sibling of .wd-on-dark, for a card that should read as full Webdev
 * orange rather than the orange-050 wash: --wd-orange-500 with white type.
 *
 * Two things this has to handle, both of which bit the dark panels first:
 *  1. .wd-body and .wd-lead carry their own dark colour, which beats the white
 *     inherited from the container. They must be re-stated here.
 *  2. The buttons are entirely token-driven, so overriding the custom
 *     properties (not `background`/`color`) is what also fixes their hover
 *     state. A primary button on orange has to invert to a white fill, or it
 *     disappears into the card.
 *
 * Opt in per element; nothing takes this automatically.
 */
.wd-on-brand {
  background: var(--wd-orange-500);
  border-color: transparent;
  color: var(--wd-white);
}

.wd-on-brand.wd-on-brand h2,
.wd-on-brand.wd-on-brand h3,
.wd-on-brand.wd-on-brand .wd-final__art,
.wd-on-brand.wd-on-brand .wd-icon,
.wd-on-brand.wd-on-brand .wd-icon-plate {
  color: var(--wd-white);
}

/*
 * Doubled class, deliberately. Page layers load AFTER this file, and several
 * of them colour their own descendants at the same specificity --
 * `.wd-compare li` is (0,1,1), exactly what `.wd-on-brand li` would be, so the
 * later file would win and leave dark grey text on solid orange. (0,3,1) puts
 * this beyond every page-layer rule without an !important contest.
 */
.wd-on-brand.wd-on-brand .wd-body,
.wd-on-brand.wd-on-brand .wd-lead,
.wd-on-brand.wd-on-brand li,
.wd-on-brand.wd-on-brand p {
  color: rgb(255 255 255 / 92%);
}

/*
 * Divider rules inside the card need to be light. .wd-fit__routes draws its
 * rules in orange-22%, which is invisible once the card itself is orange, so it
 * is named explicitly rather than left to the generic rule.
 */
.wd-on-brand hr,
.wd-on-brand li + li,
.wd-on-brand .wd-fit__routes,
.wd-on-brand .wd-fit__routes li {
  border-color: rgb(255 255 255 / 30%);
}

/* White fill, orange label — the inverse of the normal primary. */
.wd-on-brand .wd-btn--primary {
  --wd-btn-bg: var(--wd-white);
  --wd-btn-border: var(--wd-white);
  --wd-btn-color: var(--wd-orange-700);
  --wd-btn-hover-bg: var(--wd-orange-050);
  --wd-btn-hover-border: var(--wd-white);
  --wd-btn-hover-color: var(--wd-orange-700);
}

.wd-on-brand .wd-btn--secondary,
.wd-on-brand .wd-btn--ghost {
  --wd-btn-bg: transparent;
  --wd-btn-border: rgb(255 255 255 / 55%);
  --wd-btn-color: var(--wd-white);
  --wd-btn-hover-bg: rgb(255 255 255 / 12%);
  --wd-btn-hover-border: var(--wd-white);
  --wd-btn-hover-color: var(--wd-white);
}

/*
 * .wd-on-dark's secondary rule sets `background`/`color` directly, so it beats
 * the custom properties above wherever both classes could apply. Scoped reset
 * so .wd-on-brand always wins on its own card.
 */
.wd-on-brand .wd-btn--secondary {
  background: var(--wd-btn-bg);
  color: var(--wd-btn-color);
}

/*
 * Standalone links inside a brand card. .wd-link-arrow is orange-700, which on
 * orange-500 is effectively invisible — it has to go white, and it keeps an
 * underline because colour alone no longer distinguishes it from the body copy.
 */
.wd-on-brand.wd-on-brand a:not(.wd-btn) {
  color: var(--wd-white);
  text-decoration: underline;
  text-underline-offset: 0.22em;
}

/*
 * !important only because .wd-fit__routes a:hover already carries one; without
 * matching it the link would turn orange-700 on orange mid-hover and vanish.
 */
.wd-on-brand.wd-on-brand a:not(.wd-btn):hover,
.wd-on-brand.wd-on-brand a:not(.wd-btn):focus-visible {
  color: var(--wd-white) !important;
  text-decoration-thickness: 2px;
}

/*
 * Components that set their own ink INSIDE a brand card.
 *
 * These are not decoration — each was rendering near-black or orange-700 on
 * orange-500 the moment its card took .wd-on-brand, which is a contrast failure
 * rather than a cosmetic one. Doubled class for the same reason as above: the
 * owning rules live in later stylesheets at (0,1,1) and would win the tie.
 *
 *   .wd-buildfee__tiers  — /managed-websites, the build-fee card
 *   .wd-plan__price      — /custom-websites, the "Managed Websites from" price
 */
.wd-on-brand.wd-on-brand .wd-buildfee__tiers b,
.wd-on-brand.wd-on-brand .wd-plan__price b {
  color: var(--wd-white);
}

.wd-on-brand.wd-on-brand .wd-buildfee__tiers span,
.wd-on-brand.wd-on-brand .wd-plan__price span {
  color: rgb(255 255 255 / 88%);
}

/* ---------- WHMCS domain banners ----------
 * Gives the three domain pages the banner the marketing site carries, so a
 * visitor arriving from /hosting or the nav does not cross a visible seam into
 * the order flow:
 *
 *   /domain-registration/            --domains   (cart.php, domain=register)
 *   /cart.php?a=add&domain=transfer  --transfer
 *   /index.php?rp=/domain/pricing    --pricing
 *
 * IN BASE, NOT webdev-cart.css. The first two load the order form's stylesheet;
 * the pricing page does not. webdev-base.css is the only file all three pull,
 * so it is the only place one definition can serve them.
 *
 * SCOPED, deliberately. The band itself is `.top-header` in header.tpl, which
 * EVERY cart and order page renders — product groups, view-cart, checkout. Only
 * the three branches above add `.wd-carthero`, so nothing else changes.
 *
 * On WHMCS pages `.top-header` comes from the theme's main.min.css, which loads
 * before this file, so single-class selectors here already beat `.item17` and
 * `.overlay` without an !important contest on layout. The order form's own
 * style.css loads after this file but defines no `.top-header` rules — checked.
 *
 * Artwork is referenced by ABSOLUTE path. Order pages resolve relative URLs
 * against templates/orderforms/antler/css/ and the pricing page against
 * templates/antler/html/assets/css/, so no single relative hop works for both.
 *
 * ---------------------------------------------------------------------------
 * THIS FOLLOWS THE SUBHERO, NOT THE HOMEPAGE HERO.
 *
 * Two hero patterns exist on the site and they invert each other. Measured at
 * 1920px:
 *
 *   homepage (.wd-hero)      eyebrow 14px orange caps  ->  h1 60px white
 *   subhero  (.wd-subhero)   eyebrow 40px orange caps  ->  h1 28px white
 *
 * These are internal pages, so they take the SUBHERO one — the big orange caps
 * line carries the page, with a smaller white statement under it. That is what
 * /careers, /contact-us, /websites and every other internal page do, and these
 * three sit in the same navigation.
 *
 * Every value below is lifted from the .wd-subhero rules earlier in this file
 * rather than re-invented, so the two cannot drift.
 */
.wd-carthero {
  align-items: center;
  background-color: var(--wd-charcoal-950, #111416);
  background-image:
    linear-gradient(
      100deg,
      var(--wd-charcoal-950, #111416) 0%,
      var(--wd-charcoal-950, #111416) 24%,
      rgb(17 20 22 / 80%) 42%,
      rgb(17 20 22 / 30%) 66%,
      rgb(17 20 22 / 0%) 100%
    ),
    var(--wd-carthero-art);
  background-position: center, right center;
  background-repeat: no-repeat, no-repeat;
  background-size: cover, cover;
  /* Without this, min-height applies to the CONTENT box and the padding is
     added on top, overshooting the target by the full padding. */
  box-sizing: border-box;
  display: flex;
  /*
   * The vendor rule sets 200px/100px, sized for a full-bleed marketing banner.
   * The marketing heroes are content-driven and settle near 480px from about
   * 1200px up, so this clamp is tuned to PLATEAU there rather than track the
   * viewport — a pure vw value matched at 1920 and came out 83px short at 1440.
   */
  min-height: clamp(20rem, 26vw + 8rem, 30rem);
  padding: clamp(2.75rem, 5vw, 4.25rem) 0 clamp(2.25rem, 4vw, 3.25rem);
}

/*
 * `.overlay` paints a flat `rgba(0,0,0,.6)` sheet over the whole band through a
 * ::before. That is what the directional scrim above replaces — left both, the
 * artwork sits under two overlays and goes muddy. `content: none` removes the
 * pseudo-element outright rather than making it transparent.
 */
.wd-carthero.overlay::before {
  content: none;
}

/* Matches .wd-shell on the marketing pages so the copy starts on the same
   vertical line as every other page's hero. */
.wd-carthero > .container {
  margin: 0 auto;
  max-width: var(--wd-container, 1320px);
  padding: 0 clamp(1rem, 3vw, 1.5rem);
  width: 100%;
}

.wd-carthero .wrapper {
  max-width: 46rem;
}

/*
 * Values from `.wd-subhero .wd-eyebrow` + `.wd-eyebrow--brand` above. This is
 * the dominant line of the band, not a label above the title.
 */
.wd-carthero__eyebrow {
  color: var(--wd-orange-600, #df6812);
  font-family: var(--wd-font-sans);
  font-size: clamp(1.5rem, 3.4vw, 2.5rem);
  font-weight: 700;
  letter-spacing: 0.01em;
  line-height: 1.15;
  margin: 0 0 0.625rem;
  /*
   * 30ch, not the 20ch `.wd-subhero .wd-eyebrow` uses. The marketing eyebrows
   * are one or two words ("Careers", "Our website portfolio"); this one is
   * "Domains & online identity", which broke across two lines at 20ch and
   * pushed the heading down. Still wraps on narrow screens, which is wanted.
   */
  max-width: 30ch;
  text-transform: uppercase;
}

/*
 * !important on every declaration the vendor also sets. The vendor selector is
 * `.top-header .wrapper .heading`, (0,3,0), and this band still carries
 * `.top-header`. Matching that without !important would mean repeating the
 * whole ancestor chain, which breaks the moment header.tpl markup changes.
 *
 * font-family carries it for a second reason: the theme ships
 * `body[data-font="poppins"] h1 { font-family: ... !important }`, which beats
 * any non-important declaration and would leave this banner in the theme face
 * while every other hero is in ours.
 *
 * Size and max-width are `.wd-subhero h1` above; weight, colour and tracking
 * are `.wd-page h1`.
 */
.wd-carthero .wrapper .heading {
  color: var(--wd-white, #fff) !important;
  font-family: var(--wd-font-sans) !important;
  font-size: clamp(1.375rem, 2.2vw, 1.75rem) !important;
  font-weight: 700;
  letter-spacing: -0.015em;
  line-height: 1.08;
  margin: 0;
  max-width: 34ch;
  text-transform: none !important;
}

/* Values from `.wd-lead` + `.wd-subhero .wd-lead` above. */
.wd-carthero__lead {
  color: var(--wd-grey-200, #d9dee3);
  font-family: var(--wd-font-sans);
  font-size: clamp(1.0625rem, 1.3vw, 1.125rem);
  line-height: 1.6;
  margin: 1rem 0 0;
  max-width: 54ch;
}

/* ---------- TLD row ----------
 * Same pill as .wd-chips on the marketing heroes, so this reads as the site's
 * chip component rather than a one-off. Spacing follows .wd-chips too.
 */
.wd-carthero__tlds {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: clamp(1.5rem, 3vw, 2rem) 0 0;
}

.wd-tld {
  align-items: center;
  background: rgb(255 255 255 / 8%);
  border: 1px solid rgb(255 255 255 / 18%);
  border-radius: var(--wd-radius-pill, 999px);
  color: var(--wd-white, #fff);
  display: inline-flex;
  font-family: var(--wd-font-sans);
  font-size: 0.9375rem;
  font-weight: 600;
  gap: 0.375rem;
  line-height: 1;
  padding: 0.625rem 1.125rem;
  white-space: nowrap;
}

/* .co.zw is the extension Webdev is the registrar for, so it leads. */
.wd-tld--primary {
  background: var(--wd-orange-500, #f47c20);
  border-color: var(--wd-orange-500, #f47c20);
}

/*
 * The only link in the row. Outlined rather than filled so it does not compete
 * with the primary chip. `text-decoration` needs !important because the theme
 * ships `a { text-decoration: none !important }` in style.css — matching that
 * is the only way to keep control of the property here.
 */
.wd-tld--more {
  background: none;
  border-color: var(--wd-orange-500, #f47c20);
  color: var(--wd-orange-500, #f47c20);
  text-decoration: none !important;
  transition: background-color 0.2s ease, color 0.2s ease;
}

.wd-tld--more svg {
  fill: none;
  height: 1rem;
  stroke: currentColor;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-width: 1.75;
  width: 1rem;
}

/*
 * The hover colour needs !important for the same reason: custom.css ships
 * `a:hover { color: #f0682a !important }`, which would otherwise leave orange
 * text sitting on an orange fill.
 */
@media (hover: hover) and (pointer: fine) {
  .wd-tld--more:hover {
    background: var(--wd-orange-500, #f47c20);
    color: var(--wd-white, #fff) !important;
  }
}

.wd-tld--more:focus-visible {
  box-shadow: var(--wd-focus, 0 0 0 3px rgb(244 124 32 / 45%));
  outline: 0;
}

/* ---------- per-page artwork ----------
 * One variable per variant, so a page can be given its own image with a single
 * line and no duplicated gradient. header.tpl picks the variant by setting
 * $wdArt; the class is .wd-carthero--{$wdArt}.
 *
 * Every file below is ALREADY LIVE — these are the marketing heroes being
 * reused, not new uploads. Reuse is the point: a visitor moving from /hosting
 * to the VPS store page sees the same server aisle, and the image is already
 * in their cache.
 *
 * --default is the fallback for any page without a mapping, including every
 * WHMCS page nobody has assigned artwork to yet. subhero.jpg is the site's
 * existing generic hero art: dark abstract network, flat on the left where the
 * copy sits. A page with no mapping therefore looks deliberate rather than
 * unfinished.
 */
.wd-carthero--default {
  --wd-carthero-art: url("/templates/antler/html/assets/img/subhero.jpg");
}

/* Domain pages. All three share the magnifier: it is the domain category's
   artwork, the same way the Websites category shares one image. */
.wd-carthero--domains,
.wd-carthero--transfer,
.wd-carthero--pricing {
  --wd-carthero-art: url("/templates/antler/html/assets/img/search-hero.jpg");
}

/* Anything server-shaped: VPS, mail VPS, security and speed add-ons. Matches
   the artwork on /hosting and /web-hosting. */
.wd-carthero--servers {
  --wd-carthero-art: url("/templates/antler/html/assets/img/server-room-hero.jpg");
}

/* Mailboxes and sending. Matches /email-office. */
.wd-carthero--mail {
  --wd-carthero-art: url("/templates/antler/html/assets/img/emailandoffice.jpg");
}

/* Matches /google-workspace. */
.wd-carthero--workspace {
  --wd-carthero-art: url("/templates/antler/html/assets/img/workspace-hero.jpg");
}

/* Matches /microsoft-365. */
.wd-carthero--microsoft {
  --wd-carthero-art: url("/templates/antler/html/assets/img/microsoft-hero.jpg");
}

/* Matches /websites, /managed-websites and /custom-websites. */
.wd-carthero--websites {
  --wd-carthero-art: url("/templates/antler/html/assets/img/websitespage.jpg");
}

/* Our own support floor. Used where the page is about talking to us rather
   than buying something — knowledge base, pre-sales contact. Matches
   /contact-us. */
.wd-carthero--support {
  --wd-carthero-art: url("/templates/antler/html/assets/img/salessupport.jpg");
}
