/* Hand-written rules for classes THIS BUILD invents (tools/build-pages.py, runtime.js).
 * Kept OUTSIDE site/public/styles/, which port-css wipes on every run (gotcha 49).
 * Every selector repeats its class behind #dm on purpose: Duda emits
 * `#dm .dmBody div.u_<id>{display:block!important}` for every widget, (1,2,1), and a plain
 * class at (0,1,0) loses that fight silently (gotcha 70).
 * Censused on this site 2026-09-29 (31 pages x 3 bands); nothing here names another site.
 */

/* Honeypot host — off-screen, costs no layout. NO SUBJECT HERE: this site has no form
 * (0 in 93 served documents and 93 post-JS captures); kept because it is inert. */
.mg-hp {
  position: absolute !important;
  left: -9999px !important;
  top: auto !important;
  width: 1px !important;
  height: 1px !important;
  overflow: hidden !important;
}

/* Blog cards the builder appends hidden for a local pager. NO SUBJECT HERE: every blog
 * list declares a total at or below its visible-items, so nothing is appended. */
#dm .mg-blog-hidden.mg-blog-hidden.mg-blog-hidden {
  display: none !important;
}
#dm .postArticle:not(.mg-blog-hidden):has(+ .postArticle.mg-blog-hidden) {
  padding-bottom: 0 !important;
}

/* Band gates: the content forks THREE ways here (desktop == tablet 0 of 31, desktop ==
 * mobile 0 of 31), so each band's copy ships and the two inactive ones are hidden. */
@media (max-width: 767px) {
  #dm .mg-only-d.mg-only-d.mg-only-d,
  #dm .mg-only-t.mg-only-t.mg-only-t {
    display: none !important;
  }
}
@media (min-width: 768px) and (max-width: 1024px) {
  #dm .mg-only-d.mg-only-d.mg-only-d,
  #dm .mg-only-m.mg-only-m.mg-only-m {
    display: none !important;
  }
}
@media (min-width: 1025px) {
  #dm .mg-only-t.mg-only-t.mg-only-t,
  #dm .mg-only-m.mg-only-m.mg-only-m {
    display: none !important;
  }
}

/* Accordion panel opened by runtime.js on click (15 widgets on 15 pages; none opens on
 * its own — generated/accordion-reveal.json, 0 of 15 auto-open on live). */
#dm .mg-acc-open.mg-acc-open.mg-acc-open {
  max-height: 2000px;
}


/* ---- Pre-launch review 2026-10-03 ------------------------------------------ */

/* Tablet/phone drawer sub-menus ("About Us", "Services", "Service Areas"). runtime.js drawer()
 * opens and closes each from its label or caret; closed is the class gy-sub-closed.
 * The closed state collapses height, padding, border and opacity together (max-height
 * alone clips only the content box), takes the panel out of the tab order, and is
 * !important at doubled id specificity so it outranks the ported cascade's own :hover
 * opener, which a tap leaves stuck on a touch screen and which would otherwise keep a
 * closed group open. */
#hamburger-drawer#hamburger-drawer li.gy-sub > .unifiednav__container_sub-nav {
  overflow: hidden;
  transition: max-height .3s ease, opacity .2s ease;
}
#hamburger-drawer#hamburger-drawer li.gy-sub.gy-sub-closed > .unifiednav__container_sub-nav {
  max-height: 0 !important;
  padding-top: 0 !important;
  padding-bottom: 0 !important;
  margin-top: 0 !important;
  margin-bottom: 0 !important;
  border-width: 0 !important;
  opacity: 0 !important;
  pointer-events: none !important;
  visibility: hidden;
}
/* Closed, the caret points down whatever :hover says. */
#hamburger-drawer#hamburger-drawer li.gy-sub.gy-sub-closed > a .icon::before {
  transform: none !important;
}
#hamburger-drawer .hamburgerButton {
  position: relative;
  z-index: 5;
}
/* The close (X) follows the panel's scroll (runtime.js drawer()). Its row and the
 * menu's row are both transformed, so each is its own stacking context and the
 * later one — the menu — painted over the X once an open group scrolled up under
 * it. The X's row goes above the menu's. */
#hamburger-drawer div:has(.hamburgerButton) {
  z-index: 5;
}

/* Legal pages (tools/build-legal-pages.mjs). Duda's reset zeroes margin on p, ul
 * and h2, so the template text would otherwise render as one slab with every
 * heading pressed against the paragraph above it. */
#dm .gy-legal-row {
  max-width: 1200px;
  margin: 0 auto;
  padding: 60px 40px 80px;
  box-sizing: border-box;
}
#dm .gy-legal-row h2 {
  margin: 36px 0 12px;
}
#dm .gy-legal-row p,
#dm .gy-legal-row li {
  line-height: 1.6;
}
#dm .gy-legal-row p {
  margin: 0 0 14px;
}
#dm .gy-legal-row ul {
  margin: 0 0 14px;
  padding-left: 1.4em;
  list-style: disc;
}
#dm .gy-legal-row li {
  margin: 0 0 4px;
}
#dm .gy-legal-row a {
  text-decoration: underline;
}
@media (max-width: 767px) {
  #dm .gy-legal-row {
    padding: 32px 15px 60px;
  }
}

/* "Privacy Policy | Terms & Conditions" under the footer copyright and under the
 * /contact-us form's Send button (tools/build-legal-pages.mjs): the links keep the
 * ink of the line they sit on, whatever the page's own link colour is. */
#dm#dm .gy-legal-links a {
  color: inherit !important;
  text-decoration: underline !important;
  font-weight: inherit !important;
}

/* Accordion arrow (review 2026-10-03). Duda's runtime swaps the arrow <svg>'s
 * styled-components class when an item opens, turning it 180deg over 0.5s ease-in-out
 * (measured on live, /drain-stoppages-jarrell-tx at 1440). The port opens the panel
 * with mg-acc-open but never touched the arrow, so it pointed down on an open item. */
#dm [data-grab="accordion-item-arrow"] svg {
  transition: transform .5s ease-in-out;
}
#dm [data-grab="accordion-item-container"]:has(.mg-acc-open) [data-grab="accordion-item-arrow"] svg {
  transform: rotate(180deg);
}

/* The 404 page (review 2026-10-03). Duda styles its "4 04" block from a platform
 * sheet that is not part of the port, so the page shipped as four lines of unstyled
 * text pressed against the left edge. Live's measured look (1440), restated: 120px
 * above, centred on white, a 130px Oswald "4 04" with the first 4 leaning 15deg, a 22px
 * line with 45px around it, and a 184x37 grey button.
 * AND THE HEADER: on /404 and /blog-search (no hero photo behind it) the header is
 * transparent over a white page, so its white "Proudly Serving / Email Us / Call Us at"
 * lines are invisible — on live too. It takes the footer's own dark, rgb(45,46,50). */
body[data-page-alias="dmPageNotFound"] #flex-header,
body[data-page-alias="blog-search"] #flex-header {
  background-color: rgb(45, 46, 50) !important;
}
#dm #error-container {
  padding: 120px 0 0;
  text-align: center;
  background-color: rgb(255, 255, 255);
}
#dm #error-container .four-o-four {
  font-family: Oswald, sans-serif;
  font-size: 130px;
  line-height: normal;
  color: rgb(45, 46, 50);
}
#dm #error-container .four-o-four .lean {
  display: inline-block;
  transform: rotate(15deg);
}
#dm #error-container .description {
  font-family: Inter, "Inter Fallback", sans-serif;
  margin: 45px 0;
  font-size: 22px;
  line-height: normal;
  color: rgb(45, 46, 50);
}
#dm #error-container a.back-button {
  display: inline-block;
  box-sizing: border-box;
  min-width: 184px;
  height: 37px;
  margin: 0 0 20px;
  padding: 0 20px;
  border-radius: 2px;
  background-color: rgb(137, 137, 137);
  color: rgb(255, 255, 255) !important;
  font-size: 16px;
  line-height: 37px;
  text-decoration: none !important;
}
#dm #error-container a.back-button:hover,
#dm #error-container a.back-button:focus-visible {
  background-color: rgb(45, 46, 50);
}

/* Headings retagged by tools/review-fixes.py (review 2026-10-03), each held at the type
 * it had, measured before and after at 1440 / 768 / 390.
 * - Blog post titles: the data-binding "blog.title" <div> now holds an <h1 class="gy-h1">,
 *   which inherits everything from the div (Anton 50/49.5px desktop, the post's green).
 * - /blog "Blog" (was a <p>) and /blog-search "Search Results" (was an <h2>): the type
 *   lives on their inner <span>s; the <h1> itself only has to stop adding the site's h1
 *   rule (Anton 45px, green, 0.01em) underneath them.
 * - The demoted second <h1> on /backflow-testing-jarrell-tx, /plumbing-tunneling-
 *   services-jarrell-tx and /projects keeps the h1 type: Anton 45px / 1.1, green,
 *   0.01em (sizes per band below, as the site's h1 rule gives them). */
#dm#dm [data-binding] > h1.gy-h1 {
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  text-align: inherit;
  margin: 0;
  padding: 0;
}
#dm#dm .dmNewParagraph h1.gy-h1:not([data-binding] > *) {
  color: rgb(45, 46, 50);
  margin: 0;
  padding: 0;
}
/* /blog: the <p> it was used Inter on the line box (the span carries Anton). */
#dm#dm .dmNewParagraph[id="1785100321"] h1.gy-h1 {
  font-family: Inter, "Inter Fallback", sans-serif;
}
/* /blog-search: "Search Results" keeps the h2 metrics (32 / 30 / 26px, normal). */
#dm#dm .dmNewParagraph h1.gy-h1:has(> span:only-child) {
  line-height: normal;
  letter-spacing: normal;
}
body[data-page-alias="blog-search"] #dm#dm .dmNewParagraph h1.gy-h1 { font-size: 32px; }
@media (min-width: 768px) and (max-width: 1024px) {
  body[data-page-alias="blog-search"] #dm#dm .dmNewParagraph h1.gy-h1,
  body[data-page-alias="blog-search"] #dm#dm .dmNewParagraph h1.gy-h1 span { font-size: 30px !important; }
}
@media (max-width: 767px) {
  body[data-page-alias="blog-search"] #dm#dm .dmNewParagraph h1.gy-h1 { font-size: 26px; }
}
#dm#dm .dmNewParagraph h2.gy-was-h1,
#dm#dm .dmNewParagraph h2.gy-was-h1 span {
  font-family: Anton, "Anton Fallback", sans-serif;
  font-weight: 400;
  font-size: 45px;
  line-height: 1.1;
  letter-spacing: 0.01em;
  color: rgb(88, 104, 76);
}
@media (min-width: 768px) and (max-width: 1024px) {
  #dm#dm .dmNewParagraph h2.gy-was-h1,
  #dm#dm .dmNewParagraph h2.gy-was-h1 span { font-size: 50px; line-height: normal; }
}
@media (max-width: 767px) {
  #dm#dm .dmNewParagraph h2.gy-was-h1,
  #dm#dm .dmNewParagraph h2.gy-was-h1 span { font-size: 34px; line-height: normal; }
}

/* /projects call to action (tools/review-fixes.py): the site's own outlined button_2
 * restated as measured on /drain-stoppages-jarrell-tx — 238x52, 2px rgb(88,104,76)
 * border, 5px radius, Inter 700 16px (15px on phones) in rgb(107,124,91); on hover a
 * rgb(88,104,76) fill with white text, 0.2s. Centred under the gallery. */
#dm .gy-cta-wrap {
  display: flex;
  justify-content: center;
  width: 100%;
  margin: 40px 0 0;
  order: 9999;
}
#dm#dm a.gy-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  width: 238px;
  height: 52px;
  padding: 10px 0;
  border: 2px solid rgb(88, 104, 76);
  border-radius: 5px;
  background-color: transparent;
  color: rgb(107, 124, 91);
  font-family: Inter, "Inter Fallback", sans-serif;
  font-size: 16px;
  font-weight: 700;
  line-height: normal;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color .2s, border-color .2s, color .2s;
}
#dm#dm a.gy-cta:hover,
#dm#dm a.gy-cta:focus-visible {
  background-color: rgb(88, 104, 76);
  color: rgb(255, 255, 255);
}
@media (max-width: 767px) {
  #dm#dm a.gy-cta { font-size: 15px; }
}

/* /contact-us Jobber request form (review 2026-10-03). runtime.js sizes the iframe to
 * the height Jobber's frame reports; its Duda wrapper carries a fixed 1588px, which
 * would keep the blank space under the form whatever the iframe did. The wrapper
 * follows the iframe (which keeps its captured 1588px until Jobber reports). */
#dm#dm [id="widget_36g"],
#dm#dm [id="widget_36g"] > .dmCustomHtml {
  height: auto;
}
#dm iframe.jobber-work-request {
  display: block;
}
