
/* ONE reading measure, as a rem token. `ch` resolves against each element's own
   font-size, so writing 74ch on .phead, .wp and .wp-note produced three different
   widths and three different left edges -- the body column started ~235px right of
   the H1 introducing it. 34rem = 544px = ~75 characters. Do NOT move this into
   build_k.tokens(): audit() parses every LIGHT/DARK value as a hex triplet. */
:root{--measure:34rem}
.wp{max-width:var(--measure);margin-inline:auto;font-size:1.0625rem;line-height:1.72;
  color:var(--ink);overflow-wrap:break-word}
.wp h1{font-size:clamp(1.6rem,3.6vw,2.4rem);line-height:1.15;margin:2.4rem 0 .8rem;color:var(--ink)}
.wp h2{font-size:clamp(1.4rem,3vw,2rem);line-height:1.2;margin:2.4rem 0 .8rem;color:var(--ink)}
.wp h3{font-size:clamp(1.15rem,2.2vw,1.4rem);margin:1.8rem 0 .6rem;color:var(--ink)}
/* h2->h3 is the only heading adjacency in the build; margins collapse to the larger
   value, so a subheading sat further from its parent than body text does. */
.wp h2 + h3{margin-top:1rem}
.wp h4,.wp h5,.wp h6{margin:1.4rem 0 .5rem;color:var(--ink)}
.wp p{margin:0 0 1.05rem}
.wp a{color:var(--brand);text-underline-offset:2px}
.wp ul,.wp ol{margin:0 0 1.15rem 1.25rem;padding:0}
.wp li{margin:.35rem 0}
.wp img{max-width:100%;height:auto;border-radius:14px;display:block;margin:1.4rem 0}
.wp figure{margin:1.6rem 0}
.wp figcaption{font-size:.85rem;color:var(--ink_soft);margin-top:.5rem}
/* Scoped to the BLOCK class on purpose. The paid LP is the only page with
   inline-styled blockquotes; an unscoped rule would paint a card whose inline
   padding survives, putting text against the right edge. */
.wp blockquote.wp-block-quote{margin:1.8rem 0;padding:1.15rem;background:var(--bg_alt);
  border:1px solid var(--rule);border-left:3px solid var(--cta);border-radius:10px;
  color:var(--ink);font-style:normal}
.wp blockquote.wp-block-quote p{margin:0 0 .8rem;font-size:.95rem;line-height:1.55}
.wp blockquote cite{display:block;font-style:normal;font-size:.8rem;
  color:var(--ink_soft);font-weight:600}
.wp table{width:100%;border-collapse:collapse;margin:1.5rem 0;font-size:.94rem}
/* Core parity only. A min-width floor would put the six 2-column tables that
   already fit into permanent horizontal scroll. */
.wp figure.wp-block-table{overflow-x:auto}
.wp table.has-fixed-layout{table-layout:fixed}
.wp th,.wp td{border:1px solid var(--rule);padding:.6rem .7rem;text-align:left}
.wp th{background:var(--bg_alt);font-weight:700}
.wp hr{border:0;border-top:1px solid var(--rule);margin:2.2rem 0}
.wp code,.wp pre{background:var(--bg_alt);border-radius:6px;padding:.1rem .35rem;font-size:.92em}
.wp .wp-block-buttons,.wp .wp-block-button{margin:1.4rem 0}
.wp .wp-block-button__link{display:inline-block;background:var(--cta);color:var(--cta_ink);
  padding:.8rem 1.4rem;border-radius:999px;font-weight:700;text-decoration:none}
.wp-note{max-width:var(--measure);margin:0 auto 1.6rem;padding:.7rem .9rem;
  border:1px dashed var(--rule);border-radius:10px;color:var(--ink_soft);font-size:.86rem}
/* The full-bleed border-bottom goes with the max-width: it used to overhang the
   body column by ~235px each side and read as a stray rule. */
.phead{max-width:var(--measure);margin:0 auto 2.4rem;padding:3.2rem 0 1.2rem;
  border-bottom:1px solid var(--rule)}
.phead .eyebrow{font-size:.78rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--brand);font-weight:700;margin:0 0 .6rem}
.phead .crumbs{font-size:.78rem;letter-spacing:.06em;text-transform:uppercase;
  color:var(--ink_soft);font-weight:700;margin:0 0 .6rem}
.phead .crumbs a{color:var(--brand)}
.phead h1{font-size:clamp(1.9rem,4.6vw,3rem);line-height:1.08;margin:0;color:var(--ink);
  overflow-wrap:break-word}
.phead .meta{font-size:.85rem;color:var(--ink_soft);margin:.5rem 0 0}
.phead .dek{margin:.9rem 0 0;color:var(--ink_soft);font-size:1.05rem}
nav.site{border-bottom:1px solid var(--rule);background:var(--bg)}
/* No horizontal padding: it was the only .wrap in the shell with an inset, which
   pushed the first nav link 19.2px right of the logo, the H1 and the body column,
   and cost 38.4px of usable width at 320px (three wrapped rows). */
nav.site .wrap{display:flex;gap:1.15rem;flex-wrap:wrap;padding:.7rem 0}
nav.site a{color:var(--ink_soft);text-decoration:none;font-size:.9rem;font-weight:600;
  padding:.2rem 0;border-bottom:2px solid transparent}
nav.site a:hover{color:var(--ink)}
nav.site a[aria-current="page"]{color:var(--ink);border-bottom-color:var(--cta)}
.endcta{background:var(--panel);color:var(--panel_ink);padding:3.2rem 0;margin-top:4rem;text-align:center}
.endcta h2{margin:0 0 .5rem;font-size:clamp(1.3rem,3vw,1.9rem)}
.endcta p{margin:0 0 1.3rem;color:var(--panel_ink);opacity:.85}
/* .btn already reserves `border:2px solid transparent`, so this is no layout shift.
   The amber fill is 2.57:1 on the panel green -- the button's BOUNDARY is what has
   to clear 1.4.11, and white does. */
.endcta .btn-primary{border-color:#FFFFFF}
/* site.css sets `a{color:inherit}`, so the EHAP and insured crosslinks in the CTA
   subline rendered the same white as the text around them -- a link that does not
   look like a link. --gold is 5.33:1 on --panel. */
.endcta p a{color:var(--gold);text-decoration:underline;text-underline-offset:2px}

/* ---- skip link (also reaches the homepage: build_site injects content.css there) ---- */
/* position:fixed, never static -- static pushes the whole page down on focus. */
.skip{position:absolute;left:-9999px}
.skip:focus{position:fixed;left:.5rem;top:.5rem;z-index:99;background:var(--cta);
  color:var(--cta_ink);padding:.6rem 1rem;font-weight:700;border-radius:6px}

/* ---- WordPress forms: 20 pages, including /contact/, /free-estimate/ and the paid LP ---- */
/* CONTENT_CSS had zero form selectors, so the conversion form rendered in raw
   browser chrome. The LP additionally showed seven utm/gclid fields carrying the
   literal unexpanded {query_var key="utm_source"} -- their hiding CSS lives in a
   WPCode block that never reaches this build. */
.wp .lp-hidden,.wp .wpforms-field-hidden{display:none}
.wp .wpforms-field{margin:0 0 1.15rem}
.wp .wpforms-field-label{display:block;font-weight:700;font-size:.9rem;margin:0 0 .35rem}
.wp .wpforms-field-description{font-size:.85rem;color:var(--ink_soft);margin-top:.3rem}
.wp input:not([type=checkbox]):not([type=radio]):not([type=hidden]):not([type=submit]),
.wp textarea,.wp select{width:100%;max-width:100%;font:inherit;font-size:1rem;
  padding:.72rem .8rem;border:1px solid var(--field_rule);border-radius:6px;
  background:var(--field);color:var(--field_ink)}
.wp textarea{min-height:112px;resize:vertical}
.wp fieldset{border:0;padding:0;margin:0}
.wp legend.wpforms-field-label{padding:0}
.wp .wpforms-field-checkbox ul,.wp .wpforms-field-radio ul{list-style:none;margin-left:0}
.wp .wpforms-field-checkbox li,.wp .wpforms-field-radio li{display:flex;gap:.5rem;align-items:baseline}
/* --cta, not --gold: gold is 2.42:1 on the white interior ground and would add a
   second button colour beside .wp-block-button__link. */
.wp button,.wp input[type=submit],.wp .wpforms-submit{font:inherit;font-size:1rem;
  font-weight:700;background:var(--cta);color:var(--cta_ink);border:0;border-radius:6px;
  padding:.85rem 1.4rem;cursor:pointer}

/* ---- wp-block-cover: 4 pages, two variants, and the split by element type matters ---- */
/* Two flagship service pages opened with a 340px / 500px empty white void: the image
   sat on a background-image DIV with no position and no height. The two pages using a
   real <img> render fine already and must not regress -- hence the element-type split
   and max-width:none to beat `.wp img`. has-background-dim-0{opacity:0} is mandatory:
   without it, positioning the dim span turns it into an opaque panel over the photo. */
.wp .wp-block-cover{position:relative;display:flex;align-items:center;overflow:hidden;
  border-radius:14px;margin:1.6rem 0;min-height:0!important;aspect-ratio:auto!important}
.wp .wp-block-cover__image-background{position:absolute;inset:0}
.wp div.wp-block-cover__image-background{background-size:cover;background-repeat:no-repeat}
.wp img.wp-block-cover__image-background{width:100%;height:100%;object-fit:cover;
  margin:0;border-radius:0;max-width:none}
.wp .wp-block-cover__background{position:absolute;inset:0;display:block}
.wp .wp-block-cover__background.has-background-dim{opacity:.5}
.wp .wp-block-cover__background.has-background-dim-0{opacity:0}
.wp .wp-block-cover__inner-container{position:relative;z-index:1;width:100%}
.wp .wp-block-cover__inner-container > p:empty{display:none}

/* ---- /gallery/: the one page whose whole job is photographs ---- */
/* The Final Tiles masonry CSS is a WordPress head <link> and never reaches this build,
   so ten tiles stacked to ~6,000px. The container's own `caption-none` class hides the
   stray "sidetruck" caption on the live site, so hiding it here restores parity. */
.wp .final-tiles-gallery .ftg-items{display:grid;
  grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:.6rem}
.wp .final-tiles-gallery .tile{margin:0}
.wp .final-tiles-gallery .tile-inner{display:block}
.wp .final-tiles-gallery .tile img{aspect-ratio:1;object-fit:cover;width:100%;
  margin:0;border-radius:10px}
.wp .final-tiles-gallery .loading-bar,.wp .final-tiles-gallery .caption-block,
.wp .final-tiles-gallery .ftg-social{display:none}
/* Let the gallery and cover blocks out of the reading measure. Viewport units, not
   percentages: `min(50%,560px)` against `50%` of the same containing block computes
   to a margin of 0 and is a no-op. */
.wp > .final-tiles-gallery,.wp > .wp-block-cover{
  width:min(100vw - 2.25rem,1120px);margin-inline:calc(50% - min(50vw - 1.125rem,560px))}

/* ---- /blog/ archive ---- */
/* .screen-reader-text is a correctness rule and ships regardless: without it every
   "Read more" link prints its post title a second time, inside itself. */
.wp .screen-reader-text{position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}
.wp .wp-block-latest-posts{list-style:none;margin:0 0 1.15rem;padding:0;
  display:grid;gap:1rem;grid-template-columns:repeat(auto-fill,minmax(280px,1fr))}
.wp .wp-block-latest-posts>li{margin:0;border:1px solid var(--rule);border-radius:10px;padding:1.15rem}
.wp .wp-block-latest-posts__post-title{display:block;font-weight:700;font-size:1.15rem}
.wp .wp-block-latest-posts__post-date{display:block;font-size:.8rem;color:var(--ink_soft);
  margin:.25rem 0 .5rem}
.wp .wp-block-latest-posts__post-excerpt{color:var(--ink_soft)}

/* ---- Gutenberg preset classes: every editor alignment and size choice was discarded ---- */
.wp .has-text-align-center{text-align:center}
.wp .has-text-align-right{text-align:right}
.wp .has-large-font-size{font-size:1.35rem;line-height:1.4}
.wp .wp-block-buttons.is-content-justification-center{display:flex;justify-content:center}
.wp .has-primary-background-color{background:var(--brand)}
.wp .has-white-color{color:var(--panel_ink)}

/* ---- replaced elements other than img ---- */
/* No height:auto on iframe -- the map relies on its own absolute height inside a
   self-contained padding-bottom wrapper. The 420px cap is scoped to the portrait
   clip by its width attribute so the two landscape crane videos are untouched. */
.wp video,.wp iframe{max-width:100%;border-radius:14px;display:block;background:var(--bg_alt)}
.wp video{height:auto;margin:1.4rem 0}
.wp video[width="320"]{width:100%;max-width:420px}

/* Five location pages carry this crumb inline-styled at #555 -- off-token against
   --ink_soft. No negative-margin hoist: all five have a .wp-note above them. */
.wp .arbor-breadcrumb{color:var(--ink_soft)!important;font-size:.85rem}


/* ============================ K INTERIOR SPINE =============================
   Everything below is new in this pass. `.masthead`, `.zone`, `.linkgrid` and
   `.rev-card` are absent from the built homepage (checked against its class
   inventory), so none of it reaches `/` through build_site's content.css
   injection. `.alt` and `.est` are REUSED from site.css and get no new rules of
   their own here for the same reason.
   ========================================================================= */

/* ---- masthead: the interior page's answer to the hero ---- */
/* Operator decision D1, 2026-09-02: LIGHT --bg_alt, not the dark --panel this
   shipped on first. With no per-page hero art (media stays on the live origin and
   there are not 63 curated interior photographs), a dark masthead meant 63 pages
   opening identically. The light tint carries every .phead token unchanged, so all
   four colour overrides the dark version needed are GONE -- h1 keeps --ink,
   eyebrow/crumbs keep --brand, meta/dek keep --ink_soft, and the focus ring falls
   back to the global --cta, which is what a light ground wants.
   The border-bottom is not optional: --bg_alt on --bg is 1.12:1, so without an
   explicit edge the masthead would dissolve into zone 0. This is a full-bleed rule
   on a full-bleed BAND -- the band's own edge, the same construction as
   nav.site's -- not a rule under a text column, which is the D03 defect. */
.masthead{background:var(--bg_alt);padding:3.4rem 0 3rem;
  border-bottom:1px solid var(--rule)}
/* `margin:0 auto`, NOT `margin:0`. .phead centres itself inside the 1120px .wrap;
   zeroing the shorthand flush-lefts the H1 against a body column still centred at
   34rem -- the ~235px misalignment the review already fixed once. */
.masthead .phead{margin:0 auto;padding:0;border-bottom:0}
[data-band="micro"] .masthead{padding:2.6rem 0 2.3rem}

/* ---- body zones ---- */
/* One <section> per band. site.css gives every <section> 3.25rem (4.5rem >=760px);
   a 4-band page would pay that four times, so .zone sets its own. */
.zone{padding:2.6rem 0}
/* NOT `.zone:first-of-type` -- :first-of-type keys on the ELEMENT type, and the
   masthead is the first <section> in <main>, so that selector matches nothing. */
.masthead + .zone{padding-top:2.2rem}
/* The seam. --bg_alt on --bg is 1.12:1 -- a tint alone is a whisper, so the
   boundary is carried by an explicit hairline AT THE READING MEASURE (never full
   bleed: a full-bleed rule overhangs the 34rem column by ~235px each side, which
   is the defect the review already removed from .phead). The alternating ground
   reinforces it; neither is load-bearing alone. */
.zone + .zone > .wrap > .wp{border-top:1px solid var(--rule);padding-top:2.4rem}
/* Bands do not collapse margins across their boundary the way one continuous .wp
   did, so the first child's own margin-top would double the gap and the last
   child's would drift the grounds out of register down the page. */
.zone > .wrap > .wp > :first-child{margin-top:0}
.zone > .wrap > .wp > :last-child{margin-bottom:0}

/* ---- MICRO: 4 pages under 1,200 body characters ---- */
/* /lp/ is 261 characters. On a white ground under a white nav it read as a failed
   load. The tint plus the masthead make it read as a deliberately short page. */
[data-band="micro"] main{background:var(--bg_alt)}
[data-band="micro"] .zone{padding:2.2rem 0}

/* ---- the WordPress form, promoted onto site.css's own estimate panel ---- */
/* The generator prepends `est` to the container's existing class list, so
   site.css's .est panel (--panel ground, 12px radius, its own field and button
   rules) applies to all 20 form-bearing pages with no new form CSS. The five rules
   below exist only because content.css loads AFTER site.css and its own .wp form
   rules -- equal specificity, later sheet -- would otherwise repaint three things
   dark-on-dark. Scoped to `.wp .est` so the homepage's own .est is untouched. */
.wp .est{margin:1.6rem 0 0}
.wp .est a{color:var(--gold)}                      /* --brand on --panel is 1.97:1 */
.wp .est .wpforms-field-label{color:var(--panel_ink)}
.wp .est .wpforms-field-description{color:var(--panel_ink);opacity:.82}
.wp .est button,.wp .est input[type=submit],.wp .est .wpforms-submit{
  background:var(--gold);color:var(--gold_ink);width:100%}
/* --cta fill is 2.57:1 on --panel and the WPForms button has border:0, so it has no
   boundary to rescue it the way .endcta .btn-primary does with #FFF. --gold on
   --panel is 5.33:1, --gold_ink on --gold is 7.10:1 -- and this is what site.css's
   own `.est button` already specifies; content.css just has to re-win it.
   Side effect worth naming: --field_rule is 2.34:1 on the white interior ground
   (an SC 1.4.11 failure on all 20 pages) and 5.50:1 on --panel. */
.wp .est{--focus:var(--gold)}
/* REGRESSION FIX 2026-09-02, found by the operator on /forestry-mulching/.
   site.css's `.est input{width:100%;padding:.72rem .8rem;border:1px solid;
   margin-bottom:.9rem}` is UNQUALIFIED -- it was written for the homepage's own
   form, which has three text inputs and nothing else. Promoting the WPForms
   container onto that panel therefore hit every checkbox and radio too: inside
   `.wpforms-field-checkbox li{display:flex}` the box took the whole row, shoving
   its label to the right edge and wrapping every one onto two lines.
   My own `.wp input:not([type=checkbox])...` rule correctly excludes them, but it
   cannot undo a rule that was never scoped -- so undo it explicitly here. Fixed in
   CONTENT_CSS, never in site.css: that file is copied from build_k.py's output,
   the standalone apt-previews client deliverable. */
.wp .est input[type=checkbox],.wp .est input[type=radio]{
  width:auto;margin:0;padding:0;border:0;background:none;flex:0 0 auto}
.wp .est .wpforms-field-label-inline{display:inline;font-size:.94rem;font-weight:400;margin:0}
/* The form declares its own choice layout in a class and WPForms' stylesheet -- the
   thing that reads it -- never reaches this build. Honouring the class the copy
   already carries is not inventing a design. */
.wp .wpforms-list-2-columns ul{display:grid;grid-template-columns:repeat(2,1fr);gap:.4rem 1rem}
.wp .wpforms-list-inline ul{display:flex;flex-wrap:wrap;gap:.4rem 1.15rem}
@media (max-width:479px){.wp .wpforms-list-2-columns ul{grid-template-columns:1fr}}

/* ---- the legacy 5-star review card: 18 pages ---- */
/* neutralise_inline() already remapped its gradient to var(--panel) and stripped
   its box-shadow. The generator adds `class="rev-card"` to the same div (it has no
   class attribute of its own, so there is no duplicate-attribute no-op). This only
   stops its inline 24px/28px padding reading as a full-width slab in a 544px
   column, and lets it sit on the tinted band without a seam of its own. */
.wp .rev-card{border-radius:12px;padding:1.35rem 1.15rem!important;margin:1.8rem 0!important}
.wp .rev-card a{color:var(--panel)}

/* ---- internal link lists: 17 lists on 17 pages ---- */
/* Every item is a link and every label is <=38 characters -- these are navigation
   printed as bullets in a 544px column. The card treatment is the homepage's own
   .rev idiom (bordered card on the page ground). --brand on --bg is 6.54:1. */
.wp .linkgrid{list-style:none;margin:1.2rem 0 1.3rem;padding:0;display:grid;gap:.6rem;
  grid-template-columns:repeat(auto-fill,minmax(220px,1fr))}
.wp .linkgrid li{margin:0}
.wp .linkgrid li a{display:block;background:var(--bg);border:1px solid var(--rule);
  border-radius:10px;padding:.8rem .95rem;text-decoration:none;color:var(--brand);
  font-weight:600;font-size:.94rem}
.wp .linkgrid li a:hover{border-color:var(--numeral)}

/* ---- end CTA ---- */
/* WAS margin-top:4rem. That margin is transparent, so above the dark .endcta it
   rendered as a 64px white stripe wherever the last band was tinted -- roughly half
   the pages. The zones already carry 2.6rem of bottom padding. */
.endcta{margin-top:0}

/* ---- interior media bands ---- */
/* The homepage's own `.band` / `.band-in` / `figure.sq` rules in site.css do all
   the real work; these only retune the geometry for an interior page. The homepage
   runs its squares full-bleed to 1760px, which reaches ~720px tall at desktop and
   is a deliberate choice there. An interior page is a reading page, so the band is
   held to the same 1120px wrap the text uses and a lone photo is capped narrower
   still -- a 1200x1200 source stretched full-bleed would tower over the 34rem
   column it interrupts. */
.zoneband .band-in{max-width:1120px;padding:0 1.125rem;gap:.75rem}
.zoneband.solo .band-in{max-width:640px}
/* Square sources, so a wide crop would slice heads and boom tips out of frame.
   Two-up stays square; a lone plate goes slightly landscape and no further. */
.zoneband .sq{border-radius:14px}
.zoneband.solo .sq{aspect-ratio:5/4}
.zoneband{padding:2.1rem 0}
@media (max-width:759px){
  .zoneband{padding:1.5rem 0}
  .zoneband .band-in{gap:.6rem}
  /* site.css collapses .band-in.two to one column below 760px, so two photos
     stack; keep them square there rather than inheriting the solo ratio. */
  .zoneband.solo .sq{aspect-ratio:1/1}
}

/* ---- mobile ---- */
/* site.css tightens `section` below 760px but content.css had no media query at all,
   so .phead paid its full 3.2rem on a phone, stacking with the section padding for
   ~103px of empty space between the nav rule and the eyebrow. */
@media (max-width:759px){
  nav.site .wrap{gap:.8rem}
  nav.site a{font-size:.85rem}
  .phead{padding:1.9rem 0 1rem;margin-bottom:1.6rem}
  .masthead{padding:2.1rem 0 1.9rem}
  [data-band="micro"] .masthead{padding:1.8rem 0 1.6rem}
  .zone{padding:1.9rem 0}
  .masthead + .zone{padding-top:1.7rem}
  .zone + .zone > .wrap > .wp{padding-top:1.8rem}
}
