/* ===== services.css ===== */
/* banner-2285-4 */
@media only screen and (min-width:0rem){:is(#banner-2285, #banner-2285-2, #banner-2285-3, #banner-2285-4){z-index:1;position:relative;background-color:black;overflow:hidden;padding:var(--sectionPadding);padding-top:clamp(11.875rem,25vw,17.5rem);padding-bottom:0rem}:is(#banner-2285, #banner-2285-2, #banner-2285-3, #banner-2285-4) .cs-container{display:flex;flex-direction:column;justify-content:center;align-items:flex-start;margin:auto;max-width:80rem;width:100%;text-align:center}:is(#banner-2285, #banner-2285-2, #banner-2285-3, #banner-2285-4) .cs-int-title{position:relative;margin:0 0 1rem;text-transform:uppercase;font-family:var(--headerFont);font-size:clamp(2.4375rem,6.4vw,3.8125rem);line-height:1.2em;font-weight:700;color:var(--bodyTextColorWhite);text-align:inherit}:is(#banner-2285, #banner-2285-2, #banner-2285-3, #banner-2285-4) .cs-text{margin-bottom:clamp(3.75rem,7vw,7.5rem);max-width:43.75rem;color:var(--bodyTextColorWhite);text-align:left}:is(#banner-2285, #banner-2285-2, #banner-2285-3, #banner-2285-4) .cs-breadcrumbs{z-index:1;position:relative;display:flex;justify-content:center;align-items:center;padding:clamp(1rem,3vw,1.5rem)0}:is(#banner-2285, #banner-2285-2, #banner-2285-3, #banner-2285-4) .cs-breadcrumbs:before{z-index:-1;position:absolute;top:0;left:50%;content:"";opacity:0.12;transform:translateX(-50%);display:block;background-color:#fff;height:100%;width:200vw}:is(#banner-2285, #banner-2285-2, #banner-2285-3, #banner-2285-4) .cs-breadcrumbs:after{z-index:-1;position:absolute;top:0;left:50%;content:"";transform:translateX(-50%);display:block;height:100%;width:200vw;backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px)}:is(#banner-2285, #banner-2285-2, #banner-2285-3, #banner-2285-4) .cs-link{position:relative;display:flex;justify-content:center;align-items:center;text-decoration:none;text-transform:uppercase;font-size:1rem;line-height:1.2em;color:var(--bodyTextColorWhite)}:is(#banner-2285, #banner-2285-2, #banner-2285-3, #banner-2285-4) .cs-link:last-of-type{}:is(#banner-2285, #banner-2285-2, #banner-2285-3, #banner-2285-4) .cs-link:last-of-type::after{display:none}:is(#banner-2285, #banner-2285-2, #banner-2285-3, #banner-2285-4) .cs-link:after{position:relative;content:"";display:block;margin:0 1rem;background-color:#88898b;height:1.5rem;width:0.0625rem}:is(#banner-2285, #banner-2285-2, #banner-2285-3, #banner-2285-4) .cs-link.cs-active{color:var(--primaryLight)}:is(#banner-2285, #banner-2285-2, #banner-2285-3, #banner-2285-4) .cs-background{z-index:-1;position:absolute;top:0;left:0;display:block;height:100%;width:100%}:is(#banner-2285, #banner-2285-2, #banner-2285-3, #banner-2285-4) .cs-background img{z-index:-1;position:absolute;top:0;left:0;height:100%;width:100%;-o-object-fit:cover;object-fit:cover}:is(#banner-2285, #banner-2285-2, #banner-2285-3, #banner-2285-4) .cs-background:before{z-index:1;position:absolute;top:0;left:0;content:"";opacity:0.72;display:block;background:#000;height:100%;width:100%}}

/* cs-content-832-2 */
@media only screen and (min-width:0rem){:is(#cs-content-832, #cs-content-832-2){display:flex;flex-direction:column;align-items:flex-start;margin-inline:auto;max-width:80rem;width:100%;padding:var(--sectionPadding);padding-bottom:clamp(2rem,5vw,4rem);text-align:left}:is(#cs-content-832, #cs-content-832-2) .cs-flex-group{flex:none}}@media only screen and (min-width:48rem){:is(#cs-content-832, #cs-content-832-2){flex-direction:row;justify-content:space-between;align-items:flex-end;gap:3rem}:is(#cs-content-832, #cs-content-832-2) .cs-flex-group{width:50%}:is(#cs-content-832, #cs-content-832-2) .cs-text{max-width:32rem}:is(#cs-content-832, #cs-content-832-2) .cs-title{margin-bottom:0;max-width:36rem}}@media only screen and (min-width:90rem){:is(#cs-content-832, #cs-content-832-2){padding-right:0;padding-left:0}}

/* in-page-navigation */
@media only screen and (min-width:0rem){#in-page-navigation{z-index:999;position:sticky;top:8.5rem;background-color:#fff;padding:var(--sectionPadding);padding-top:1.5rem;padding-bottom:0}#in-page-navigation .cs-container{margin:auto;max-width:80rem}#in-page-navigation .cs-ul{display:flex;margin:0;width:100%;overflow-x:auto;padding:0;list-style:none;gap:2rem}#in-page-navigation .cs-li{max-width:15.625rem;padding-bottom:1.5rem;flex:1 0 auto}#in-page-navigation .cs-link{display:flex;align-items:center;text-decoration:none;gap:clamp(0.75rem,1vw,1rem)}#in-page-navigation .cs-h3{width:100%;font-size:clamp(1rem,1vw,1.25rem);line-height:1.5em;font-weight:700;color:var(--headerColor)}body.dark-mode #in-page-navigation{background-color:var(--dark)}body.dark-mode #in-page-navigation .cs-h3{color:var(--bodyTextColorWhite)}body.dark-mode #in-page-navigation .cs-icon{filter:invert(1) brightness(1000%)}}

/* ---------- offering rows: #windows, #new-construction-windows,
   #energy-efficient-glass, #doors, #patio-sliding-doors, #how-it-works ----------
   These six ship with .RPsbs-2278 / .RPsbsr-2278 (alternating so the photo swaps
   sides row to row), but no stylesheet in this repo has ever defined either
   class — confirmed against every .css file, and it's there in the very first
   commit, so the export dropped this component's CSS from day one. Everything
   these rows have today (heading weight, button styling) comes from the
   handful of classes that happen to be global in root.css; the row layout,
   picture sizing and alternating tint never existed.

   Rebuilt from the same numbered component (2278) shipped for a sibling
   CodeStitch export at _reference/clarkes-construction.netlify.app/services.css,
   which still has it intact. Two changes from that copy: the cream half-bleed
   (#fefaf6) is swapped for this site's own --lightGrey token so it reads as
   this brand and not the other client's, and the .cs-header/.cs-title/
   .cs-number rules are dropped — our markup never puts those classes inside
   these sections, so they'd be dead weight. */
.RPsbs-2278,
.RPsbsr-2278 {
  z-index: 1;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: var(--sectionPadding);
  gap: clamp(3rem, 6vw, 4rem);
  scroll-margin-top: 12rem;
}

.RPsbs-2278 .cs-container,
.RPsbsr-2278 .cs-container {
  z-index: 1;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  margin: auto;
  max-width: 43.75rem;
  width: 100%;
  padding: var(--sectionPadding);
  padding-right: 0;
  padding-left: 0;
  gap: clamp(3rem, 6vw, 4rem);
}

/* Full-viewport-wide tint behind the row, offset toward the picture side —
   keeps six rows in a row from reading as one flat white page without a
   background colour on every individual section. */
.RPsbs-2278 .cs-container::before,
.RPsbsr-2278 .cs-container::before {
  z-index: -1;
  position: absolute;
  top: 0;
  left: 50%;
  content: "";
  transform: translateX(-50%);
  display: block;
  background: var(--lightGrey);
  height: 100%;
  width: 100vw;
}

.RPsbs-2278 .cs-content,
.RPsbsr-2278 .cs-content {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  max-width: 42.875rem;
  width: 100%;
  text-align: left;
}

.RPsbs-2278 .cs-h3,
.RPsbsr-2278 .cs-h3 {
  margin: 0 0 1rem;
  text-transform: uppercase;
  font-size: clamp(1.5625rem, 4vw, 2.4375rem);
  line-height: 1.2em;
  color: var(--headerColor);
}

.RPsbs-2278 .cs-h4,
.RPsbsr-2278 .cs-h4 {
  margin: 0 0 0.75rem;
  font-family: var(--headerFont);
  font-size: clamp(1rem, 2.5vw, 1.25rem);
  line-height: 1.2em;
  color: var(--headerColor);
}

.RPsbs-2278 .cs-text,
.RPsbsr-2278 .cs-text {
  margin-bottom: 1rem;
}

.RPsbs-2278 .cs-heading,
.RPsbsr-2278 .cs-heading {
  margin: 0 0 0.75rem;
  font-size: 1rem;
  line-height: 1.2em;
  font-weight: 700;
  color: var(--headerColor);
}

.RPsbs-2278 .cs-ul,
.RPsbsr-2278 .cs-ul {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  margin: 0 0 2rem 0;
  width: 100%;
  padding: 0;
  gap: 0.5rem;
}

.RPsbs-2278 .cs-li,
.RPsbsr-2278 .cs-li {
  z-index: 1;
  position: relative;
  display: inline-block;
  list-style: none;
  font-size: 1rem;
  line-height: 1.5em;
  color: var(--bodyTextColor);
}

.RPsbs-2278 .cs-li::before,
.RPsbsr-2278 .cs-li::before {
  content: "";
  transform: rotate(45deg);
  display: inline-block;
  margin-right: 0.5rem;
  margin-bottom: 0.125rem;
  background: var(--secondary);
  height: 0.5rem;
  width: 0.5rem;
}

.RPsbs-2278 .cs-picture,
.RPsbsr-2278 .cs-picture {
  position: relative;
  display: block;
  margin: 0;
  max-height: 22.5rem;
  height: 91.14vw;
  width: 100%;
}

.RPsbs-2278 .cs-picture img,
.RPsbsr-2278 .cs-picture img {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
  object-fit: cover;
}

/* Rows alternate .RPsbsr-2278 / .RPsbs-2278 / .RPsbsr-2278 down the page; on a
   stacked mobile layout that means every other row would double up top+bottom
   padding at the seam. Zeroing it on the reversed row only (the non-reversed
   row keeps full padding) leaves one section's worth of gap between every
   pair instead of two. Desktop restores it below once the rows sit side by
   side and the doubling stops being a stacking problem. */
.RPsbsr-2278 {
  padding-top: 0;
  padding-bottom: 0;
}

body.dark-mode .RPsbs-2278 .cs-h3,
body.dark-mode .RPsbsr-2278 .cs-h3,
body.dark-mode .RPsbs-2278 .cs-h4,
body.dark-mode .RPsbsr-2278 .cs-h4,
body.dark-mode .RPsbs-2278 .cs-heading,
body.dark-mode .RPsbsr-2278 .cs-heading,
body.dark-mode .RPsbs-2278 .cs-li,
body.dark-mode .RPsbsr-2278 .cs-li {
  color: var(--bodyTextColorWhite);
}

body.dark-mode .RPsbs-2278 .cs-container::before,
body.dark-mode .RPsbsr-2278 .cs-container::before {
  background: var(--medium);
}

@media only screen and (min-width: 64rem) {
  .RPsbs-2278 .cs-container,
  .RPsbsr-2278 .cs-container {
    flex-direction: row;
    justify-content: space-between;
    align-items: stretch;
    max-width: 80rem;
  }

  .RPsbs-2278 .cs-container::before,
  .RPsbsr-2278 .cs-container::before {
    right: 50%;
    transform: none;
    margin-left: calc(clamp(110px, 14vw, 335px) * -1);
  }

  .RPsbs-2278 .cs-picture,
  .RPsbsr-2278 .cs-picture {
    max-height: 100%;
    height: auto;
    max-width: 32.625rem;
  }

  .RPsbs-2278 {
    padding-block: 0;
  }

  /* Reversed rows: photo swaps to the right and the tint bleed mirrors with
     it, so alternating rows put the photo on alternating sides. */
  .RPsbsr-2278 {
    padding: var(--sectionPadding);
  }

  .RPsbsr-2278 .cs-container {
    justify-content: flex-end;
  }

  .RPsbsr-2278 .cs-container::before {
    left: auto;
    right: 50%;
    margin-right: calc(clamp(110px, 14vw, 335px) * -1);
    margin-left: 0;
  }

  .RPsbsr-2278 .cs-picture {
    order: 2;
  }
}

/* ==========================================================================
   In-page jump nav — sticky table of contents for the services sections.

   The stitch ships this as a sticky mobile swipe strip and leaves it that way
   at every width: position:sticky at top:8.5rem, overflow-x:auto on the list,
   flex-shrink:0 on the items. Two things were wrong with that here.

   1. 8.5rem is a guess at the header's height. #cs-navigation is fixed AND
      changes size as you scroll — .scroll collapses the top bar to height:0
      and, below 75rem, slides the whole header up 3rem — so no constant can
      keep the bar welded to it. Page content scrolled through the gap. The
      offset is now --ww-header-bottom, the header's live rect bottom, written
      by jump-nav.js; the 8.5rem fallback only applies before the script runs.

   2. flex-shrink:0 with no wrap ran the six links to roughly 1660px, so they
      overflowed the 80rem container and clipped "How It Works" on a desktop
      that had room to spare. The swipe strip is now scoped to below 64rem,
      where it is the right control; above that the row wraps.

   z-index sits UNDER the header on purpose (100 below 75rem, 10000 above), so
   the "Subsidiary of Home Gear Installations" chip — which is inside the
   header and hangs half past its bottom edge — paints on top of this bar and
   the two read as one stacked unit rather than a collision.
   ========================================================================== */
#in-page-navigation {
  position: sticky;
  top: var(--ww-header-bottom, 8.5rem);
  z-index: 99;
  /* Pinned over the page it needs an edge of its own, or the white bar and a
     white section below it merge into one floating block of links. */
  border-bottom: 1px solid #e7e7e8;
}

/* Links read as a TOC: the underline grows from the leading edge on hover and
   sits at full width on the section you are currently in. Same idiom as the
   review and FAQ cards, so it looks native to the site rather than bolted on.
   The rule is on .cs-link, which wraps icon and label, so the underline spans
   the whole item. */
#in-page-navigation .cs-link {
  position: relative;
  padding-bottom: 0.5rem;
}

#in-page-navigation .cs-link::after {
  position: absolute;
  bottom: 0;
  left: 0;
  content: "";
  display: block;
  background-color: var(--primary);
  height: 0.125rem;
  width: 0;
  transition: width 0.3s;
}

#in-page-navigation .cs-link:hover::after,
#in-page-navigation .cs-link:focus-visible::after,
#in-page-navigation .cs-li.cs-active .cs-link::after {
  width: 100%;
}

#in-page-navigation .cs-h3 {
  transition: color 0.2s;
}

#in-page-navigation .cs-link:hover .cs-h3,
#in-page-navigation .cs-link:focus-visible .cs-h3,
#in-page-navigation .cs-li.cs-active .cs-h3 {
  color: var(--primary);
}

/* .cs-li carries the 1.5rem of bottom padding the underline needs to clear, so
   the wrapped rows do not need a row-gap on top of it. */
@media only screen and (min-width: 64rem) {
  #in-page-navigation .cs-ul {
    flex-wrap: wrap;
    overflow-x: visible;
    row-gap: 0;
  }

  #in-page-navigation .cs-li {
    flex: 0 1 auto;
  }
}

/* Below 64rem the stitch's swipe strip is what you want: one line, scrolled
   horizontally, with jump-nav.js pulling the active item into view as you
   scroll the page. The scrollbar is hidden because the active-item tracking is
   the affordance — a scrollbar under a 3rem-tall strip just adds noise.
   white-space:nowrap keeps "New Construction Windows" on one line so every
   item is the same height. */
@media only screen and (max-width: 63.9375rem) {
  #in-page-navigation .cs-ul {
    flex-wrap: nowrap;
    overflow-x: auto;
    gap: 1.5rem;
    scrollbar-width: none;
    -ms-overflow-style: none;
    -webkit-overflow-scrolling: touch;
  }

  #in-page-navigation .cs-ul::-webkit-scrollbar {
    display: none;
  }

  #in-page-navigation .cs-li {
    flex: 0 0 auto;
    max-width: none;
  }

  #in-page-navigation .cs-h3 {
    white-space: nowrap;
  }
}

/* Anchor landing spot. The stitch's flat 12rem was a second guess at the same
   header height as the sticky offset above, and it has the bar itself to clear
   now as well, so it is composed from the two measured values. Falls back to
   the original 12rem worth before jump-nav.js runs. */
.RPsbs-2278,
.RPsbsr-2278 {
  scroll-margin-top: calc(var(--ww-header-bottom, 8.5rem) + var(--ww-jumpnav-height, 3.5rem));
}

body.dark-mode #in-page-navigation {
  border-bottom-color: rgba(255, 255, 255, 0.12);
}

body.dark-mode #in-page-navigation .cs-link::after {
  background-color: var(--onDarkAccent);
}

body.dark-mode #in-page-navigation .cs-link:hover .cs-h3,
body.dark-mode #in-page-navigation .cs-link:focus-visible .cs-h3,
body.dark-mode #in-page-navigation .cs-li.cs-active .cs-h3 {
  color: var(--onDarkAccent);
}

/* Centre the in-page nav once it has room to sit on one line.

   Deliberately NOT applied below this width: .cs-ul is a horizontal scroller
   (overflow-x:auto) on smaller screens, and centring an overflowing flex
   container pushes the first item off the left edge into space no scrollbar
   can reach. At 75rem the four items — capped at 15.625rem each, plus three
   2rem gaps — fit inside the 80rem container with room to spare, so there is
   nothing left to scroll and the free space can safely go to the sides.

   .cs-li keeps flex-grow:1 from the base rule but is capped by its own
   max-width, so the items stop growing and justify-content gets real free
   space to distribute. */
@media only screen and (min-width: 75rem) {
  #in-page-navigation .cs-ul {
    justify-content: center;
  }
}

/* ===== before-after.css ===== */
/* =============================================================
   Before / After job photos
   -------------------------------------------------------------
   Two presentations of the same real customer photos:

   .ww-ba            drag-to-reveal slider. Used for the pairs
                     that were shot from the same spot, where a
                     wipe actually lines up.
   .ww-ba--split     side-by-side pair. Used where the before and
                     after were shot from different angles, so a
                     wipe would just look like a mistake.

   The slider's interaction is a real <input type="range"> laid
   over the frame, so keyboard and screen readers work without any
   JS of our own. JS mirrors the value onto the --ww-ba-pos custom
   property and, once it has run, moves pointer dragging onto the
   frame (.ww-ba--drag below — see before-after.js for why). If it
   never runs, the frame sits at the 50% authored in the markup and
   both photos still read.
   ============================================================= */

.ww-ba {
  --ww-ba-pos: 50%;
  position: relative;
  margin: 0;
  display: flex;
  flex-direction: column;
}

/* ---------- frame ---------- */

.ww-ba-frame {
  position: relative;
  width: 100%;
  aspect-ratio: 3 / 4;
  overflow: hidden;
  border-radius: 0.5rem;
  background: var(--lightGrey, #f5f5f5);
  isolation: isolate;
}

.ww-ba--wide .ww-ba-frame {
  aspect-ratio: 4 / 3;
}

.ww-ba-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  /* The photos are phone snaps off a job site — a hair of extra contrast
     keeps the new frames from washing out next to bright Texas sky. */
  filter: saturate(1.03);
}

/* The "before" sits on top of the "after" and is clipped back to the
   divider. Clipping (rather than sizing a wrapper) means both images stay
   exactly the same size, so the two halves always register with each other. */
.ww-ba-img--before {
  z-index: 1;
  clip-path: inset(0 calc(100% - var(--ww-ba-pos)) 0 0);
}

/* ---------- labels ---------- */

.ww-ba-badge {
  position: absolute;
  z-index: 3;
  top: 0.75rem;
  padding: 0.3rem 0.7rem;
  border-radius: 0.25rem;
  font-family: var(--headerFont, "Barlow", Arial, sans-serif);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1.2;
  pointer-events: none;
  backdrop-filter: blur(4px);
  transition: opacity 0.25s ease;
}

.ww-ba-badge--before {
  left: 0.75rem;
  background: rgba(11, 31, 51, 0.82);
  color: #fff;
}

.ww-ba-badge--after {
  right: 0.75rem;
  background: var(--primary, #044c94);
  color: #fff;
}

/* Once the divider is pushed most of the way to one side, the photo that has
   been wiped away is gone but its label would still be sitting there naming
   nothing. Fade whichever label no longer has a photo under it. */
.ww-ba[data-ww-ba-edge="start"] .ww-ba-badge--before,
.ww-ba[data-ww-ba-edge="end"] .ww-ba-badge--after {
  opacity: 0;
}

/* ---------- divider + grip ---------- */

.ww-ba-divider {
  position: absolute;
  z-index: 2;
  top: 0;
  bottom: 0;
  left: var(--ww-ba-pos);
  width: 2px;
  margin-left: -1px;
  background: #fff;
  box-shadow: 0 0 0 1px rgba(11, 31, 51, 0.25);
  pointer-events: none;
}

.ww-ba-grip {
  position: absolute;
  top: 50%;
  left: 50%;
  translate: -50% -50%;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 2px 10px rgba(11, 31, 51, 0.35);
  display: grid;
  place-items: center;
  transition: scale 0.15s ease;
}

/* Two chevrons pointing outward, drawn from borders so there is no extra
   asset to load and they tint with the brand colour. */
.ww-ba-grip::before,
.ww-ba-grip::after {
  content: "";
  position: absolute;
  width: 0.5rem;
  height: 0.5rem;
  border: solid var(--primary, #044c94);
  border-width: 2px 2px 0 0;
}

.ww-ba-grip::before {
  rotate: -135deg;
  margin-right: 0.85rem;
}

.ww-ba-grip::after {
  rotate: 45deg;
  margin-left: 0.85rem;
}

/* ---------- the control itself ---------- */

.ww-ba-range {
  position: absolute;
  z-index: 4;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  background: transparent;
  border: none;
  cursor: ew-resize;
  appearance: none;
  -webkit-appearance: none;
  /* Let a vertical swipe scroll the page; keep horizontal drags for the wipe. */
  touch-action: pan-y;
}

/* The thumb is deliberately hairline-thin and invisible. The visible grip is
   .ww-ba-grip, which is positioned from the same percentage. A wide thumb
   would inset its own travel by half its width at each end, so the grip would
   drift away from the pointer near the edges. */
.ww-ba-range::-webkit-slider-thumb {
  appearance: none;
  -webkit-appearance: none;
  width: 2px;
  height: 100%;
  background: transparent;
  border: none;
  cursor: ew-resize;
}

.ww-ba-range::-moz-range-thumb {
  width: 2px;
  height: 100%;
  background: transparent;
  border: none;
  border-radius: 0;
  cursor: ew-resize;
}

.ww-ba-range::-moz-range-track {
  background: transparent;
  border: none;
}

.ww-ba-range:focus-visible {
  outline: 3px solid var(--primary, #044c94);
  outline-offset: 3px;
}

/* ---------- pointer dragging (JS present) ----------
   before-after.js adds .ww-ba--drag and then drives the range from pointer
   events on the frame, because a 2px invisible thumb cannot be grabbed with a
   fingertip: on a touch screen the gesture lands on the track, the browser
   reads it as a tap, and no drag ever starts.

   The range stays in the DOM and stays focusable — pointer-events only affects
   hit testing, so Tab and the arrow keys are untouched — but it no longer
   competes for the gesture, and its own tap-to-jump can't fire alongside ours. */

.ww-ba--drag .ww-ba-frame {
  cursor: ew-resize;
  /* Vertical swipes still scroll the page; horizontal ones are the wipe. */
  touch-action: pan-y;
  /* A drag that starts on a photo shouldn't sweep a text selection with it. */
  user-select: none;
  -webkit-user-select: none;
}

.ww-ba--drag .ww-ba-range {
  pointer-events: none;
}

.ww-ba-frame:hover .ww-ba-grip,
.ww-ba-range:focus-visible ~ .ww-ba-divider .ww-ba-grip {
  scale: 1.08;
}

/* ---------- caption ---------- */

.ww-ba-caption {
  margin-top: 1rem;
}

.ww-ba-place {
  display: block;
  font-family: var(--headerFont, "Barlow", Arial, sans-serif);
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--primary, #044c94);
  margin-bottom: 0.25rem;
}

.ww-ba-name {
  display: block;
  font-family: var(--headerFont, "Barlow", Arial, sans-serif);
  font-size: 1.25rem;
  font-weight: 700;
  line-height: 1.2;
  color: var(--headerColor, #141615);
  margin-bottom: 0.5rem;
}

.ww-ba-desc {
  font-size: 0.9375rem;
  line-height: 1.5;
  color: var(--bodyTextColor, #585b5d);
}

/* ---------- split (different-angle) pairs ---------- */

.ww-ba--split .ww-ba-frame {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.375rem;
  aspect-ratio: 8 / 3;
  overflow: visible;
  background: none;
}

.ww-ba--split .ww-ba-half {
  position: relative;
  overflow: hidden;
  border-radius: 0.5rem;
  background: var(--lightGrey, #f5f5f5);
}

.ww-ba--split .ww-ba-img {
  position: absolute;
  clip-path: none;
}

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

.ww-ba-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(2rem, 4vw, 3rem);
  width: 100%;
  max-width: 80rem;
  margin: 0 auto;
}

@media only screen and (min-width: 48rem) {
  .ww-ba-grid--2 {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media only screen and (min-width: 64rem) {
  .ww-ba-grid--3 {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* A split pair is a wide, single-column item wherever it lands in a grid. */
.ww-ba-grid .ww-ba--split {
  grid-column: 1 / -1;
}

/* Below 34rem a side-by-side pair is two ~140px photos — too small to show
   anything. Stack them and let each one have real height. */
@media only screen and (max-width: 33.9375rem) {
  .ww-ba--split .ww-ba-frame {
    grid-template-columns: 1fr;
    gap: 0.75rem;
    aspect-ratio: auto;
  }

  .ww-ba--split .ww-ba-half {
    aspect-ratio: 4 / 3;
  }
}

/* ---------- section chrome ---------- */

.ww-ba-section {
  padding: var(--sectionPadding);
}

.ww-ba-section .ww-ba-head {
  max-width: 46rem;
  margin: 0 auto clamp(2.5rem, 5vw, 3.5rem);
  text-align: center;
}

.ww-ba-section .ww-ba-head .cs-text {
  margin: 1rem auto 0;
}

.ww-ba-section .ww-ba-foot {
  display: flex;
  justify-content: center;
  margin-top: clamp(2.5rem, 5vw, 3.5rem);
}

.ww-ba-hint {
  display: block;
  margin-top: 1.25rem;
  font-size: 0.875rem;
  font-style: italic;
  color: var(--bodyTextColor, #585b5d);
}

/* ---------- dark mode ----------
   Reads the tokens set on body.dark-mode in root.css; no colours of its own. */

body.dark-mode .ww-ba-frame,
body.dark-mode .ww-ba--split .ww-ba-half {
  background: var(--medium);
}

body.dark-mode .ww-ba-name {
  color: var(--bodyTextColorWhite);
}

body.dark-mode .ww-ba-place {
  color: var(--onDarkAccent);
}

body.dark-mode .ww-ba-desc,
body.dark-mode .ww-ba-hint {
  color: var(--onDarkMuted);
}

body.dark-mode .ww-ba-grip::before,
body.dark-mode .ww-ba-grip::after {
  border-color: var(--dark);
}

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

@media (prefers-reduced-motion: reduce) {
  .ww-ba-grip,
  .ww-ba-badge {
    transition: none;
  }
}

/* ===== mobile-nav.css ===== */
/* ==========================================================================
   Mobile / tablet navigation — the "glass panes" takeover
   --------------------------------------------------------------------------
   Loaded AFTER critical.css on every page. The template's mobile menu was a
   white panel that scaleY'd down from under the header; everything below is a
   full-viewport replacement built on the brand's own subject matter: three
   frosted panes drop into their frame like sashes seating in a window, a glint
   travels across each one as it lands, then the links rise through the glass.

   Nothing here is a framework: the stagger is a CSS custom property (--i) set
   once by nav.js, the pane sequence is nth-child transition-delay, the light is
   a radial-gradient positioned by --ww-mx/--ww-my, and the swipe-to-dismiss is
   a translate driven by --ww-dx. All of it is transform/opacity only, so it
   composites on the GPU and stays smooth on a phone.

   Specificity notes — critical.css is minified and uses #cs-navigation .cs-x
   selectors, some with :nth-of-type (which outranks a bare class). Where a
   declaration has to beat one of those, the selector here carries an extra
   class (usually .cs-nav) so it wins on specificity rather than on load order
   alone. Load order is still the safety net: this file comes after critical.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Desktop guards. The extra elements exist in the markup at every width, so
   they are switched off first and re-enabled inside the mobile media query.
   .ww-menu-body uses display:contents so at desktop widths the wrapper leaves
   no box behind at all and .cs-ul sits directly in .cs-ul-wrapper, exactly as
   the original template expects.
   -------------------------------------------------------------------------- */
.ww-menu-fx,
.ww-menu-foot {
  display: none;
}

.ww-menu-body {
  display: contents;
}

/* Keyboard parity for the desktop dropdown: the trigger is a <span> that
   nav.js makes focusable, so the panel has to open on focus as well as hover
   (the template only handled :hover). */
@media only screen and (min-width: 75rem) {
  #cs-navigation .cs-dropdown:focus-within .cs-drop-ul {
    visibility: visible;
    opacity: 1;
    transform: scaleY(1);
  }

  #cs-navigation .cs-dropdown:focus-within .cs-drop-li {
    opacity: 1;
    transform: translateY(0);
  }

  #cs-navigation .cs-li-link:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: 4px;
  }
}

@media only screen and (max-width: 74.96875rem) {
  /* ------------------------------------------------------------------------
     Tokens. One easing curve does almost all the work: a long, decelerating
     "settle" that makes a pane feel like it has mass. The in-curve is its
     mirror, used when things leave.
     ------------------------------------------------------------------------ */
  #cs-navigation {
    --ww-settle: cubic-bezier(0.16, 1, 0.3, 1);
    /* Fallback surface for engines without backdrop-filter: near-opaque, since
       there is no blur to soften whatever sits behind it. */
    --ww-glass-1: rgba(11, 31, 51, 0.985);
    --ww-glass-2: rgba(4, 15, 27, 0.995);
    --ww-hairline: rgba(255, 255, 255, 0.08);
  }

  /* ------------------------------------------------------------------------
     Bar geometry. The logo was 2.5rem in a row padded 1.25rem top and bottom —
     5.5rem of bar for 2.5rem of brand, with the 3rem toggle setting the real
     floor. Trading the padding for logo height spends that slack on the mark
     instead: 4rem of logo inside 0.75rem padding is the same 5.5rem row, so
     the bar does not move and neither does anything measured off it (the
     badge hangs from the header's bottom edge, the panel starts below it).

     These live here rather than in root.css because critical.css AND local.css
     both ship their own `#cs-navigation .cs-bottom-bar` at equal specificity
     and both load after root.css — an override there loses on the homepage
     only, which is exactly the sort of bug that takes an hour to find.
     ------------------------------------------------------------------------ */
  #cs-navigation .cs-bottom-bar {
    padding: 0.75rem 0;
  }

  #cs-navigation .cs-logo.cs-mobile {
    height: 4rem;
  }

  /* ------------------------------------------------------------------------
     Scroll lock. Freezing <body> with position:fixed is the only approach that
     holds on iOS Safari; nav.js stores the offset in --ww-lock-y and restores
     the scroll position on close, so the page never jumps.
     ------------------------------------------------------------------------ */
  body.ww-locked {
    position: fixed;
    left: 0;
    right: 0;
    width: 100%;
    overflow: hidden;
  }

  /* critical.css gives the mobile header `position:fixed` but never sets `top`,
     so it renders at its *static* position — fine while <body> starts at 0.
     The lock above puts <body> at position:fixed with top:-<scrollY>, which
     moves the body box up and takes the header's static position with it: open
     the menu 700px down the page and the bar (logo, close button and all) is
     laid out 700px above the viewport. Pinning top:0 for the duration of the
     lock detaches it from the body box. */
  body.ww-locked #cs-navigation {
    top: 0;
  }

  /* The scroll-to-top dial is fixed too — get it out of the takeover. */
  body.cs-open .pb-go-top-progress,
  body.ww-menu-closing .pb-go-top-progress {
    opacity: 0 !important;
    pointer-events: none;
  }

  /* ------------------------------------------------------------------------
     The header while the menu is open.

     #cs-navigation.scroll translateY(-3rem)s the whole header to tuck the info
     bar away. A transformed ancestor becomes the containing block for its
     fixed descendants, which would drag the panel 3rem off-screen with it — so
     the transform is neutralised for as long as the panel is on screen. The
     side effect is the nicer of the two: opening the menu slides the full
     header back into view, closing it tucks it away again. .ww-menu-closing
     holds the override through the exit animation so nothing shifts mid-flight.
     ------------------------------------------------------------------------ */
  body.cs-open #cs-navigation,
  body.ww-menu-closing #cs-navigation {
    transform: none !important;
  }

  /* Every rule below is keyed on cs-open AND ww-menu-closing. The panes
     retract upwards, so the strip behind the header is the last thing they
     uncover — reverting the bar to white the instant the menu is dismissed
     would flash a white slab across glass that is still on screen. The bar
     stays inverted for the whole exit and flips back once the panel is gone. */
  body.cs-open #cs-navigation,
  body.ww-menu-closing #cs-navigation {
    z-index: 9999;
    /* The panel supplies the surface now; the white bar would slice a strip
       across the top of it. */
    background-color: transparent;
    box-shadow: none;
  }

  /* Header chrome inverts onto the dark glass. */
  body.cs-open #cs-navigation .cs-item,
  body.cs-open #cs-navigation .cs-link,
  body.ww-menu-closing #cs-navigation .cs-item,
  body.ww-menu-closing #cs-navigation .cs-link {
    color: rgba(255, 255, 255, 0.72);
  }

  body.cs-open #cs-navigation .cs-icon,
  body.ww-menu-closing #cs-navigation .cs-icon {
    filter: grayscale(1) brightness(1000%);
    opacity: 0.7;
  }

  body.cs-open #cs-navigation .cs-top-bar:before,
  body.ww-menu-closing #cs-navigation .cs-top-bar:before {
    background: rgba(255, 255, 255, 0.14);
  }

  body.cs-open #cs-navigation #dark-mode-toggle .cs-moon,
  body.ww-menu-closing #cs-navigation #dark-mode-toggle .cs-moon {
    fill: #fff;
  }

  /* .scroll re-parks the theme toggle for the tucked-up header; with the
     transform neutralised it has to go back to its resting spot. */
  body.cs-open #cs-navigation.scroll #dark-mode-toggle,
  body.ww-menu-closing #cs-navigation.scroll #dark-mode-toggle {
    top: 0;
    right: 1rem;
  }

  /* The mobile bar carries a colour logo on white and a white one on navy
     (root.css). Open, the bar is always dark glass — force the white lockup. */
  body.cs-open #cs-navigation .cs-mobile .ww-logo-light,
  body.ww-menu-closing #cs-navigation .cs-mobile .ww-logo-light {
    display: none;
  }

  body.cs-open #cs-navigation .cs-mobile .ww-logo-dark,
  body.ww-menu-closing #cs-navigation .cs-mobile .ww-logo-dark {
    display: block;
  }

  /* The badge is its own solid chip now (root.css), so it no longer has to be
     re-tinted for the dark bar — only its shadow, which would disappear into
     the glass, gets a lift. */
  body.cs-open #cs-navigation .cs-mobile .ww-former-tag,
  body.ww-menu-closing #cs-navigation .cs-mobile .ww-former-tag {
    box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.5);
  }

  /* ------------------------------------------------------------------------
     The toggle: three lines into an X, on a spring.

     critical.css ships this as "#cs-navigation .cs-active .cs-line1" — a
     descendant selector, and .cs-active lands on the header itself, so the
     template's X never actually fires. These rules replace it with the
     compound selector it wanted, and add the overshoot.
     ------------------------------------------------------------------------ */
  #cs-navigation .cs-toggle {
    position: relative;
    z-index: 20;
    border-radius: 0.25rem;
    background-color: #f3f3f3;
    transition: background-color 0.4s ease, box-shadow 0.4s ease, transform 0.6s var(--ww-settle);
  }

  #cs-navigation .cs-toggle:active {
    transform: scale(0.94);
  }

  /* Surface follows the panel's lifetime (so it does not turn pale grey while
     still sitting on glass); the X morph below follows .cs-active, so the
     icon starts animating back the moment the menu is dismissed. */
  body.cs-open #cs-navigation .cs-toggle,
  body.ww-menu-closing #cs-navigation .cs-toggle {
    background-color: rgba(255, 255, 255, 0.08);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.18);
  }

  #cs-navigation .cs-line {
    background-color: #585b5d;
    transition: background-color 0.4s ease, transform 0.55s var(--ww-settle), top 0.35s var(--ww-settle),
      opacity 0.25s ease, width 0.35s var(--ww-settle);
  }

  /* The export turns the closed toggle into a solid --primary chip in dark mode
     and pairs it with `body.dark-mode #cs-navigation .cs-line { color: #1a1a1a }`
     — but the lines are <span>s painted with background-color, so that rule sets
     a property nothing reads and they keep the #585b5d grey meant for the white
     light-mode bar. Grey on saturated blue is the muddy icon you see; white is
     what the chip wants, and it matches the white label on every other solid
     button. Same specificity as the export's rule — this sheet loading last is
     what settles it. */
  body.dark-mode #cs-navigation .cs-line {
    background-color: #fff;
  }

  body.cs-open #cs-navigation .cs-line,
  body.ww-menu-closing #cs-navigation .cs-line {
    background-color: #fff;
  }

  #cs-navigation.cs-active .cs-line1 {
    top: 50%;
    transform: translate(-50%, -50%) rotate(225deg);
  }

  #cs-navigation.cs-active .cs-line2 {
    top: 50%;
    transform: translate(-50%, -50%) rotate(-225deg);
  }

  #cs-navigation.cs-active .cs-line3 {
    bottom: 50%;
    width: 0;
    opacity: 0;
  }

  /* ------------------------------------------------------------------------
     The panel.

     z-index:-1 is deliberate and load-bearing: a negative-z child paints above
     its parent's own background but below every other child, so the panel
     covers the header's white bar while the logo, toggle and info bar stay on
     top of the glass. visibility is transitioned with a delay instead of being
     switched, which keeps the element in the a11y tree only while it is
     genuinely on screen and still lets the exit animation play out.
     ------------------------------------------------------------------------ */
  #cs-navigation .cs-ul-wrapper {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: -1;
    height: 100vh;
    height: 100dvh;
    width: 100%;
    display: flex;
    flex-direction: column;
    background: none;
    box-shadow: none;
    opacity: 1;
    transform: none;
    overflow: hidden;
    visibility: hidden;
    pointer-events: none;
    transition: visibility 0s linear 0.8s;
    /* Default position of the light; nav.js steers it with the pointer. */
    --ww-mx: 78%;
    --ww-my: 8%;
  }

  #cs-navigation .cs-ul-wrapper:before {
    display: none;
  }

  #cs-navigation.cs-active .cs-ul-wrapper {
    opacity: 1;
    transform: none;
    visibility: visible;
    pointer-events: auto;
    transition-delay: 0s;
  }

  /* Dark mode already paints this navy; the panes own the surface now. */
  body.dark-mode #cs-navigation .cs-ul-wrapper {
    background-color: transparent;
  }

  body.dark-mode #cs-navigation .cs-ul-wrapper:before {
    display: none;
  }

  /* ------------------------------------------------------------------------
     Layer 1 — the panes.

     Three columns, each translated a hair past its own height so no sliver
     shows, dropping in sequence. --p is the column index: opening runs
     left-to-right off it, closing runs right-to-left off (2 - --p), which is
     what makes the exit read as a reversal rather than a rewind.

     backdrop-filter is what sells the glass: the page behind stays faintly
     legible and out of focus. The gradients sit at ~93-96% alpha so text
     contrast never depends on what happens to be scrolled behind them.
     ------------------------------------------------------------------------ */
  #cs-navigation .ww-menu-fx {
    position: absolute;
    inset: 0;
    z-index: 0;
    display: flex;
    pointer-events: none;
    transform: translate3d(calc(var(--ww-dx, 0px) * 0.35), 0, 0);
  }

  #cs-navigation .ww-pane {
    --p: 0;
    position: relative;
    flex: 1 1 0;
    overflow: hidden;
    background: linear-gradient(178deg, var(--ww-glass-1) 0%, var(--ww-glass-2) 100%);
    transform: translate3d(0, -101%, 0);
    transition: transform 0.72s var(--ww-settle);
    transition-delay: calc((2 - var(--p)) * 0.055s);
    will-change: transform;
  }

  /* With a real blur behind it the sash can afford to stay translucent — the
     page reads as depth, not as noise. The alpha still sits high enough that
     nothing scrolled behind can compete with the link text. */
  @supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
    #cs-navigation .ww-pane {
      -webkit-backdrop-filter: blur(30px) saturate(1.4);
      backdrop-filter: blur(30px) saturate(1.4);
      background: linear-gradient(178deg, rgba(12, 32, 53, 0.975) 0%, rgba(4, 16, 28, 0.99) 100%);
    }
  }

  #cs-navigation .ww-pane:nth-child(2) {
    --p: 1;
  }

  #cs-navigation .ww-pane:nth-child(3) {
    --p: 2;
  }

  /* The mullion between sashes — a hairline of caught light, not a border. */
  #cs-navigation .ww-pane + .ww-pane {
    box-shadow: -1px 0 0 rgba(255, 255, 255, 0.07), -2px 0 12px rgba(0, 0, 0, 0.28);
  }

  #cs-navigation.cs-active .ww-pane {
    transform: translate3d(0, 0, 0);
    transition-delay: calc(var(--p) * 0.065s);
  }

  /* The glint. A narrow diagonal highlight that crosses the sash just after it
     seats — the detail that reads as glass rather than as a coloured div. */
  #cs-navigation .ww-pane:after {
    content: "";
    position: absolute;
    top: -60%;
    left: -120%;
    height: 220%;
    width: 60%;
    background: linear-gradient(
      100deg,
      transparent 0%,
      rgba(255, 255, 255, 0.05) 42%,
      rgba(204, 228, 244, 0.16) 50%,
      rgba(255, 255, 255, 0.05) 58%,
      transparent 100%
    );
    transform: translate3d(0, 0, 0) rotate(8deg);
    opacity: 0;
  }

  #cs-navigation.cs-active .ww-pane:after {
    animation: ww-glint 1.15s var(--ww-settle) calc(var(--p) * 0.065s + 0.22s) both;
  }

  @keyframes ww-glint {
    0% {
      opacity: 0;
      transform: translate3d(0, 0, 0) rotate(8deg);
    }
    18% {
      opacity: 1;
    }
    100% {
      opacity: 0;
      transform: translate3d(420%, 0, 0) rotate(8deg);
    }
  }

  /* ------------------------------------------------------------------------
     Layer 2 — the light. A soft brand-blue bloom that drifts on its own and
     tracks the pointer through --ww-mx/--ww-my. Painting it as a background
     gradient (rather than a blurred element) keeps it off the compositor's
     critical path while still feeling alive.
     ------------------------------------------------------------------------ */
  #cs-navigation .ww-menu-glow {
    position: absolute;
    inset: -20%;
    opacity: 0;
    background: radial-gradient(
        38% 30% at var(--ww-mx) var(--ww-my),
        rgba(100, 148, 204, 0.34) 0%,
        rgba(28, 92, 156, 0.16) 42%,
        transparent 72%
      ),
      radial-gradient(46% 34% at 12% 96%, rgba(4, 76, 148, 0.32) 0%, transparent 68%);
    transition: opacity 0.7s ease 0.18s;
    animation: ww-drift 22s ease-in-out infinite;
  }

  #cs-navigation.cs-active .ww-menu-glow {
    opacity: 1;
  }

  @keyframes ww-drift {
    0%,
    100% {
      transform: translate3d(0, 0, 0) scale(1);
    }
    50% {
      transform: translate3d(-4%, 3%, 0) scale(1.08);
    }
  }

  /* ------------------------------------------------------------------------
     Layer 3 — the frame. Faint horizontal rails that, crossed with the pane
     seams, read as muntins in a large window. Fades in only once the sashes
     have landed.
     ------------------------------------------------------------------------ */
  #cs-navigation .ww-menu-grid {
    position: absolute;
    inset: 0;
    opacity: 0;
    background-image: repeating-linear-gradient(
      to bottom,
      rgba(255, 255, 255, 0.038) 0 1px,
      transparent 1px 5.5rem
    );
    -webkit-mask-image: radial-gradient(120% 80% at 50% 0%, #000 30%, transparent 78%);
    mask-image: radial-gradient(120% 80% at 50% 0%, #000 30%, transparent 78%);
    transition: opacity 0.6s ease;
  }

  #cs-navigation.cs-active .ww-menu-grid {
    opacity: 1;
    transition-delay: 0.42s;
  }

  /* ------------------------------------------------------------------------
     Layer 4 — the content. This is also the scroll container and the element
     the swipe gesture moves, which is why the fx layer is a sibling rather
     than a parent: dragging the content never disturbs the glass behind it.
     --ww-nav-h is the measured header height, so the list always clears the
     logo no matter how the bar wraps.
     ------------------------------------------------------------------------ */
  #cs-navigation .ww-menu-body {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    height: 100%;
    width: 100%;
    max-width: 34rem;
    margin: 0 auto;
    /* Fallback matches the bar's usual rendered height, so the list clears the
       logo even in the frame before nav.js measures it. */
    padding: calc(var(--ww-nav-h, 9rem) + 0.75rem) 1.5rem 2rem;
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    /* Vertical panning stays native; horizontal is ours to interpret. */
    touch-action: pan-y;
    transform: translate3d(var(--ww-dx, 0px), 0, 0) scale(var(--ww-scale, 1));
    transform-origin: 50% 40%;
    transition: transform 0.5s var(--ww-settle);
  }

  /* While a finger is down the panel must track it exactly — no easing. */
  #cs-navigation .ww-dragging .ww-menu-body,
  #cs-navigation .ww-dragging .ww-menu-fx {
    transition: none;
  }

  /* ------------------------------------------------------------------------
     The list.
     ------------------------------------------------------------------------ */
  #cs-navigation .cs-nav .cs-ul {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
    counter-reset: ww-nav;
    max-height: none;
    height: auto;
    width: 100%;
    margin: 0 0 auto;
    padding: 0;
    overflow: visible;
    gap: 0;
    /* Gives the links somewhere to rotate through as they rise. */
    perspective: 900px;
  }

  #cs-navigation .cs-nav .cs-li {
    --i: 0;
    position: relative;
    display: block;
    width: 100%;
    margin: 0;
    text-align: left;
    list-style: none;
    counter-increment: ww-nav;
    border-bottom: 1px solid var(--ww-hairline);
    opacity: 0;
    transform: translate3d(0, 1.4rem, 0) rotateX(-38deg);
    transform-origin: 50% 0;
    filter: blur(7px);
    transition: opacity 0.4s ease, transform 0.55s var(--ww-settle), filter 0.45s ease;
    /* Closing: everything leaves at once, quickly. Opening re-delays below. */
    transition-delay: 0s;
  }

  #cs-navigation.cs-active .cs-nav .cs-li {
    opacity: 1;
    transform: none;
    filter: none;
    transition-delay: calc(var(--i) * 55ms + 300ms);
  }

  /* Hover / press wash — a brand-blue wipe from the leading edge, sitting
     behind the link's own text. */
  #cs-navigation .cs-nav .cs-li:before {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    left: -1.5rem;
    right: -1.5rem;
    background: linear-gradient(90deg, rgba(28, 92, 156, 0.42) 0%, rgba(28, 92, 156, 0) 78%);
    opacity: 0;
    transform: translate3d(-1.25rem, 0, 0);
    transition: opacity 0.35s ease, transform 0.45s var(--ww-settle);
    pointer-events: none;
  }

  #cs-navigation .cs-nav .cs-li:hover:before,
  #cs-navigation .cs-nav .cs-li:focus-within:before,
  #cs-navigation .cs-nav .cs-li:active:before {
    opacity: 1;
    transform: translate3d(0, 0, 0);
  }

  /* ------------------------------------------------------------------------
     The links. Big Barlow caps with a counter-generated index — the numbering
     is pure CSS, so adding or removing a nav item needs no markup bookkeeping.
     ------------------------------------------------------------------------ */
  #cs-navigation .cs-nav .cs-ul > .cs-li > .cs-li-link {
    position: relative;
    z-index: 1;
    display: flex;
    align-items: center;
    gap: 0.9rem;
    width: 100%;
    margin: 0;
    padding: 0.85rem 0.25rem;
    font-family: var(--headerFont);
    font-size: clamp(1.375rem, 6.4vw, 2rem);
    font-weight: 700;
    line-height: 1.05;
    letter-spacing: -0.015em;
    text-transform: uppercase;
    text-decoration: none;
    color: #fff;
    transition: color 0.3s ease, transform 0.45s var(--ww-settle);
  }

  #cs-navigation .cs-nav .cs-ul > .cs-li > .cs-li-link:active {
    transform: translateX(0.35rem);
  }

  #cs-navigation .cs-nav .cs-ul > .cs-li > .cs-li-link:before {
    content: counter(ww-nav, decimal-leading-zero);
    flex: none;
    align-self: flex-start;
    margin-top: 0.5em;
    font-family: var(--bodyFont);
    font-size: 0.6875rem;
    font-weight: 700;
    line-height: 1;
    letter-spacing: 0.16em;
    color: var(--secondary);
    opacity: 0.85;
    transition: color 0.3s ease, opacity 0.3s ease;
  }

  /* Chevron for the plain links; the dropdown supplies its own icon. */
  #cs-navigation .cs-nav .cs-li:not(.cs-dropdown) > .cs-li-link:after {
    content: "";
    flex: none;
    height: 0.5rem;
    width: 0.5rem;
    margin-left: auto;
    border-top: 2px solid currentColor;
    border-right: 2px solid currentColor;
    transform: rotate(45deg);
    opacity: 0.28;
    transition: transform 0.4s var(--ww-settle), opacity 0.3s ease;
  }

  #cs-navigation .cs-nav .cs-li:not(.cs-dropdown):hover > .cs-li-link:after,
  #cs-navigation .cs-nav .cs-li:not(.cs-dropdown):focus-within > .cs-li-link:after {
    opacity: 0.9;
    transform: rotate(45deg) translate3d(0.2rem, -0.2rem, 0);
  }

  /* Current page. The template turns this --primary, which is near-black on
     navy — invisible. It gets the light tint, a lit index, a standing accent
     bar and a faint wash instead, so "you are here" survives without relying
     on colour alone. The selector has to out-specify the base link rule above
     (1 id + 4 classes), hence the full child chain. */
  #cs-navigation .cs-nav .cs-ul > .cs-li > .cs-li-link.cs-active {
    /* Negative margin + equal padding + the width it gives back: the bar hangs
       into the container's gutter and the index numbers stay on the same
       optical line as every other row. */
    margin-left: -0.9rem;
    padding-left: 0.9rem;
    width: calc(100% + 0.9rem);
    background: linear-gradient(90deg, rgba(28, 92, 156, 0.3) 0%, transparent 62%);
    box-shadow: inset 3px 0 0 var(--secondary);
    color: var(--secondaryLight);
  }

  #cs-navigation .cs-nav .cs-ul > .cs-li > .cs-li-link.cs-active:before {
    color: var(--secondaryLight);
    opacity: 1;
    text-shadow: 0 0 0.75rem rgba(204, 228, 244, 0.8);
  }

  #cs-navigation .cs-nav .cs-li-link:focus-visible {
    outline: 2px solid var(--secondaryLight);
    outline-offset: 2px;
    border-radius: 0.125rem;
  }

  /* ------------------------------------------------------------------------
     The submenu. Height is animated in pixels by nav.js (measured from
     scrollHeight) so the accordion is exact at any width and any content
     length — the usual max-height guess would either clip or coast.
     No padding on the <ul>: with border-box a padded element cannot collapse
     to a true zero height, and the seam would show.
     ------------------------------------------------------------------------ */
  #cs-navigation .cs-nav .cs-dropdown > .cs-li-link {
    cursor: pointer;
    -webkit-user-select: none;
    user-select: none;
  }

  #cs-navigation .cs-nav .cs-drop-icon {
    position: static;
    flex: none;
    height: auto;
    width: 1.4rem;
    margin-left: auto;
    transform: none;
    opacity: 0.55;
    filter: brightness(0) invert(1);
    transition: transform 0.45s var(--ww-settle), opacity 0.3s ease;
  }

  #cs-navigation .cs-nav .cs-dropdown.cs-active .cs-drop-icon {
    transform: rotate(180deg);
    opacity: 1;
  }

  #cs-navigation .cs-nav .cs-drop-ul {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    /* Collapsed is hidden, not merely zero-height: a clipped-but-visible list
       still takes tab stops, and tabbing into a submenu nobody opened is the
       kind of thing that only ever gets found by the person using a keyboard.
       The visibility flip is delayed to the end so it cannot cut the collapse
       animation short. */
    visibility: hidden;
    height: 0;
    width: 100%;
    margin: 0;
    padding: 0;
    background: transparent;
    overflow: hidden;
    opacity: 0;
    gap: 0;
    transition: height 0.45s var(--ww-settle), opacity 0.3s ease, margin 0.45s var(--ww-settle),
      visibility 0s linear 0.45s;
  }

  #cs-navigation .cs-nav .cs-dropdown.cs-active .cs-drop-ul {
    visibility: visible;
    opacity: 1;
    height: 0; /* nav.js overwrites inline with the measured value */
    margin: 0 0 0.85rem;
    padding: 0;
    transition-delay: 0s;
  }

  #cs-navigation .cs-nav .cs-drop-li {
    position: relative;
    list-style: none;
    /* The rail: one continuous line down the left of the group, echoing the
       pane seams. */
    border-left: 1px solid rgba(255, 255, 255, 0.16);
    margin-left: 2rem;
  }

  #cs-navigation .cs-nav .cs-li-link.cs-drop-link {
    display: block;
    padding: 0.6rem 0 0.6rem 1.1rem;
    font-family: var(--bodyFont);
    font-size: 0.9375rem;
    font-weight: 500;
    line-height: 1.35;
    letter-spacing: 0.01em;
    text-transform: none;
    text-decoration: none;
    color: rgba(255, 255, 255, 0.7);
    transition: color 0.25s ease, transform 0.35s var(--ww-settle);
  }

  #cs-navigation .cs-nav .cs-li-link.cs-drop-link:before {
    content: "";
    position: absolute;
    top: 50%;
    left: -1px;
    height: 0;
    width: 2px;
    background: var(--secondary);
    transform: translateY(-50%);
    transition: height 0.35s var(--ww-settle);
  }

  #cs-navigation .cs-nav .cs-drop-li:hover .cs-drop-link,
  #cs-navigation .cs-nav .cs-drop-link:focus-visible {
    color: #fff;
    transform: translateX(0.2rem);
  }

  #cs-navigation .cs-nav .cs-drop-li:hover .cs-drop-link:before,
  #cs-navigation .cs-nav .cs-drop-link:focus-visible:before {
    height: 60%;
  }

  /* ------------------------------------------------------------------------
     The footer block — quote CTA, the contact details people actually open the
     menu for, and the brand tail. Rises after the links, on the same curve.
     ------------------------------------------------------------------------ */
  #cs-navigation .ww-menu-foot {
    display: flex;
    flex-direction: column;
    gap: 0.9rem;
    /* No border of its own — the last link's border-bottom is already the
       seam between the list and this block. */
    margin-top: 1.75rem;
  }

  #cs-navigation .ww-menu-foot > * {
    opacity: 0;
    transform: translate3d(0, 1rem, 0);
    transition: opacity 0.4s ease, transform 0.55s var(--ww-settle);
  }

  #cs-navigation.cs-active .ww-menu-foot > * {
    opacity: 1;
    transform: none;
  }

  #cs-navigation.cs-active .ww-menu-foot > *:nth-child(1) {
    transition-delay: 0.56s;
  }

  #cs-navigation.cs-active .ww-menu-foot > *:nth-child(2) {
    transition-delay: 0.63s;
  }

  #cs-navigation.cs-active .ww-menu-foot > *:nth-child(3) {
    transition-delay: 0.7s;
  }

  /* CTA. Squared and uppercase to match .cs-button-solid elsewhere on the
     site, with a sheen that sweeps once on entry so the eye is drawn to it
     last — after the links have already been read. */
  #cs-navigation .ww-menu-cta {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 1.05rem 1.25rem;
    border-radius: 0.25rem;
    background: linear-gradient(100deg, var(--primary) 0%, var(--accent) 100%);
    box-shadow: 0 0.75rem 1.75rem rgba(4, 76, 148, 0.42), inset 0 1px 0 rgba(255, 255, 255, 0.18);
    font-family: var(--headerFont);
    font-size: 1rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    text-decoration: none;
    color: #fff;
    overflow: hidden;
    /* This element IS .ww-menu-foot > *:nth-child(1), so it inherits the block's
       entry motion — and `transition` is a shorthand, so declaring one here
       (same specificity, later in the sheet) REPLACES that entry list rather
       than adding to it. Omitting the opacity leg is what made the CTA pop in
       at full strength the instant the menu opened while the contact tiles and
       brand tail below it faded up on the stagger: those are nth-child 2 and 3
       and set no transition of their own, so they kept the block's. The two
       entry legs have to be restated verbatim alongside the CTA's own
       box-shadow. */
    transition: opacity 0.4s ease, transform 0.55s var(--ww-settle), box-shadow 0.35s ease;
  }

  #cs-navigation .ww-menu-cta:active {
    transform: scale(0.985);
    box-shadow: 0 0.35rem 1rem rgba(4, 76, 148, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.18);
  }

  #cs-navigation .ww-menu-cta:after {
    content: "";
    position: absolute;
    top: -50%;
    left: -80%;
    height: 200%;
    width: 45%;
    background: linear-gradient(100deg, transparent, rgba(255, 255, 255, 0.28), transparent);
    transform: rotate(8deg);
    opacity: 0;
  }

  #cs-navigation.cs-active .ww-menu-cta:after {
    animation: ww-sheen 1.1s ease-out 0.95s both;
  }

  @keyframes ww-sheen {
    0% {
      opacity: 0;
      transform: translate3d(0, 0, 0) rotate(8deg);
    }
    22% {
      opacity: 1;
    }
    100% {
      opacity: 0;
      transform: translate3d(360%, 0, 0) rotate(8deg);
    }
  }

  #cs-navigation .ww-menu-cta svg {
    flex: none;
    height: 1rem;
    width: 1rem;
    transition: transform 0.4s var(--ww-settle);
  }

  #cs-navigation .ww-menu-cta:hover svg {
    transform: translateX(0.25rem);
  }

  /* Contact tiles. Call and Email, paired — the two things anyone opens a menu
     on a phone to find. Tap targets stay comfortably over the 44px minimum at
     every width. */
  #cs-navigation .ww-menu-contact {
    display: grid;
    /* auto tracks, not equal ones. The two tiles carry strings of different
       lengths — "tom@hginstall.com" measures a good 25% wider than the phone
       number — so splitting the row down the middle left the phone tile half
       empty while the email wrapped onto a second line. auto sizes each track
       to the text it actually holds and then stretches both by an equal share
       of whatever is left, which is what gets the address onto one line. */
    grid-template-columns: auto auto;
    gap: 0.5rem;
  }

  /* Below ~320px there is no font size that keeps two tiles on one row and
     stays readable, so they stack instead. */
  @media only screen and (max-width: 20rem) {
    #cs-navigation .ww-menu-contact {
      grid-template-columns: minmax(0, 1fr);
    }
  }

  #cs-navigation .ww-contact-row {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    min-height: 2.875rem;
    padding: 0.5rem 0.7rem;
    border-radius: 0.25rem;
    background: rgba(255, 255, 255, 0.045);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.06);
    text-decoration: none;
    transition: background-color 0.3s ease, transform 0.35s var(--ww-settle);
  }

  #cs-navigation a.ww-contact-row:active {
    background: rgba(255, 255, 255, 0.1);
    transform: scale(0.99);
  }

  #cs-navigation .ww-contact-row svg {
    flex: none;
    height: 1rem;
    width: 1rem;
    color: var(--secondary);
  }

  #cs-navigation .ww-contact-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
  }

  #cs-navigation .ww-contact-label {
    font-family: var(--bodyFont);
    font-size: 0.625rem;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.45);
  }

  #cs-navigation .ww-contact-value {
    font-family: var(--bodyFont);
    /* Sized to fit rather than fixed. Measured in Roboto 500, the address is
       8.73× the font size wide and the number 6.97×; each tile spends a fixed
       48px on its icon, gap and padding, and the drawer spends 48px of its own
       on side padding. So both tiles clear one row while
       15.7F + 104 <= viewport, i.e. F <= (100vw - 152px) / 15.7. The middle
       term sits just under that line and reaches the 14px cap at 390px, which
       is where most phones already were. */
    font-size: clamp(0.625rem, calc(6vw - 9px), 0.875rem);
    font-weight: 500;
    line-height: 1.3;
    color: #fff;
    /* The whole point: never break the address across two lines. */
    white-space: nowrap;
  }

  /* Brand tail. */
  #cs-navigation .ww-menu-meta {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
  }

  #cs-navigation .ww-menu-tagline {
    display: flex;
    flex-direction: column;
    margin: 0;
    font-family: var(--headerFont);
    font-size: 0.9375rem;
    font-weight: 700;
    font-style: italic;
    letter-spacing: 0.02em;
    color: var(--secondaryLight);
  }

  #cs-navigation .ww-menu-tagline span {
    font-family: var(--bodyFont);
    font-size: 0.5625rem;
    font-weight: 400;
    font-style: normal;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.4);
  }

  #cs-navigation .ww-menu-social {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: none;
    height: 2.75rem;
    width: 2.75rem;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.07);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1);
    color: #fff;
    transition: background-color 0.3s ease, transform 0.4s var(--ww-settle);
  }

  #cs-navigation .ww-menu-social:hover,
  #cs-navigation .ww-menu-social:active {
    background: var(--primary);
    transform: translateY(-2px);
  }

  #cs-navigation .ww-menu-social svg {
    height: 1rem;
    width: 1rem;
  }

}

/* --------------------------------------------------------------------------
   Tablet: more room, so the type grows and the contact tiles pair up.
   -------------------------------------------------------------------------- */
@media only screen and (min-width: 40.625rem) and (max-width: 74.96875rem) {
  #cs-navigation .ww-menu-body {
    max-width: 40rem;
    padding-left: 2.5rem;
    padding-right: 2.5rem;
  }

  #cs-navigation .cs-nav .cs-ul > .cs-li > .cs-li-link {
    padding: 1rem 0.25rem;
  }

  /* critical.css re-parks the theme toggle for the tucked-up header with
     `.scroll #dark-mode-toggle{top:4.25rem;right:4.875rem}` under a blanket
     max-width:74.96875rem. Those are coordinates only on the phone bar, where
     the button is position:absolute inside the header. From 40.625rem the
     template makes it a relative flex item in the bottom row, and on a
     relative box the same offsets are a *nudge*: scrolling shoved the moon
     4.25rem down and 4.875rem left, out of the bar and onto the hero. There is
     nothing to re-park at this size — the flex row already moves with the
     header — so the offsets go back to auto. The open-menu re-park earlier in
     this file (top:0/right:1rem) is the same coordinates-vs-nudge story and
     gets the same treatment. */
  #cs-navigation.scroll #dark-mode-toggle,
  body.cs-open #cs-navigation.scroll #dark-mode-toggle,
  body.ww-menu-closing #cs-navigation.scroll #dark-mode-toggle {
    top: auto;
    right: auto;
  }
}

/* --------------------------------------------------------------------------
   Reduced motion. The choreography is the point of this menu, so rather than
   half-disable it the whole thing collapses to a single honest cross-fade:
   panes already seated, links already in place, no drift, no glint, no sheen.
   -------------------------------------------------------------------------- */
@media only screen and (max-width: 74.96875rem) and (prefers-reduced-motion: reduce) {
  #cs-navigation .cs-ul-wrapper,
  #cs-navigation .ww-menu-fx,
  #cs-navigation .ww-menu-body,
  #cs-navigation .ww-pane,
  #cs-navigation .cs-nav .cs-li,
  #cs-navigation .ww-menu-foot > *,
  #cs-navigation .cs-line,
  #cs-navigation .ww-menu-glow,
  #cs-navigation .ww-menu-grid {
    transition-duration: 0.001s !important;
    transition-delay: 0s !important;
    animation: none !important;
  }

  #cs-navigation .ww-pane {
    transform: none;
  }

  #cs-navigation .cs-nav .cs-li {
    transform: none;
    filter: none;
  }

  #cs-navigation .cs-ul-wrapper {
    opacity: 0;
    transition: opacity 0.2s linear, visibility 0s linear 0.2s !important;
  }

  #cs-navigation.cs-active .cs-ul-wrapper {
    opacity: 1;
  }

  #cs-navigation .ww-menu-glow {
    animation: none !important;
  }
}

/* ==========================================================================
   Current-page state for the Windows / Doors submenu.

   The top-level links (Home, About Us, Gallery) have carried .cs-active since
   the export; the two dropdown children never did — there was no template
   condition and no style for one, so /windows/ and /doors/ were the only pages
   with nothing lit in the nav.

   Why the parent <li> gets ww-section-active and NOT .cs-active: in this nav
   .cs-active is already three different states depending on where it lands —
   menu-open on #cs-navigation, submenu-open on .cs-dropdown, current-page on a
   link. Marking the current section with .cs-active on the <li> would trip the
   `.cs-dropdown.cs-active .cs-drop-ul` rule and hang the submenu permanently
   open on mobile. A separate class keeps the two meanings apart.
   ========================================================================== */

/* ---- desktop: the hover panel ------------------------------------------ */
@media only screen and (min-width: 75rem) {
  /* Out-specifies the base `.cs-li-link.cs-drop-link` colour (1 id + 2
     classes) with 1 id + 4. Deliberately not the panel's hover treatment
     (solid --primary fill): hovering the current item should still read as a
     hover, so this is the quieter pair — brand colour, weight, and a bar on
     the leading edge. */
  #cs-navigation .cs-nav .cs-li-link.cs-drop-link.cs-active {
    color: var(--primary);
    font-weight: 700;
    box-shadow: inset 3px 0 0 var(--primary);
  }

  /* --primary is the same near-black-on-navy problem the top-level active
     link has in dark mode, so it takes the same on-dark accent. root.css sets
     that at 1 id + 3 classes and would lose to the rule above; this restates
     it one class higher. */
  body.dark-mode #cs-navigation .cs-nav .cs-li-link.cs-drop-link.cs-active {
    color: var(--onDarkAccent);
    box-shadow: inset 3px 0 0 var(--onDarkAccent);
  }

  /* The closed panel gives no clue which section you are in, since the submenu
     is only visible on hover. This lights the trigger itself. */
  #cs-navigation .cs-nav .cs-dropdown.ww-section-active > .cs-li-link {
    color: var(--primary);
  }

  body.dark-mode #cs-navigation .cs-nav .cs-dropdown.ww-section-active > .cs-li-link {
    color: var(--onDarkAccent);
  }
}

/* ---- mobile: the glass panel ------------------------------------------- */
@media only screen and (max-width: 74.96875rem) {
  /* Matches the top-level current-page row, one step quieter: the same
     --secondaryLight text, and the accent bar that hover animates in is simply
     held lit instead of a second competing treatment. */
  #cs-navigation .cs-nav .cs-li-link.cs-drop-link.cs-active {
    color: var(--secondaryLight);
  }

  #cs-navigation .cs-nav .cs-li-link.cs-drop-link.cs-active:before {
    height: 60%;
  }

  /* Hover still has somewhere to go from the active state. */
  #cs-navigation .cs-nav .cs-drop-li:hover .cs-drop-link.cs-active,
  #cs-navigation .cs-nav .cs-drop-link.cs-active:focus-visible {
    color: #fff;
  }
}
