/* The ONLY hand-written stylesheet in this build.
 *
 * Everything else under /styles is Duda's own cascade, ported verbatim from what
 * the live documents actually load, with nothing but url() rewritten. This file
 * exists for the things that cannot come from there: the device gating a
 * single-document build needs, the touch parallax behaviour Duda's RUNTIME (not
 * its CSS) applies, and the honeypot that replaces reCAPTCHA.
 *
 * The breakpoints below are Duda's own, read out of its runtime package, and they
 * MUST stay identical to the ones tools/port-css.mjs media-gates the ported sheets
 * with — if the two disagree there is a width where a device's markup is visible
 * with another device's stylesheet.
 *
 *     mobile   (max-width: 767px)
 *     tablet   (min-width: 768px) and (max-width: 1024px)
 *     desktop  (min-width: 1025px)
 */

/* ------------------------------------------------------------- device gating
 * This build serves ONE document; live serves three. Both headers and the mobile
 * drawer are therefore always in the markup and the wrong one is hidden per band.
 * Measured from the captures: the desktop document has .dmHeaderContainer and
 * .dmPageTitleRow and NO drawer/overlay/back-to-top; the mobile document has
 * #hamburger-header-container, #mobile-hamburger-drawer, .layout-drawer-overlay
 * and #dmBackToTop and neither of the first two. Tablet is desktop. */
@media (max-width: 767px) {
  #dmRoot #dm .dmHeaderContainer,
  #dmRoot #dm .dmRespRow.dmPageTitleRow {
    display: none !important;
  }
}

@media (min-width: 768px) {
  #dmRoot #dm #hamburger-header-container,
  #dmRoot #dm #layout-drawer-hamburger,
  #dmRoot #dm #mobile-hamburger-drawer,
  #dmRoot #dm .layout-drawer-overlay,
  #dmRoot #dm #dmBackToTop {
    display: none !important;
  }
}

/* ------------------------------------------------------------ touch parallax
 * PARALLAX IS FROZEN ON TOUCH BY DUDA'S RUNTIME, NOT BY ITS CSS (gotcha 22). The
 * ported sheets declare `background-attachment: fixed !important` for these
 * sections at every width, and on desktop that is what live computes. But
 * measured on live, the TABLET and MOBILE documents compute
 * `background-attachment: scroll` — Duda's runtime overrides it for touch, and no
 * stylesheet records that. A faithful CSS-only port therefore keeps `fixed` below
 * 1025px and renders the hero at roughly 3x zoom in a full-page capture.
 *
 * Measured background-position at rest, per band, on / :
 *     desktop  50% -6.02125px at viewport height 900   (skrollr, see runtime.js)
 *     tablet   0% 0%
 *     mobile   50% 50%
 *
 * SPECIFICITY IS LOAD-BEARING. Duda targets these as `#dm .dmBody div.u_<id>`,
 * so a `[class*=...]` selector loses outright. `#dmRoot #dm .dmBody div[data-center]`
 * matches that weight and adds one id, and the attribute selector is what keeps
 * this scoped to the parallax sections themselves. Duda also ships TWO spellings
 * of the same idea — dmSectionParallaxNew and dmSectionParallex — so both are
 * matched. */
@media (max-width: 1024px) {
  #dmRoot #dm .dmBody div[data-center],
  #dmRoot #dm .dmBody div.dmSectionParallaxNew,
  #dmRoot #dm .dmBody div.dmSectionParallex {
    background-attachment: scroll !important;
  }
}

@media (min-width: 768px) and (max-width: 1024px) {
  #dmRoot #dm .dmBody div[data-center],
  #dmRoot #dm .dmBody div.dmSectionParallaxNew,
  #dmRoot #dm .dmBody div.dmSectionParallex {
    background-position: 0% 0% !important;
  }
}

@media (max-width: 767px) {
  #dmRoot #dm .dmBody div[data-center],
  #dmRoot #dm .dmBody div.dmSectionParallaxNew,
  #dmRoot #dm .dmBody div.dmSectionParallex {
    background-position: 50% 50% !important;
  }
}

/* --------------------------------------------------------- per-device widgets
 * .dmPhotoGallery builds its own DOM client-side and the three documents
 * genuinely disagree about STRUCTURE, not just image renditions — /gallery has 56
 * references on desktop against 9 on tablet, and a different column count and
 * caption placement. All present variants are emitted and gated here.
 *
 * .mainBlog does NOT fork structurally on this site (verified: identical element
 * counts across all three documents, and no .postTextContainer anywhere), but its
 * cards name a DIFFERENT CROP per device through an inline background — 1920w
 * desktop, 1280w tablet — which is invisible to srcset (gotcha 16), so it is
 * emitted per device for that reason alone.
 *
 * The class sits on the widget element ITSELF rather than on a wrapper, so no
 * descendant relationship the widget's own CSS relies on is disturbed.
 *
 * display:none rather than visibility:hidden is deliberate: these variants have
 * different heights, and a hidden-but-laid-out copy would add its own height.
 *
 * Only the INACTIVE bands are touched. Forcing the active one to display:block
 * would silently restyle a widget Duda gives display:flex.
 *
 * The selector is DOUBLED to raise specificity. Duda ships
 *   body.dmRoot #dm [list-layout="layout4"] { display: flex !important }
 * at (1,2,1); a plain `.mg-only-t{display:none!important}` is (0,1,0) and LOSES
 * even with !important. `.mg-only-t.mg-only-t` inside `body.dmRoot #dm` is (1,3,1)
 * and wins outright rather than relying on a source-order tiebreak. */
@media (min-width: 1025px) {
  body.dmRoot #dm .mg-only-t.mg-only-t,
  body.dmRoot #dm .mg-only-m.mg-only-m { display: none !important; }
}
@media (min-width: 768px) and (max-width: 1024px) {
  body.dmRoot #dm .mg-only-d.mg-only-d,
  body.dmRoot #dm .mg-only-m.mg-only-m { display: none !important; }
}
@media (max-width: 767px) {
  body.dmRoot #dm .mg-only-d.mg-only-d,
  body.dmRoot #dm .mg-only-t.mg-only-t { display: none !important; }
}

/* --------------------------------------------------------------- honeypot
 * Duda sites rely on reCAPTCHA for spam protection and we remove that widget
 * (its keys are Duda's own and domain-restricted, so they cannot work here), so
 * without this every migrated form would ship with none at all.
 *
 * Off-screen rather than display:none: bots skip obviously-hidden fields. Taken
 * out of flow so it costs no layout — the pixel gate would otherwise measure it.
 * The field is named `company`, which cannot collide because Duda names every
 * real field dmform-N. */
.mg-hp {
  position: absolute !important;
  left: -9999px !important;
  top: auto !important;
  width: 1px !important;
  height: 1px !important;
  overflow: hidden !important;
  opacity: 0 !important;
  pointer-events: none !important;
}

/* ------------------------------------------------------------ blog "Show More"
 * /blog publishes 10 of this site's 11 posts and a "Show More" control that asks
 * Duda's backend for the next page. A static build has no backend, so all 11
 * cards ship and the 11th starts hidden; runtime.js reveals it on the same click
 * live uses and then removes the control, which is live's own end state.
 * display:none rather than visibility:hidden — a laid-out card would add its
 * height, and the initial render has to stay identical to live's un-clicked
 * state, which is what the pixel gate measures. */
.mg-blog-hidden {
  display: none !important;
}

/* The card that is last AMONG THE VISIBLE ONES. Duda spaces cards with
 *   [list-layout=recent_posts][posts-padding="15"] .postArticle:not(:last-child)
 *       { padding-bottom: 30px }
 * and `display:none` does NOT release :last-child — so appending a hidden 11th
 * card made the 10th match :not(:last-child) and grow 30px, pushing the footer
 * down on every width. This restores live's geometry for the last visible card;
 * runtime.js moves the class as cards are revealed and removes it once none are
 * hidden, at which point the real :last-child does the job again.
 *
 * Specificity has to beat #dm[attr][attr][attr] .postArticle:not(:last-child),
 * hence the two ids plus !important. */
#dmRoot #dm .postArticle.mg-last-visible {
  padding-bottom: 0 !important;
}

/* --------------------------------------------- H1 demotion, /service-areas/…-colorado
 * REVIEW FIX 2026-08-26. Live publishes THREE <h1> on
 * /service-areas/asphalt-paving-contractor-colorado — the page title plus two
 * mid-page section headings. Its two sibling service-area pages (Louisiana,
 * Colorado Springs) each publish one <h1> and use <h2> for exactly these
 * section headings, so the pattern being deviated from is the site's own.
 * Reproducing it 1:1 would carry a live SEO defect into the new build, so the
 * two extra headings are now <h2 class="gy-h1-demoted">.
 *
 * ONE of them needs this rule and the other does not. The second heading already
 * carried Duda's own `size-30 m-size-24` utilities, which pin 30px/24px with
 * !important — identical to what an h2 computes to here, so its demotion is
 * pixel-identical and it gets no rule.
 *
 * The third heading carried NO size utility and inherited the h1 defaults
 * (measured on the built page: 40px desktop/tablet, 30px mobile). As an h2 it
 * would drop to 30px/24px — a visible change on a 1:1 port. Duda's `.size-40`
 * and `.m-size-30` utilities cannot be used to restore it: Duda emits only the
 * utilities a page actually references, and neither this page's mobile sheet
 * (9d2c21348a4a4b5c.css) nor its desktop/tablet sheet (fc206bf771e26337.css)
 * contains `.size-40`. Verified by grep, then by measuring the built page.
 *
 * Bands are this file's own, matching the device gating above. Specificity has
 * to beat `#dm div.dmContent h2 {font-size:30px}` at (1,1,2); two ids plus a
 * class is (2,1,0) and wins outright rather than on source order. */
@media (min-width: 768px) {
  #dmRoot #dm .gy-size-40 { font-size: 40px !important; }
}
@media (max-width: 767px) {
  #dmRoot #dm .gy-size-40 { font-size: 30px !important; }
}

/* ------------------------------------------------------------- footer GBP map
 * REVIEW ADDITION 2026-08-26. Neither live nor the port had a Google Business
 * Profile map in the FOOTER — live embeds one on /contact-us and on
 * /service-areas/asphalt-paving-contractor-colorado only, so it was absent from
 * 22 of 24 pages.
 *
 * The embed URL is NOT generated: it is the client's own published GBP embed,
 * lifted verbatim from the iframe live already serves on /contact-us (place id
 * 0x876c996076aa47e7:0x6bea208c37c5a73f, "Harris Asphalt Paving, LLC"). Nothing
 * about the place was guessed.
 *
 * The row is a real Duda .dmRespRow / .dmRespColsWrapper / .dmRespCol large-12
 * so it inherits the footer's own full-width column behaviour rather than
 * needing a parallel layout, and it is marked `gy-added` — see the repo
 * convention — so a later re-port can find every hand-inserted element.
 *
 * Height is capped at 300px per the review checklist. The cap is enforced on the
 * WRAPPER as well as the iframe's own height attribute, because the attribute
 * alone loses to any stylesheet that sizes iframes by percentage. */
#dmRoot #dm .gy-footer-map {
  width: 100%;
  clear: both;
  /* 20px above separates the map from the Google-review badge that sits directly
     over it; 18px below keeps it off the copyright line. */
  margin: 20px 0 18px;
}
#dmRoot #dm .gy-footer-map .gy-footer-map__frame {
  width: 100%;
  max-width: 100%;
  max-height: 300px;
  overflow: hidden;
  line-height: 0;
}
#dmRoot #dm .gy-footer-map .gy-footer-map__frame iframe {
  display: block;
  width: 100%;
  height: 300px;
  max-height: 300px;
  border: 0;
}

/* ------------------------------------------------- legal links under the form
 * REVIEW ADDITION 2026-08-26. The review checklist wants Privacy Policy and
 * Terms & Conditions linked in the footer AND on the contact form, after all of
 * its fields. The footer nav carries them as two more `unifiednav__item-wrap`
 * entries, which need no styling because they inherit the nav's own; this rule
 * is only for the pair that sits under the form's submit button.
 *
 * COLOUR IS EXPLICIT, NOT INHERITED. `color: inherit` was tried first and the
 * links rendered rgb(43,43,43) — near-black on the row's own rgb(43,43,43)
 * background, i.e. invisible. Caught by screenshotting the footer rather than by
 * the DOM assertion, which reported them present, visible and non-zero-size and
 * was completely correct while the user could not see them.
 *
 * #fff is the form's OWN label colour on this row (`.dmform label` computes
 * rgb(255,255,255)), so the pair matches the fields they sit under. */
#dmRoot #dm .gy-form-legal {
  margin: 14px 0 0;
  clear: both;
  text-align: center;
  font-size: 13px;
  line-height: 1.6;
  color: #fff;
}
#dmRoot #dm .gy-form-legal a {
  color: #fff;
  text-decoration: underline;
}
#dmRoot #dm .gy-form-legal a:hover,
#dmRoot #dm .gy-form-legal a:focus {
  text-decoration: none;
}

/* ------------------------------------------------------ review-added interlink
 * REVIEW ADDITION 2026-08-26. The checklist wants the business name linked to the
 * homepage once per page where it appears in the copy, with interlink styling
 * (underline) on BODY TEXT ONLY — never headings, buttons, or header/footer.
 *
 * Scoping is what enforces that: the rule is anchored to `#dm_content p`, so the
 * class cannot pick up interlink styling if it ever ends up in a heading, in the
 * footer, or on a button. Colour is inherited so the link reads correctly on the
 * dark section backgrounds as well as the white ones.
 *
 * NOT applied on /testimonials: the only three mentions of the business name on
 * that page sit inside customer review quotes, and turning a reviewer's words
 * into a site link edits their testimonial. Left unlinked deliberately. */
#dmRoot #dm #dm_content p a.gy-home-link {
  color: inherit;
  text-decoration: underline;
  font-weight: inherit;
}
#dmRoot #dm #dm_content p a.gy-home-link:hover,
#dmRoot #dm #dm_content p a.gy-home-link:focus {
  text-decoration: none;
}

/* --------------------------------------------------------- review-added CTA row
 * /blog and /asphalt-sealcoating-castle-rock-protect-your-pavement-now were the
 * only two pages on the site with no call to action of any kind — no button, no
 * tel: link, no /contact-us link in the page body. Every other page already has
 * at least one. The button reuses Duda's own dmButtonLink classes and the same
 * "CONTACT US" wording the FAQ page already uses, so nothing new is introduced
 * visually. */
#dmRoot #dm .gy-page-cta {
  display: block;
  width: 100%;
  clear: both;
  margin: 24px 0 8px;
  text-align: center;
}

/* --------------------------------------------------------------- lightbox fix
 * REVIEW FIX 2026-08-26. Two layout faults in the ported PhotoSwipe overlay,
 * both invisible to any DOM assertion and both obvious in a screenshot.
 *
 * 1. POSITION. PhotoSwipe's base rule is `.pswp { position: absolute }` and its
 *    own JS promotes the root to `fixed` when it opens (measured on live with
 *    the overlay open: `position: fixed`). Nothing in this build did that, so an
 *    overlay opened after scrolling anchored to the DOCUMENT top — it painted a
 *    partial black box over the top of the page with the gallery still visible
 *    below it, instead of covering the viewport.
 *
 * 2. IMAGE PLACEMENT. `.pswp__img` is `position:absolute; top:0; left:0` in
 *    PhotoSwipe's CSS because its own JS measures and transforms every slide.
 *    This build sets a plain `src` instead, so the photo sat hard against the
 *    top-left corner. The injected item is a centring flex box and its image is
 *    taken out of absolute flow — scoped to `.gy-pswp-*` so the three original
 *    `.pswp__item` placeholders in the ported markup are left alone. */
#dmRoot .pswp.pswp--open {
  position: fixed;
}
#dmRoot .pswp .gy-pswp-item {
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  /* Top/bottom clears the 44px UI bar and the caption; the side inset clears the
   * 70px arrow hit areas so a wide photo does not sit under them. */
  padding: 52px 70px;
}

/* On a phone, reserving 140px of a 375px viewport for the arrows left the photo
 * at 235px wide — smaller than the thumbnail that opened it. Phones get the
 * arrows overlaying the image edges instead, which is what every touch lightbox
 * does, and the photo gets the width back. */
@media (max-width: 767px) {
  #dmRoot .pswp .gy-pswp-item { padding: 52px 8px; }
}
#dmRoot .pswp .gy-pswp-img {
  position: static;
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
}


/* ------------------------------------------------- legal links on the copyright
 * REVIEW CHANGE 2026-08-26, on the client's instruction: the two legal links
 * moved OUT of the footer navigation and onto the copyright line, and the GBP
 * map moved down to sit directly above that line.
 *
 * `.copyright` is Duda's own flex row (© / year / "All Rights Reserved."), so a
 * third child joins that line rather than starting a new one; `flex-wrap` on the
 * parent is what lets it drop cleanly to a second line on a phone instead of
 * squashing the sentence. The separator between the two links is decorative and
 * carries aria-hidden, so a screen reader reads two links and not a stray dot. */
#dmRoot #dm .widget-1f5975 .copyright {
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0 6px;
}
#dmRoot #dm .gy-copyright-legal {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
}
#dmRoot #dm .gy-copyright-legal a {
  color: inherit;
  text-decoration: underline;
}
#dmRoot #dm .gy-copyright-legal a:hover,
#dmRoot #dm .gy-copyright-legal a:focus {
  text-decoration: none;
}
