/* ==========================================================================
   Seven D Wholesale — 7dwholesale.com
   Hand-authored stylesheet. Every value is taken from the forensic capture of
   the live site (capture/analysis/design-system.md and reproduction-guide.md),
   which recorded each one with its source file and line number.

   This replaces 936 KB of Elementor-generated CSS across 39 files.
   Cascade here is authored, not machine-emitted: tokens → base → layout →
   components → pages.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. TOKENS
   -------------------------------------------------------------------------- */
:root {
  /* Colour — the live Elementor kit defines only two globals; everything else
     on the original was hard-coded per element. These are those values. */
  --c-primary:        #000000;              /* headings, button text, footer bg */
  --c-text:           rgba(0, 0, 0, 0.541); /* #0000008A — global body text     */
  --c-heading-6:      #081B22;
  --c-link:           #5b7bfb;
  --c-link-hover:     #181b31;

  --c-nav-link:       rgba(0, 0, 0, 0.949); /* #000000F2 */
  --c-nav-link-hover: #000000;

  --c-header-bg:      #ffffff;
  --c-footer-bg:      #000000;
  --c-footer-text:    rgba(255, 255, 255, 0.541); /* #FFFFFF8A */
  --c-footer-menu:    rgba(255, 255, 255, 0.70);  /* #FFFFFFB3 */
  --c-footer-micro:   rgba(255, 255, 255, 0.47);  /* #FFFFFF78 */

  --c-dark-band:      #0C2327;   /* homepage locations tabs */
  --c-deep-teal:      #032326;   /* brand-page CTA section  */
  --c-reveal-wipe:    #345B5D;   /* block-revealer element  */

  --c-pill-bg:        #E3E3E3;   /* "Product" eyebrow chip  */
  --c-chip-bg:        #F7F7F7;
  --c-band-light:     #F7F8FA;
  --c-border-btn:     #BCBCBC;
  --c-cta-link:       #BABABA;
  --c-circle-btn:     #2E2E2E;

  /* Typography */
  --font-display: "termina", "Archivo", "Helvetica Neue", Arial, sans-serif;
  --font-body:    "DM Sans", "Helvetica Neue", Arial, sans-serif;
  --font-caps:    "Six Caps", "Oswald", "Arial Narrow", sans-serif;

  /* The live Adobe kit ships only weight 600, so every heading on the real
     site renders at 600 even though its CSS asks for 500. Matching reality. */
  --fw-heading: 600;

  /* Layout */
  --container:   1170px;
  --gutter:      15px;

  /* Effects */
  --ease-signature: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-alt:       cubic-bezier(0.19, 1, 0.22, 1);
  --radius-card:    2px;
  --radius-box:     16px;
  --radius-pill:    99px;
  --shadow-glass:   0 4px 30px rgba(0, 0, 0, 0.1);
  --shadow-btn:     0 12px 28px rgba(0, 0, 0, 0.12);
}

/* --------------------------------------------------------------------------
   2. BASE
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: 16px;
  font-weight: 400;
  line-height: 1.56em;
  color: var(--c-text);
  background: #fff;
  overflow-x: hidden;
}

img { max-width: 100%; height: auto; border: 0; display: block; }

a {
  color: var(--c-link);
  text-decoration: none;
  transition: all .3s;
}
a:hover { color: var(--c-link-hover); }

/* Heading margins survive from the theme's base typography sheet. */
h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-display);
  font-weight: var(--fw-heading);
  line-height: 1.2em;
  color: var(--c-primary);
  margin: 1em 0 .5em;
  /* Upstream every heading is SplitText (a <span> per character), so a word
     longer than its column wraps instead of painting into the next element.
     We render plain text nodes, so this restores that wrap as a safety net —
     it only ever triggers when a word would otherwise overflow its box. */
  overflow-wrap: break-word;
}
h1 { font-size: 52px; margin-top: 0; }
h2 { font-size: 40px; margin-top: .75em; }
h3 { font-size: 32px; }
h4 { font-size: 25px; }
h5 { font-size: 21px; }
h6 {
  font-family: var(--font-body);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .81px;
  text-transform: uppercase;
  color: var(--c-heading-6);
}

p { margin: 0 0 1.5em; }

::selection      { background: rgb(219, 205, 184); }
::-moz-selection { background: rgb(219, 205, 184); }

/* The theme replaces the system cursor site-wide. */
body {
  cursor: url('/assets/img/custom-cursor-1.svg'), auto;
  --lqd-cc-active-bw: 1px;
}

/* --- GDPR notice ---------------------------------------------------------- */
.lqd-gdpr {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 120;
  background: #fff;
  box-shadow: 0 -4px 30px rgba(0, 0, 0, .12);
}
.lqd-gdpr[hidden] { display: none; }
/* Measured upstream: the bar is a centred pill, not a full-width strip —
   the notice sits at x=466 and is only 503px wide, 14.4px on a 21.6px line
   in rgba(0,0,0,.86), with a light #EFF3F5 rounded Accept button in plain
   black 14px (no uppercase, no tracking). */
.lqd-gdpr-inner {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  flex-wrap: wrap;
  max-width: 1170px;
  margin-inline: auto;
  padding: 18px 15px;
}
.lqd-gdpr-left {
  font-size: 14.4px;
  line-height: 21.6px;
  color: rgba(0, 0, 0, .86);
  padding-right: 16px;
}
.lqd-gdpr-accept {
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 400;
  line-height: 14px;
  letter-spacing: normal;
  text-transform: none;
  color: #000;
  background: #EFF3F5;
  border: 0;
  border-radius: var(--radius-pill);
  padding: 8px 23px;
  cursor: pointer;
  transition: transform .3s var(--ease-signature);
}
.lqd-gdpr-accept:hover { transform: translateY(-2px); }

/* .screen-reader-text is the label the skip-link block carries upstream, where
   it is hidden. Without it here the words "Skip links" painted 25px of visible
   text above the header on every page and pushed the whole document down. */
.visually-hidden,
.screen-reader-text {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: #000; color: #fff; padding: 12px 20px;
}
.skip-link:focus { left: 0; color: #fff; }

/* --------------------------------------------------------------------------
   3. LAYOUT — the container ladder
   -------------------------------------------------------------------------- */
/* Two separate ladders exist upstream and they disagree. Bootstrap's .container
   drives the titlebar and the page body; Elementor's drives the header and
   footer rows. Collapsing them into one made the body 1070px at a 1100px
   viewport where the original is 970px. */
/* Upstream `main#lqd-site-content` tiles lines-bg-1.svg across the whole
   content area — a 480×10 tile whose only ink is a 1px vertical rule at
   rgba(22,23,30,.07), so the page carries faint pinstripes every 480px.
   HOMEPAGE ONLY: the same element on brand pages computes background-image:
   none, so this must not go sitewide. */
.home #main {
  background-image: url('/assets/img/lines-bg-1.svg');
  background-repeat: repeat;
  background-position: 50% 50%;
}

.container {
  width: 100%;
  margin-inline: auto;
  padding-inline: var(--gutter);
}
@media (min-width: 768px)  { .container { width: 750px;  } }
@media (min-width: 992px)  { .container { width: 970px;  } }
@media (min-width: 1200px) { .container { width: 1170px; } }

/* The HOMEPAGE rows are Elementor flex containers (.e-con), whose content box
   is 1170 with no gutter — 30px wider than the Bootstrap .container that
   drives the titlebar and every inner page. Measured on the reference render
   at a 1425 viewport: homepage rows sit at x=128/w=1170, brand pages at
   x=143/w=1140. Two ladders, and they really do disagree. */
@media (min-width: 1200px) { .container--wide { width: 1200px; } }

/* Elementor rows — header, footer */
.e-container {
  width: 100%;
  max-width: 1170px;
  margin-inline: auto;
  padding-inline: var(--gutter);
}
@media (max-width: 1024px) { .e-container { max-width: 1024px; } }
@media (max-width: 767px)  { .e-container { max-width: 767px;  } }

.section { padding: 80px 0; }
@media (max-width: 1024px) { .section { padding: 40px; } }
@media (max-width: 767px)  { .section { padding: 30px 20px; } }

.full-bleed { width: 100%; }

/* --------------------------------------------------------------------------
   4. BUTTONS
   -------------------------------------------------------------------------- */

/* The signature outlined CTA: four 12px corner brackets that rotate and scale
   on hover. This is the button used on every brand page. */
.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  white-space: nowrap;
  overflow: hidden;
  font-family: var(--font-body);
  font-size: 13px;
  letter-spacing: 1px;
  text-transform: uppercase;
  cursor: pointer;
  transition: color .3s var(--ease-signature),
              background-color .3s var(--ease-signature),
              border-color .3s var(--ease-signature),
              transform .3s var(--ease-signature),
              box-shadow .3s var(--ease-signature);
}

.btn-brand {
  width: 212px;
  height: 50px;
  color: var(--c-primary);
  background-color: #fff;
  border: 1px solid var(--c-border-btn);
  --extended-line-size: 12px;
}
.btn-brand:hover,
.btn-brand:focus-visible {
  color: #fff;
  background-color: #000;
  border-color: #000;
}

.btn-extended-line {
  position: absolute;
  width: var(--extended-line-size, 12px);
  height: var(--extended-line-size, 12px);
  border-style: solid;
  border-color: #fff;
  border-width: 0;
  pointer-events: none;
  transition: transform .45s var(--ease-signature),
              border-color .3s var(--ease-signature);
}
.btn-extended-line-tl { top: -1px; left: -1px;  border-top-width: 1px; border-left-width: 1px; }
.btn-extended-line-tr { top: -1px; right: -1px; border-top-width: 1px; border-right-width: 1px; }
.btn-extended-line-br { bottom: -1px; right: -1px; border-bottom-width: 1px; border-right-width: 1px; }
.btn-extended-line-bl { bottom: -1px; left: -1px;  border-bottom-width: 1px; border-left-width: 1px; }

.btn-brand:hover .btn-extended-line,
.btn-brand:focus-visible .btn-extended-line {
  border-color: #000;
  transform: rotate(180deg) scale(1.2);
}

/* Naked text button with a sliding arrow — the "Visit Us" CTA. */
.btn-naked {
  position: relative;
  z-index: 10;
  background: none;
  border: 0;
  padding: 0;
  font-weight: 700;
  color: var(--c-cta-link);
}
.btn-naked:hover { color: #fff; }
.btn-naked .btn-icon {
  display: inline-flex;
  font-size: 1.3em;
  margin-inline-start: 0.75em;
  transition: transform .45s var(--ease-signature);
}
.btn-naked:hover .btn-icon { transform: translateX(6px); }

/* Solid button used in page bodies. */
.btn-solid {
  background: #000;
  color: #fff;
  border: 0;
  padding: 16px 32px;
}
.btn-solid:hover {
  transform: translate3d(0, -2px, 0);
  box-shadow: var(--shadow-btn);
  color: #fff;
}

/* --------------------------------------------------------------------------
   5. HEADER
   -------------------------------------------------------------------------- */
.sticky-placeholder { display: none; height: 80px; }
.sticky-placeholder.is-active { display: block; }

.main-header {
  position: relative;
  z-index: 99;
  width: 100%;
  background-color: var(--c-header-bg);
  transition: background-color .3s var(--ease-signature);
}
.main-header.is-stuck {
  position: fixed;
  top: 0; left: 0; right: 0;
  box-shadow: 0 2px 20px rgba(0, 0, 0, .06);
}

.header-row {
  display: flex;
  align-items: center;
  padding: 0 30px;
}

.header-logo { flex: 0 0 20%; max-width: 20%; }
.header-logo .module-logo { display: block; padding: 25px 0; }
/* The source PNG is 80x93 and the original ships no width/height on it, so it
   renders at natural size. The wp-custom-css `width:150%` rule targets the
   MOBILE `a.navbar-brand` wrapper, not this image — applying it here blows the
   logo up to ~240px and swallows the viewport. */
.header-logo .module-logo img { width: auto; height: auto; max-height: 93px; }

.header-tools {
  flex: 0 0 80%;
  max-width: 80%;
  /* Fills the 143px header row so the nav can too — see .main-nav. The search
     button stays centred on its own; only the nav is stretched. */
  align-self: stretch;
  display: flex;
  align-items: center;
  justify-content: flex-end;
}

/* --- primary nav ------------------------------------------------------- */
/* The items STRETCH to the full header height upstream — the anchor is 143
   tall, not 45, with its label centred inside. That is not just hit-area: the
   hover underline is positioned `bottom: 20px` against the ANCHOR, so on a
   45px anchor it lands 12px INTO the text and reads as a strikethrough. At the
   real height it sits 37px below the label, near the foot of the header. */
.header-tools > nav { align-self: stretch; display: flex; }
.main-nav {
  height: 100%;
  display: flex;
  align-items: stretch;
  list-style: none;
  margin: 0;
  padding: 0;
  --nav-underline-height: 2px;
  --nav-underline-bottom-offset: 20px;
  --nav-underline-left-offset: 30px;
  --nav-underline-right-offset: 30px;
}
.main-nav > li { position: relative; display: flex; }
.main-nav > li > a {
  position: relative;
  display: flex;
  align-items: center;
  padding: 10px 20px;
  font-family: var(--font-body);
  font-size: 20px;
  font-weight: 700;
  letter-spacing: 1.3px;
  text-transform: uppercase;
  color: var(--c-nav-link);
}
.main-header.is-stuck .main-nav > li > a { padding-inline: 30px; }

.main-nav > li > a::after {
  content: "";
  position: absolute;
  bottom: var(--nav-underline-bottom-offset);
  left: var(--nav-underline-left-offset);
  right: var(--nav-underline-right-offset);
  height: var(--nav-underline-height);
  background-color: currentColor;
  transform: scaleX(0);
  /* Retracts rightwards on mouse-out, grows from the left on hover. */
  transform-origin: right center;
  transition: transform .85s var(--ease-signature);
}
.main-nav > li:hover > a::after,
.main-nav > li.is-active > a::after { transform-origin: left center; }
.main-nav > li:hover > a,
.main-nav > li.is-active > a { color: var(--c-nav-link-hover); }
.main-nav > li:hover > a::after,
.main-nav > li.is-active > a::after { transform: scaleX(1); }

/* --- mega dropdown ------------------------------------------------------ */
.main-nav .sub-menu {
  position: absolute;
  top: 100%;
  left: 0;
  min-width: 232px;
  margin: 0;
  padding: 1.0625em 0;
  list-style: none;
  background: #fff;
  border-radius: 5px;
  box-shadow: 0 16px 50px rgba(0, 0, 0, 0.07);
  opacity: 0;
  visibility: hidden;
  transform: translateY(10px);
  transition: all .85s var(--ease-alt);
  z-index: 20;
}
.main-nav li:hover > .sub-menu,
.main-nav li:focus-within > .sub-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}
.main-nav .sub-menu li { position: relative; }
.main-nav .sub-menu a {
  display: block;
  padding: 0.75em 1.75em;
  font-size: 16px;
  color: rgba(0, 0, 0, 0.55);
  white-space: nowrap;
}
.main-nav .sub-menu a:hover { color: #000; }

/* Third level opens to the SIDE. It must open leftward, not rightward: the
   only mega-menu ("Products") sits right-of-centre, so a rightward flyout ran
   ~112px past the viewport and made every page horizontally scrollable. */
.main-nav .sub-menu .sub-menu { top: 0; left: auto; right: 104%; }
/* The original sets .submenu-expander{display:none} at desktop — no chevron is
   drawn anywhere in the desktop nav. Kept for the mobile panel only. */

/* --- header buttons ---------------------------------------------------- */
.header-search-trigger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 46px; height: 46px;
  margin: 0 12px;
  border: 1px solid rgba(0, 0, 0, .259); /* #00000042 */
  border-radius: var(--radius-pill);
  background: none;
  cursor: pointer;
  transition: background .3s var(--ease-signature);
}
/* no hover background upstream */

/* --- mobile header ------------------------------------------------------
   The live site switches at 1200px, driven by a data attribute on <body>,
   not at the 1024px tablet breakpoint. Matching that. */
.mobile-header { display: none; }

@media (max-width: 1200px) {
  .header-row { display: none; }
  .mobile-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 20px;
  }
  /* This is the element wp-custom-css widens to 150%; the 80px image inside
     does not scale with it, which is why the original logo stays small. */
  .mobile-header .navbar-brand { display: block; }
  .mobile-header .navbar-brand img { width: auto; height: auto; max-height: 60px; }
  .nav-trigger {
    width: 52px; height: 52px;
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 5px;
    background: none;
    border: 1px solid rgba(0, 0, 0, .129); /* #00000021 */
    cursor: pointer;
  }
  .nav-trigger .bar {
    display: block;
    width: 22px; height: 2px;
    background: #000;
    transition: transform .3s var(--ease-signature), opacity .2s;
  }
  .nav-trigger.is-open .bar:nth-child(1) { transform: translateY(7px) rotate(45deg); }
  .nav-trigger.is-open .bar:nth-child(2) { opacity: 0; }
  .nav-trigger.is-open .bar:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
}

/* Real mobile menu — mirrors the desktop nav.
   The original shipped a raw alphabetical dump of all 44 pages here. */
.mobile-nav {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 98;
  background: #fff;
  padding: 90px 24px 40px;
  overflow-y: auto;
}
.mobile-nav.is-open { display: block; }
.mobile-nav ul { list-style: none; margin: 0; padding: 0; }
.mobile-nav > ul > li { border-bottom: 1px solid rgba(0, 0, 0, .08); }
.mobile-nav a {
  display: block;
  padding: 14px 0;
  font-size: 15px;
  font-weight: 500;
  color: var(--c-nav-link);
}
.mobile-nav .sub-menu { display: none; padding-left: 16px; }
.mobile-nav .sub-menu.is-open { display: block; }
.mobile-nav .sub-menu a { font-size: 14px; font-weight: 400; opacity: .8; }
.mobile-nav .toggle-sub {
  position: absolute; right: 0; top: 6px;
  width: 40px; height: 40px;
  background: none; border: 0; cursor: pointer;
  font-size: 20px; line-height: 1; color: #000;
}
.mobile-nav li { position: relative; }

/* --------------------------------------------------------------------------
   6. BRAND PAGE — hero
   -------------------------------------------------------------------------- */
/* The original marks this section `elementor-section-stretched` with a
   `full_width` container: it breaks out of the 1170px wrapper and spans the
   whole viewport, so each column is 50% of the window, not 50% of 1170px. */
.brand-hero {
  padding: 80px 0;
  overflow: hidden;
}
@media (max-width: 1024px) { .brand-hero { padding: 40px; } }
@media (max-width: 767px)  { .brand-hero { padding: 30px 20px; } }

.brand-hero-inner {
  display: flex;
  align-items: center;
  width: 100%;
  position: relative;
  z-index: 2;
}

/* acre-siding / davinci-roofscapes: a siding photograph behind a 76% black
   overlay, with all hero type reversed to white. */
.brand-hero--photo { position: relative; }
/* The clone pages inset BOTH columns by the same 106.875/71.25 the copy column
   uses, so the photograph is 534 wide at x=819 — not the 640-at-713 the brand
   pages use, and not the full 713 it filled once the media column's padding
   came off. */
@media (min-width: 1025px) {
  .brand-hero--photo .brand-hero-media { padding: 0 71.25px 0 106.875px; }
  .brand-hero--photo .brand-hero-media img { width: 100%; }
}
/* And no -50px lift here: on the clones the photograph sits level with its
   column (510), unlike the brand pages where it is pulled up. */
.brand-hero--photo .brand-hero-media > img { top: 0; }
.brand-hero-bg {
  position: absolute; inset: 0;
  background-position: center right;
  background-size: cover;
  background-repeat: no-repeat;
}
.brand-hero-overlay {
  position: absolute; inset: 0;
  background-color: #000000;
  opacity: 0.76;
}
.brand-hero--photo .brand-title,
.brand-hero--photo .brand-blurb { color: #FFFFFF; }
/* Compound selector so this modifier beats the later, equal-specificity
   `.brand-title` base rule (clones render at 34px, not 60px). */
/* Upstream this heading is SplitText, so each WORD is its own inline-flex box
   and can wrap to a new line but never split. The global break-word safety net
   was cutting "ThermoSheath" after "ThermoSheat" and dropping the h onto a
   fourth line — the reference sets it whole on three. */
.brand-title { overflow-wrap: normal; word-break: normal; }
.brand-title.brand-title--sm { font-size: 34px; line-height: .9em; }
@media (max-width: 1024px) { .brand-title.brand-title--sm { font-size: 12vw; } }
@media (max-width: 767px)  { .brand-title.brand-title--sm { font-size: 22vw; } }
.brand-actions--end { justify-content: flex-end; align-items: stretch; }
.brand-hero-col { width: 50%; }

/* Padding lives on this inner block, NOT on the flex item. Percentage padding
   on a flex item resolves against the flex CONTAINER's width, which doubled it
   and left half the column unusable. On a block child it resolves against the
   column, which is what the original does. */
.brand-hero-copy-inner { padding: 0 10% 0 15%; }
/* No widget padding on the media column upstream: the image sits flush at the
   column's left edge (x=713) and the column is exactly as tall as the image
   (853). The 10px here was adding 20 to the hero on all 21 brand pages. */
.brand-hero-media { overflow: hidden; padding: 0; }
/* Only rosboro stretches its hero image; every other page renders it at its
   intrinsic size, left-aligned. */
.brand-hero-media img { width: auto; max-width: 100%; }
/* The image is painted 50px above its column upstream (widget at 460 against
   a column at 510). Offset rather than margin so the column keeps its 853. */
.brand-hero-media > img { position: relative; top: -50px; }
/* engineered-lumber's three product photos render at 60% of the column,
   centred, matching live (the intro image already gets 60% via introImgW).
   img is display:block here, so it centres via auto margins, not text-align. */
/* Measured on the reference: the intro band's photo renders 384x512 centred at
   x=877, and the three repeated product blocks render it at only 180x240
   centred at x=979 — the upstream `.lqd-imggrp-single` is shrink-to-fit around
   a 640 and a 300 declared width respectively, and the 60% rule then resolves
   against THAT, not against the 713 column. Taking 60% of the column gave
   428x570 on every block, 2.4x too big, and made this page 119 too tall.
   img is display:block, so it centres by auto margins, not text-align. */
.page-engineered-lumber .brand-hero-media img { width: 384px; margin-inline: auto; }
/* The intro image carries an inline width:60% from the data, and inline wins —
   so the fix is the BASIS, not the value. Upstream that 60% resolves against a
   640-wide shrink-to-fit wrapper (384), where here it was resolving against
   the 692.5 column (415.5). Giving the wrapper its real 640 and centring it in
   the 713 column puts the image at 384x512 starting at x=877, as measured.
   Fourth time this percentage-basis trap has bitten on this rebuild. */
.page-engineered-lumber .cat-intro-media { width: 640px; max-width: 100%; margin-inline: auto; }
/* All FOUR product photographs on this page are 384x512 at x=877 — measured on
   both surfaces. The 180px this rule used to force put three of them at
   180x240 and 102px right of where they belong. Same 60%-of-a-640-wrapper as
   the intro image above, not 60% of a 300 one. */
.page-engineered-lumber .brand-hero-media img { width: 384px; margin-inline: auto; }
/* No -50px lift on this page — its images sit level with their columns. */
.page-engineered-lumber .brand-hero-media > img { top: 0; }
/* rosboro does NOT stretch its hero image — that was a misreading of its one
   extra rule, `img{width:100%}`. Upstream that img sits inside
   `.lqd-imggrp-single`, which is `display:inline-flex` and therefore
   shrink-to-fit: the percentage resolves against the image's own intrinsic
   640px, not the 713 column. Measured on the reference: 640x853 at x=749 in a
   713 column starting at 713, i.e. exactly CENTRED — which is what the
   accompanying `text-align:center` is for, and it would be a no-op if the
   image really filled. Flattened into a bare <img> here, `width:100%` meant
   what it says and blew the photo up to 713x950, making the page 97px too
   tall at 1440 and proportionally worse at wider viewports.
   img is display:block, so it centres by auto margins, not text-align. */
.brand-hero-media--fill img { width: auto; margin-inline: auto; }
/* And no -50px lift on this one: its image sits level with the column at 510,
   where gaf's is pulled up to 460. */
.brand-hero-media--fill > img { top: 0; }

/* Repeated-hero index pages alternate sides so a stack of product blocks
   doesn't read as one long left-aligned column. */
.brand-hero-inner--reverse { flex-direction: row-reverse; }
.brand-hero-inner--reverse .brand-hero-copy-inner { padding: 0 15% 0 10%; }
@media (max-width: 1024px) {
  .brand-hero-inner--reverse { flex-direction: column-reverse; }
  .brand-hero-inner--reverse .brand-hero-copy-inner { padding: 10px; }
}

@media (max-width: 1024px) {
  .brand-hero-col { width: 100%; }
  .brand-hero-copy-inner { padding: 10px; }
  .brand-hero-media { padding: 10px; margin: 0; }
}
/* Elementor scopes `elementor-reverse-mobile` to <=767px only. Between 768 and
   1024 the original stacks copy first, not image first. */
@media (max-width: 767px) {
  .brand-hero-inner { flex-direction: column-reverse; }
  .brand-hero-copy { margin-top: 20px; }
}

/* The pill is 25 tall upstream around a 12px line, and the block it sits in is
   45 — 25 plus a 20px margin. Measured on /gaf/: eyebrow block 675..720, with
   the title starting at 720. */
.eyebrow {
  display: inline-block;
  background-color: var(--c-pill-bg);
  border-radius: var(--radius-card);
  padding: 4px 0;
  margin: 0 0 20px;
}
.eyebrow h6 { margin: 0 0 .5em; padding: 0 16px; }

.brand-title {
  font-size: 60px;
  line-height: .9em;
  margin: 0;
  /* Measured on the reference render: the box is exactly one 54px line tall —
     the 10px bottom padding here was invented and made it 64.
     Upstream this heading is also inline-block, but setting that here centres
     it (x 107 -> 196) because of the enclosing text alignment; a too-wide box
     is invisible where a shifted heading is not, so it stays block. */
  padding: 0;
  /* The 10px does exist, but on the widget WRAPPER, not the heading: the
     title block measures 64 and the blurb starts 64 below it. As margin the
     heading box stays the 54 it should be and the spacing is still right. */
  margin-bottom: 10px;
}
@media (max-width: 1024px) { .brand-title { font-size: 12vw; } }
@media (max-width: 767px) {
  /* The original renders 22vw here, which makes long brand names enormous on a
     390px viewport. Clamped — recorded as an approved exception. */
  .brand-title { font-size: clamp(38px, 14vw, 68px); }
}

/* The widget is deliberately wider than its column upstream; without this the
   measure is ~7.5% narrow and every page wraps differently. */
.brand-blurb {
  color: var(--c-primary);
  width: 107.471%;
  max-width: 107.471%;
  flex: 0 0 auto;
  margin: 0 0 2em;
  /* Upstream this is 22%, but a percentage padding resolves against the
     CONTAINING BLOCK — there the widget (574), here .brand-hero-copy-inner
     (534). 22% of 574 is 126.34, and 22% of 534 is only 117.6, which gave the
     blurb an extra ~9px of measure and dropped it a whole line short (7 lines
     against the original's 8). 107.471% x 22% = 23.643% of the container. */
  padding: 0 23.643% 0 0;
}
@media (max-width: 1024px) { .brand-blurb { padding: 0; } }

/* The row starts at the column inset and its contents are 10px in from there
   — measured x=107 for the block, x=117 for the button. The -10px here pulled
   the whole row 20px left of the original. */
.brand-actions {
  display: flex;
  align-items: flex-start;
  padding: 10px;
}
.brand-actions--around     { justify-content: space-around; }
.brand-actions--around-end { justify-content: space-around; align-items: flex-end; }
.brand-actions-btn { width: 48.752%; margin: 0 0 40px; }
.brand-actions-logo { flex: 1; text-align: start; }
/* Logo width differs per page — set inline from the per-brand table. Defaulting
   every logo to 100% blew a 115px USG mark up to ~285px. */
.brand-actions-logo img { width: auto; max-width: 100%; }
@media (max-width: 767px) {
  .brand-actions { flex-wrap: wrap; gap: 24px; }
  .brand-actions-btn { width: 100%; }
  .brand-actions-logo { max-width: 200px; }
}

/* --------------------------------------------------------------------------
   7. BRAND PAGE — CTA band
   -------------------------------------------------------------------------- */
.brand-cta {
  position: relative;
  background-color: var(--c-deep-teal);
  color: #fff;
  transition: background .3s, border .3s, border-radius .3s, box-shadow .3s;
  overflow: hidden;
}
.brand-cta-inner {
  position: relative;
  max-width: 1000px;
  min-height: 100vh;
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
/* Upstream's 1000x270 column: it is the containing block the photograph is
   absolutely positioned against, and its 10px padding is what puts the copy at
   x=230. Anchoring the picture to the 900-tall band instead lifted it 315px,
   clear of the heading, where upstream it sits behind it — and the 15px gutter
   put every line 5px right of where it belongs. */
.brand-cta-copy { position: relative; padding: 10px; }
@media (max-width: 1024px) { .brand-cta { padding: 0 15px; } }
@media (max-width: 767px)  { .brand-cta { padding: 45px 15px 0; } }

/* Stays 152px from desktop through tablet, then jumps to 30vw. The rebuild had
   this ladder inverted — 184px at 1024 and only 67px at 375. */
.brand-cta h2 {
  position: relative;
  z-index: 2;
  color: #fff;
  font-family: var(--font-caps);
  font-size: 152px;
  font-weight: 400;
  line-height: 1em;
  margin: 0 0 .1em;
  /* ld_fancy_heading is d-inline-block: the box hugs the name (100px for
     "GAF"), it does not fill the 970px column. */
  display: inline-block;
  align-self: flex-start;
}
@media (max-width: 767px) { .brand-cta h2 { font-size: 30vw; } }

.brand-cta p { position: relative; z-index: 2; color: #FFFFFF; }
/* The CTA is a flex child of a column, so it stretches and centres its label
   unless pinned; upstream it sits hard left under the lede. */
.brand-cta .btn { align-self: flex-start; }
.brand-cta-lede { padding: 0 55% 0 0; margin: 0 0 2em; }
@media (max-width: 1024px) { .brand-cta-lede { padding: 0 50% 0 0; } }
@media (max-width: 767px)  { .brand-cta-lede { padding: 0; } }
.brand-cta a { color: var(--c-cta-link); }
.brand-cta a:hover { color: #fff; }
/* The arrow is absolute and starts at opacity 0 — it is a hover reveal, not
   part of the label. In flow and visible it made the button 94px where
   upstream measures 59.72, and painted an arrow the original never shows. */
.brand-cta .btn-naked { position: relative; }
.brand-cta .btn-naked .btn-icon {
  position: absolute;
  left: 33.06px;
  top: 4.02px;
  width: 16.91px;
  height: 16.91px;
  margin-left: 9.75px;
  opacity: 0;
  transition: opacity .3s var(--ease-signature), transform .3s var(--ease-signature);
}
.brand-cta .btn-naked:hover .btn-icon,
.brand-cta .btn-naked:focus-visible .btn-icon { opacity: 1; transform: translateX(2em); }

.brand-cta-img {
  position: absolute;
  top: -25px;
  right: 0;
  z-index: 0;
  text-align: right;
}
/* text-align cannot move it: img is display:block here, so the CTA photograph
   sat hard left in its 850 box wherever it was narrower than the box — IKO's
   459-wide picture was 391px out. Upstream the figure is inline and the
   text-align does the work; here it takes an auto margin. */
.brand-cta-img img { margin-left: auto; }
@media (max-width: 1024px) {
  .brand-cta-img { top: 78px; right: 0; }
  .brand-cta-img img { max-width: 650px; }
}
@media (max-width: 767px) {
  .brand-cta-img { top: -5vw; }
  .brand-cta-img img { max-width: 100%; }
}

/* The reveal wipe that uncovers the CTA image on scroll. */
.block-revealer { position: relative; display: inline-block; }
.block-revealer__element {
  position: absolute;
  inset: 0;
  background-color: var(--c-reveal-wipe);
  transform: scaleX(1);
  transform-origin: left center;
}
/* power4.inOut, driven forward from scaleX(0) — the original grows the panel
   across the image and retracts it, rather than starting covered. */
.block-revealer__element { transform: scaleX(0); transform-origin: 0% 50%; }
.block-revealer.is-revealed .block-revealer__element {
  animation: revealWipe .5s cubic-bezier(0.86, 0, 0.07, 1) forwards;
}
@keyframes revealWipe {
  0%   { transform: scaleX(0); transform-origin: 0% 50%; }
  50%  { transform: scaleX(1); transform-origin: 0% 50%; }
  50.1%{ transform: scaleX(1); transform-origin: 100% 50%; }
  100% { transform: scaleX(0); transform-origin: 100% 50%; }
}

/* --------------------------------------------------------------------------
   8. FOOTER — sticky-footer reveal (upstream data-sticky-footer, shadow:4)
   The content is an opaque sheet at z-index 2 with a soft bottom shadow; the
   footer is fixed at the viewport bottom at z-index 1, so as the page scrolls
   the sheet slides up and uncovers the footer beneath it. site.js sets the
   sheet's bottom margin to the footer height so there is room to reveal it.
   -------------------------------------------------------------------------- */
.site-footer {
  background-color: var(--c-footer-bg);
  color: var(--c-footer-text);
  padding-top: 40px;
}
/* The footer rows are Elementor containers: 1170 of content starting at x=128,
   not the 1140/143 of the Bootstrap ladder that drives the page body. A branch
   cell is therefore 292.5 wide and, with its own 10px padding, gives 272.5 of
   content at x=138 — which is what the reference measures (273), not the 288
   an unpadded 1150-wide row produced. */
@media (min-width: 1200px) { .site-footer .e-container { max-width: 1200px; } }
/* Progressive enhancement: site.js adds `sticky-footer` to <html> once it has
   sized the reveal gap, so no-JS visitors keep a normal in-flow footer. */
.sticky-footer .site-content {
  position: relative;
  z-index: 2;
  background: #fff;
  box-shadow: 0 30px 70px -25px rgba(0, 0, 0, .1);
}
.sticky-footer .site-footer {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1;
}
@media (max-width: 1024px) { .site-footer { padding: 100px 40px; } }
@media (max-width: 767px)  { .site-footer { padding: 60px 20px; } }

.site-footer h2, .site-footer h3, .site-footer h4, .site-footer h5 { color: #fff; }

/* Top row is 60% / 20% / 20% (outer 60/40, inner 50/50) and its bottom padding
   is zero — the branch rows below supply their own. */
/* No padding of its own — .site-footer already supplies the 40px, and having
   both put the whole block 40px too low. */
.footer-top {
  display: grid;
  grid-template-columns: 60% 20% 20%;
  padding: 0;
}
/* The two link columns sit inside a 448-wide block at x=840, i.e. the 40%
   right half inset by 10px on each outer edge. */
@media (min-width: 1025px) {
  .footer-top > :nth-child(2) { padding-left: 10px; }
  .footer-top > :nth-child(3) { padding-right: 10px; }
}
@media (max-width: 1024px) {
  .footer-top { grid-template-columns: 1fr; }
  .footer-top > :nth-child(2) { margin-top: 30px; }
}
@media (max-width: 767px) {
  .footer-top { grid-template-columns: 1fr 1fr; }
  .footer-top > :first-child { grid-column: 1 / -1; }
}

.footer-logo-wrap { text-align: start; padding: 10px; }
.footer-logo { width: 15%; min-width: 90px; margin-bottom: 0; }
.footer-blurb {
  color: var(--c-footer-text);
  font-size: 18px;
  line-height: 28px;
  margin: 10px 7em .5em 0;
}
@media (max-width: 767px) { .footer-blurb { margin: 0; } }

/* Column headings are <h5> at the 11px micro recipe, in solid white.
   Measured upstream: termina (not DM Sans), 11/700/22px/1.35px, uppercase,
   inline-block so the box hugs the label (105px, not the full column), with
   a 33px bottom margin. */
.site-footer .footer-col-head {
  font-family: var(--font-display);
  font-size: 11px;
  font-weight: 700;
  line-height: 22px;
  letter-spacing: 1.35px;
  text-transform: uppercase;
  color: #FFFFFF;
  display: inline-block;
  margin: 0 0 33px;
}

/* State eyebrows (CONNECTICUT etc.) — same recipe, dimmer, no margin.
   inline-block upstream, so the box is the width of the word (94px). */
.footer-eyebrow {
  font-family: var(--font-body);
  font-size: 11px;
  font-weight: 700;
  line-height: 22px;
  letter-spacing: 1.35px;
  text-transform: uppercase;
  color: var(--c-footer-micro);
  /* Each of these is its own widget box upstream. Left inline-block they share
     a line with the "Locations" label above them and print CONNECTICUT beside
     it; the 3px makes the box the 25 the reference measures. */
  display: block;
  margin: 0 0 3px;
}

/* The "Locations" label above the branch grid — 20px, not the branch heading. */
.footer-locations-label {
  font-family: var(--font-body);
  font-size: 20px;
  font-weight: 700;
  line-height: 2em;
  letter-spacing: 1.35px;
  text-transform: uppercase;
  color: #FFFFFF;
  display: block;
  margin: 0;
}

.footer-menu { list-style: none; margin: 0; padding: 0; }
.footer-menu li:not(:last-child) { margin-bottom: 16px; }
.footer-menu a { display: block; font-size: 16px; color: var(--c-footer-menu); }
.footer-menu a:hover { color: #fff; }

/* Two boxed rows of four 25% cells, no gap, no rule. Each cell carries 10px of
   its own padding, so the row's 1170 becomes 273 of content per column. Row 1
   bottom-aligns: its first cell is 40px taller because the "Locations" label
   lives inside it, and all four still end level. */
.footer-branches {
  display: grid;
  grid-template-columns: repeat(4, 25%);
  align-items: flex-end;
  padding: 10px 0;
}
.footer-branches + .footer-branches { padding: 0; }
.branch { padding: 10px; }
@media (max-width: 1024px) { .footer-branches { grid-template-columns: repeat(2, 50%); } }
@media (max-width: 560px)  { .footer-branches { grid-template-columns: 100%; } }

/* The footer branch name is NOT a display heading upstream — every SplitText
   shard of it computes DM Sans 16px/400 on a 24.96px line in solid white,
   i.e. plain body type, and it wraps to two lines inside the column (measured
   273×68). The termina 15px one-liner here was an invention that had to be
   shrunk to fit; at the real size and family it simply wraps, as it does live. */
.branch h2 {
  font-family: var(--font-body);
  font-size: 16px;
  font-weight: 400;
  line-height: 1.56em;
  letter-spacing: normal;
  word-spacing: normal;
  text-transform: none;
  color: #fff;
  /* The name block is 68 tall upstream around a single 25px line: SplitText
     leaves the inter-word spaces at the H2's own termina 40px/48px while the
     characters render at body size, so the line box is inflated and the text
     sits 21px down. Reproduced as padding rather than as a 48px line-height,
     which would put the glyphs 8px high. */
  padding-top: 21px;
  margin: 0 0 22px;
  overflow-wrap: break-word;
}
.branch address {
  font-style: normal;
  color: #FFFFFF;
  line-height: 1.56em;
  margin: 0 0 24px;
}
/* The original published all 17 branch numbers as plain, un-tappable text. */
.branch a { color: var(--c-footer-menu); }
.branch a:hover { color: #fff; }

.footer-bottom {
  padding: 10px 0 34px;
  color: #FFFFFF;
}
.footer-bottom p { margin: 0; }
.footer-bottom img { display: inline-block; vertical-align: middle; }

/* --------------------------------------------------------------------------
   9. SCROLL ANIMATION
   Recipes A–F on the original are GSAP + ScrollTrigger with power4.out. These
   reproduce the same motion with the Web Animations timing model — no library.
   -------------------------------------------------------------------------- */
/* Theme defaults from theme.min.js (liquidCustomAnimations):
   duration 1600ms, stagger 160ms, ease power4.out. */
[data-anim] {
  opacity: 0;
  transform: translate3d(var(--anim-x, 0), var(--anim-y, 35px), 0);
  transition: opacity 1.6s var(--ease-signature),
              transform 1.6s var(--ease-signature);
  transition-delay: var(--anim-delay, 0ms);
}
[data-anim].is-inview { opacity: 1; transform: none; }

/* A — home hero split-line layer (the only recipe with both axes) */
[data-anim="hero-line"]     { --anim-x: 30px; --anim-y: 30px; }
/* SR7 — the two homepage slider layers. Not one of the six GSAP recipes:
   Slider Revolution runs its own in-timeline, a plain opacity 0→1 over 300ms
   on power3.inOut, with no offset. */
[data-anim="sr7-fade"] {
  --anim-x: 0; --anim-y: 0;
  transition-duration: .3s;
  transition-timing-function: cubic-bezier(.65, 0, .35, 1);
}
/* B — section columns, diagonal */
[data-anim="stagger-diag"]  { --anim-x: 30px; --anim-y: 60px; }
/* C — footer and true column reveals */
[data-anim="stagger-up"]    { --anim-x: 0; --anim-y: 30px; }
/* D — widget groups (brand hero copy). Slower: 1800ms, 180ms step. */
[data-anim="widget-slow"]   { --anim-x: 0; --anim-y: 35px;
  transition-duration: 1.8s; }
/* E — brand CTA column, X-only */
[data-anim="stagger-right"] { --anim-x: 30px; --anim-y: 0; }
/* F — Get-a-Quote column */
[data-anim="stagger-y40"]   { --anim-x: 0; --anim-y: 40px; }

/* Brand-page headings init Y-only upstream; the shared hero-line recipe was
   adding an X offset and sliding them in diagonally. */
.brand-hero [data-anim="hero-line"] { --anim-x: 0; --anim-y: 35px; }

.parallax-wrap { overflow: hidden; }
.parallax-img { will-change: transform; }

@media (prefers-reduced-motion: reduce) {
  [data-anim] { opacity: 1 !important; transform: none !important; transition: none !important; }
  .parallax-img { transform: none !important; }
  .block-revealer__element { display: none; }
  * { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* Reproduces Liquid's SplitText for the footer branch names — see split_chars
   in build.pl. Each word is an inline-flex box and each glyph a flex item, so
   kerning and subpixel advances stop carrying across and the line sets to the
   same width the original does. */
.split-word { display: inline-flex; }
.split-char { display: block; }
/* The word gap is a space set in the heading face at 40px — 11.09px, not the
   4.34px a 16px DM Sans space gives. line-height:0 keeps it out of the line box. */
.split-gap { font-family: var(--font-display); font-size: 40px; line-height: 0; }
