/* ===========================================================================
   Adkins Tree & Stump — goatspro.com

   The brief was a poster, not a brochure. The supplied logo is a badge: an
   arched illustration over a stacked wordmark over a banner carrying the phone
   number, with the whole thing keylined in lime. So the page is built out of
   the same three parts — banded grounds, hard keylines and angled chevrons —
   and it never uses a rounded card, a drop shadow or a small-caps eyebrow.

   Deliberately NOT the other three builds in this family:
     Arbor Pro    navy/red, rounded cards, shadows          (light template)
     Immaculate   black + lime, Oswald, dark all the way through
     Moore        bone base, forest green, Archivo + serif
   This one alternates black -> bone -> photo -> coal in bands, which is what
   keeps it from reading as Immaculate with a different logo.

   PALETTE — sampled, not guessed:
     --lime    #79971B  modal colour of the badge's keyline (tools/probe)
     --orange  #F6642A  modal colour of the company's own TREE WORK road sign
   Every foreground/background pair the page uses is listed in tools/contrast.py
   with its measured ratio. Text over the photographs is measured separately by
   tools/photo_contrast.py, because a computed ratio over a photo is fiction.
   =========================================================================== */

:root {
  --black:      #000000;   /* the badge's own ground — it seams in exactly */
  --coal:       #0D0F0C;   /* dark sections */
  --coal-2:     #171B12;   /* raised dark: form fields, faq rows */
  --bone:       #F4F2EA;   /* light sections */
  --bone-2:     #E9E6D9;   /* alternate light ground */
  --white:      #ffffff;

  --lime:       #79971B;   /* sampled from the badge keyline */
  --lime-hi:    #A9CE33;   /* lime text + CTAs on dark — 10.60:1 on coal */
  --lime-ink:   #44570C;   /* lime text on bone — 7.17:1 */
  /* The sampled lime lands on 2.9997:1 against bone — a hair under the 3:1
     that WCAG 1.4.11 asks of a meaningful graphic. Rules and keylines drawn on
     a LIGHT ground use this slightly deeper mix instead (3.71:1); chip fills,
     which are read via their own dark label, keep the sampled colour. */
  --lime-rule:  #6B8617;

  /* Focus ring colour, set per ground. A single ring cannot work on both:
     lime-hi is 10.60:1 on coal but 1.62:1 on bone, and ink is the reverse.
     Custom properties inherit, so every dark section re-declares --focus once
     and everything inside it picks the right one up. */
  --focus:      #14160F;
  /* Same trick for lime rules and keylines: deeper on light, sampled on dark. */
  --keyline:    var(--lime-rule);

  --orange:     #F6642A;   /* sampled from their TREE WORK sign — 6.21:1 on coal */
  --orange-hi:  #FF8049;
  --orange-ink: #B23C08;   /* orange text on bone — 5.29:1 */

  --ink:        #14160F;   /* headings on bone — 16.28:1 */
  --body:       #43483C;   /* body copy on bone — 8.40:1 */
  --mist:       #C8CDBE;   /* body copy on dark — 11.86:1 */
  --dim:        #8E9683;   /* de-emphasised copy on dark — 6.27:1 */

  --line-lt:    #D8D4C4;
  --line-dk:    rgba(169, 206, 51, .22);

  --dsp:  'Anton', 'Arial Narrow', Impact, sans-serif;
  --ui:   'IBM Plex Sans', ui-sans-serif, system-ui, 'Segoe UI', Roboto, Arial, sans-serif;

  --wrap: 1180px;
  --pad:  1.4rem;
  --head: 104px;           /* utility bar + sticky header, desktop */
  --key:  5px;             /* the standard keyline weight */
}

/* ------------------------------------------------------------------ base --- */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  overflow-x: clip;
  scroll-behavior: smooth;
}
[id] { scroll-margin-top: calc(var(--head) + 14px); }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}

body {
  margin: 0;
  background: var(--bone);
  color: var(--body);
  font-family: var(--ui);
  font-size: 17px;
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; display: block; }
a { color: inherit; }
p { margin: 0 0 1rem; }
ul, ol { margin: 0; padding: 0; list-style: none; }

h1, h2, h3 {
  font-family: var(--dsp);
  font-weight: 400;              /* Anton ships one weight; 400 IS the heavy */
  text-transform: uppercase;
  letter-spacing: .012em;
  line-height: .96;
  margin: 0;
  color: var(--ink);
}
h1 { font-size: clamp(2.6rem, 7.4vw, 5.1rem); }
h2 { font-size: clamp(2rem, 4.9vw, 3.4rem); }
h3 { font-size: clamp(1.18rem, 1.9vw, 1.5rem); letter-spacing: .02em; }

.wrap { width: 100%; max-width: var(--wrap); margin-inline: auto; padding-inline: var(--pad); }
.wrap-narrow { max-width: 860px; }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--lime-hi); color: var(--black);
  padding: .75rem 1.15rem; font-weight: 700;
}
.skip:focus { left: 0; }

:where(a, button, input, select, textarea, summary):focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 3px;
}
/* Everything with a dark ground flips the ring to lime. */
.util, .site, .nav, .hero, .proof, .sec-coal, .sec-black, .band, .foot, .lb,
.stump-stage { --focus: var(--lime-hi); --keyline: var(--lime); }

/* Icon+text rows. align-items:center centres the MARGIN box, so any inherited
   margin on the icon offsets the text by half its value. Kill it explicitly. */
.ico { width: 1em; height: 1em; flex: none; fill: currentColor; margin: 0; display: block; }

/* --------------------------------------------------------------- lockups --- */
/* A "banner" is the badge's own device: a keylined slab with a notched end.
   Used for section titles, the 24/7 flag and the proof marks. */
.banner {
  display: inline-block;
  background: var(--lime);
  color: var(--black);
  font: 700 .8rem/1 var(--ui);
  letter-spacing: .16em;
  text-transform: uppercase;
  padding: .62rem 1.15rem;
  clip-path: polygon(0 0, 100% 0, calc(100% - 11px) 100%, 11px 100%);
}
.banner-orange { background: var(--orange); }

/* ---------------------------------------------------------------- rules --- */
.rule {
  width: 88px; height: var(--key);
  background: var(--keyline);
  margin: 1.15rem 0 1.5rem;
}
.rule-c { margin-inline: auto; }
.rule-orange { background: var(--orange); }

/* -------------------------------------------------------------- chevrons ---
   The divider between two bands. --a is the colour ABOVE, --b the colour
   BELOW; the wedge is drawn in --a over a ground of --b, with a lime edge
   tracing its underside. Nothing here is content, so it is aria-hidden. */
.chev {
  position: relative;
  height: clamp(26px, 3.8vw, 58px);
  background: var(--b);
  margin-top: -1px;           /* kill the hairline sub-pixel seam */
}
.chev::before, .chev::after { content: ""; position: absolute; inset: 0; }
.chev::before { background: var(--lime); clip-path: polygon(0 0, 50% 100%, 100% 0); }
.chev::after  { background: var(--a);    clip-path: polygon(0 0, 50% calc(100% - 8px), 100% 0); }
.chev-orange::before { background: var(--orange); }

/* -------------------------------------------------------------- buttons --- */
/* Lime is 6.30:1 against a near-black label and only 3.06:1 against white, and
   orange is 6.21 / 3.10 the same way round. Both solid buttons therefore carry
   a DARK label, always. This is not a style preference. */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: .5rem;
  font: 700 .95rem/1 var(--ui);
  letter-spacing: .09em;
  text-transform: uppercase;
  text-decoration: none;
  padding: .95rem 1.5rem;
  border: 3px solid transparent;
  cursor: pointer;
  transition: background-color .16s ease, color .16s ease, border-color .16s ease;
  clip-path: polygon(0 0, 100% 0, calc(100% - 13px) 100%, 13px 100%);
}
.btn-lg { font-size: 1.02rem; padding: 1.1rem 1.9rem; }
.btn-block { width: 100%; }

.btn-lime   { background: var(--lime-hi); color: var(--black); }
.btn-orange { background: var(--orange);  color: var(--black); }
/* A ghost button has no fill, so its label sits on whatever is behind it. On
   the dark grounds and over the photographs that is the bright lime. */
.btn-ghost  { background: transparent; color: var(--lime-hi); border-color: var(--lime-hi); }
.btn-ghost-ink { color: var(--ink); border-color: var(--ink); }

@media (hover: hover) {
  .btn-lime:hover   { background: #C0E24B; }
  .btn-orange:hover { background: var(--orange-hi); }
  .btn-ghost:hover  { background: var(--lime-hi); color: var(--black); }
  .btn-ghost-ink:hover { background: var(--ink); color: var(--bone); }
}

/* ---------------------------------------------------------- utility bar --- */
.util {
  background: var(--coal);
  border-bottom: 2px solid var(--lime);
  color: var(--dim);
  font-size: .82rem;
  line-height: 1;
}
.util-in {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; min-height: 40px;
}
.util p { margin: 0; letter-spacing: .05em; text-transform: uppercase; }
.util-call a { color: var(--lime-hi); text-decoration: none; font-weight: 600; }
.util-call strong { letter-spacing: .04em; }
@media (hover: hover) { .util-call a:hover { text-decoration: underline; } }

/* --------------------------------------------------------------- header --- */
.site {
  position: sticky; top: 0; z-index: 60;
  background: var(--black);
  border-bottom: var(--key) solid var(--lime);
}
.site-in {
  display: flex; align-items: center; gap: 1.6rem;
  min-height: 68px;
}
.brand { display: block; flex: none; margin-right: auto; }
.brand img { height: 42px; width: auto; }

/* THE HEADER BUG. <nav> is a block by default, and .nav-links is a block-level
   flex row, so the CTA — an inline-flex .btn — had nowhere to go but the line
   underneath. On a desktop that painted a stray "Free Estimate" button floating
   below the menu. Making .nav itself the flex row puts the links and the CTA on
   one baseline, which is what it always looked like it was meant to do. */
.nav { display: flex; align-items: center; gap: 1.7rem; }

.nav-links { display: flex; align-items: center; gap: 1.55rem; }
.nav-links a {
  color: var(--mist);
  text-decoration: none;
  font-weight: 600;
  font-size: .88rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  padding: .35rem 0;
  border-bottom: 3px solid transparent;
}
@media (hover: hover) { .nav-links a:hover { color: var(--lime-hi); } }
.nav-links a[aria-current="true"] { color: var(--white); border-bottom-color: var(--orange); }

/* SPECIFICITY TRAP: `.nav a` is (0,1,1) and beats a bare `.btn` at (0,1,0), so
   the CTA has to be selected as `.nav a.nav-cta` (0,2,1) or its label inherits
   --mist and paints grey-on-lime. This exact bug cost a round trip on an
   earlier build in this family. */
.nav a.nav-cta {
  background: var(--lime-hi); color: var(--black);
  border-bottom: 0;
  padding: .8rem 1.25rem;
  font-size: .86rem;
}
@media (hover: hover) { .nav a.nav-cta:hover { background: #C0E24B; color: var(--black); } }

.burger {
  display: none;
  width: 46px; height: 40px;
  background: transparent; border: 2px solid var(--lime); cursor: pointer;
  padding: 0; place-items: center;
}
.burger span { display: block; width: 22px; height: 3px; background: var(--lime-hi); margin: 2.5px auto; }

.nav-head, .nav-foot { display: none; }
.scrim {
  position: fixed; inset: 0; z-index: 70;
  background: rgba(0, 0, 0, .72);
}

/* ----------------------------------------------------------------- hero --- */
.hero { position: relative; background: var(--black); isolation: isolate; }
.hero-img {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%; object-fit: cover; object-position: 50% 42%;
}
/* Poster scrim. Heavier at the foot than the head, because the headline and
   both CTAs sit low and the sky at the top is already dark. Measured over the
   real frame by tools/photo_contrast.py — not eyeballed. */
.hero::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background:
    linear-gradient(180deg, rgba(0,0,0,.72) 0%, rgba(0,0,0,.56) 34%, rgba(0,0,0,.82) 100%),
    radial-gradient(120% 82% at 50% 62%, rgba(0,0,0,.34) 0%, rgba(0,0,0,0) 70%);
}
.hero-in {
  position: relative;
  padding: clamp(3.4rem, 8vw, 6.6rem) var(--pad) clamp(3rem, 7vw, 5.6rem);
  text-align: center;
  display: flex; flex-direction: column; align-items: center;
  /* LOAD-BEARING. .hero-in is a flex item; without an explicit full width it
     shrinks to its widest child and `margin:auto` then re-centres the whole
     column off the layout grid. */
  width: 100%;
}
.hero h1 { color: var(--white); text-shadow: 0 2px 26px rgba(0,0,0,.55); max-width: 15ch; }
/* The lime bar under "AND THE STUMP" is painted as a background gradient with
   box-decoration-break:clone, NOT an absolutely-positioned ::after — the
   pseudo-element version vanishes the moment the span wraps on a phone. */
.hero h1 .mark {
  background-image: linear-gradient(var(--lime), var(--lime));
  background-repeat: no-repeat;
  background-size: 100% .17em;
  background-position: 0 .93em;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
.hero-lede {
  color: #E7EBDF; max-width: 56ch; margin: 1.5rem 0 0;
  font-size: clamp(1.02rem, 1.5vw, 1.14rem);
  text-shadow: 0 1px 14px rgba(0,0,0,.6);
}
.hero-btns { display: flex; flex-wrap: wrap; gap: .85rem; justify-content: center; margin-top: 2rem; }
.hero-loc {
  margin: 0 0 1.35rem; color: var(--lime-hi);
  font-weight: 600; font-size: .84rem; letter-spacing: .2em; text-transform: uppercase;
  text-shadow: 0 1px 12px rgba(0,0,0,.7);
}

/* --- desktop hero ---
   Centred copy over a centred subject means the copy sits on the subject, and
   on a wide screen the headline covered the climber completely. Above 900px the
   column goes hard left and the scrim goes with it: heavy under the text,
   clearing to almost nothing over the right-hand third where the climber is.

   The horizontal half of this fix is NOT here — it is the pre-crop in
   tools/build_assets.py that moves him to ~58% across. `object-fit: cover`
   ignores horizontal object-position whenever the container is wider than the
   image, which a full-bleed hero always is, so CSS cannot shift him. */
@media (min-width: 901px) {
  .hero-in {
    text-align: left;
    align-items: flex-start;
    padding-block: clamp(4.4rem, 7.5vw, 7rem) clamp(4rem, 6.5vw, 6rem);
  }
  .hero h1 { max-width: 11ch; }
  .hero-lede { max-width: 42ch; margin-top: 1.6rem; }
  .hero-btns { justify-content: flex-start; }
  .hero-img { object-position: 50% 45%; }
  .hero::after {
    background:
      linear-gradient(90deg,
        rgba(0,0,0,.90) 0%, rgba(0,0,0,.84) 26%,
        rgba(0,0,0,.52) 52%, rgba(0,0,0,.26) 72%, rgba(0,0,0,.20) 100%),
      linear-gradient(180deg, rgba(0,0,0,.34) 0%, rgba(0,0,0,0) 42%, rgba(0,0,0,.46) 100%);
  }
}

/* ---------------------------------------------------------------- proof --- */
.proof { background: var(--black); border-block: var(--key) solid var(--lime); }
.proof-in {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: 1px 0;
  padding-block: 0;
}
.proof-in li {
  display: flex; align-items: center; justify-content: center; gap: .6rem;
  color: var(--white); text-align: center;
  font-weight: 600; font-size: .84rem; letter-spacing: .11em; text-transform: uppercase;
  padding: 1.15rem .7rem;
  line-height: 1.25;
}
.proof-in li + li { box-shadow: -1px 0 0 var(--line-dk); }
.proof-in li::before {
  content: ""; flex: none;
  width: 13px; height: 13px; background: var(--lime-hi);
  clip-path: polygon(0 0, 100% 0, 72% 100%, 0 100%);
}
.proof-in li.is-urgent::before { background: var(--orange); }

/* -------------------------------------------------------------- sections --- */
.sec { padding-block: clamp(3.4rem, 6.5vw, 5.6rem); }
.sec-bone { background: var(--bone); }
.sec-bone2 { background: var(--bone-2); }
.sec-coal { background: var(--coal); color: var(--mist); }
.sec-coal h2, .sec-coal h3 { color: var(--white); }
.sec-black { background: var(--black); color: var(--mist); }
.sec-black h2, .sec-black h3 { color: var(--white); }

.sec-head { margin-bottom: clamp(2rem, 3.4vw, 2.9rem); }
.sec-head.is-centre { text-align: center; }
.lede { font-size: clamp(1.02rem, 1.5vw, 1.14rem); max-width: 62ch; margin: 0; }
.sec-head.is-centre .lede { margin-inline: auto; }
.sec-coal .lede, .sec-black .lede { color: var(--mist); }

/* -------------------------------------------------------------- services --- */
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 1.6rem;
}
.card {
  background: var(--white);
  border: 2px solid var(--line-lt);
  border-top: var(--key) solid var(--keyline);
  display: flex; flex-direction: column;
  transition: border-top-color .18s ease, transform .18s ease;
}
.card-urgent { border-top-color: var(--orange); }
@media (hover: hover) {
  .card:hover { transform: translateY(-4px); }
}
/* Neutralise the lift on touch — a transform hover sticks after a tap. */
@media (hover: none) { .card:hover { transform: none; } }

.card img { width: 100%; height: auto; }
.card-body { padding: 1.35rem 1.4rem 1.5rem; display: flex; flex-direction: column; flex: 1; }
.card-body h3 { margin-bottom: .6rem; }
.card-body p { margin: 0; flex: 1; }
.card-tag {
  display: inline-block; align-self: flex-start;
  margin-bottom: .75rem;
  font: 700 .7rem/1 var(--ui); letter-spacing: .16em; text-transform: uppercase;
  color: var(--lime-ink);
}
.card-urgent .card-tag { color: var(--orange-ink); }

/* ----------------------------------------------------------- storm band --- */
.band { position: relative; isolation: isolate; background: var(--black); }
.band-img {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%; object-fit: cover; object-position: 50% 44%;
}
.band::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(100deg, rgba(0,0,0,.92) 0%, rgba(0,0,0,.80) 46%, rgba(0,0,0,.62) 100%);
}
.band-in {
  padding-block: clamp(3.6rem, 7vw, 6rem);
  max-width: 720px;
}
.band-in h2 { color: var(--white); margin-block: 1.2rem .9rem; }
.band-in p { color: var(--mist); }
.band-in .btn { margin-top: .8rem; }

/* -------------------------------------------------- stump / how it works --- */
.stump-in {
  display: grid; grid-template-columns: 1.05fr .95fr;
  gap: clamp(2rem, 4vw, 3.6rem); align-items: center;
}
.stump-steps { margin-top: 1.9rem; display: grid; gap: 1.35rem; }
.stump-steps li { display: grid; grid-template-columns: auto 1fr; gap: 0 1rem; }
.stump-n {
  font: 400 1.65rem/1 var(--dsp); color: var(--lime-hi);
  grid-row: span 2; align-self: start; padding-top: .1rem;
  min-width: 2.1ch;
}
.stump-steps h3 { color: var(--white); font-size: 1.1rem; margin-bottom: .25rem; }
.stump-steps p { margin: 0; color: var(--mist); font-size: .97rem; }

.stump-stage {
  background: #090B08;
  border: 2px solid var(--line-dk);
  padding: 1rem;
}
.stump-svg { width: 100%; height: auto; display: block; }

/* ------------------------------------------------------------------ work --- */
/* TWO sliders, side by side. Each half of the client's collages is only 478px
   across, so a single full-width frame was blowing them up past 2x and it
   showed — the pair reads as more proof AND lands each photo at roughly its
   native size, which is the actual fix for the softness. */
.ba-pair {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.8rem;
  max-width: 1000px;
  margin-inline: auto;
}
.ba-item { margin: 0; }

.ba {
  position: relative;
  border: var(--key) solid var(--keyline);
  background: var(--black);
  overflow: hidden;
  touch-action: pan-y;          /* let a vertical swipe scroll the page */
}
.ba-frame { position: relative; }
.ba-frame img { width: 100%; height: auto; }
/* The AFTER frame is clipped with clip-path:inset, NOT by resizing a wrapper.
   Resizing re-lays-out the inner image, so object-fit crops the two halves
   differently and the seam walks. */
.ba-top {
  position: absolute; inset: 0;
  clip-path: inset(0 calc(100% - var(--p, 0%)) 0 0);
}
.ba-top img { width: 100%; height: 100%; object-fit: cover; }
.ba-tag {
  position: absolute; bottom: 0; z-index: 3;
  font: 700 .74rem/1 var(--ui); letter-spacing: .18em; text-transform: uppercase;
  padding: .55rem .95rem;
  color: var(--black);
  pointer-events: none;
}
.ba-tag-b { left: 0; background: var(--white); }
.ba-tag-a { right: 0; background: var(--lime-hi); }

.ba-line {
  position: absolute; top: 0; bottom: 0; z-index: 4;
  left: var(--p, 0%);
  width: 4px; margin-left: -2px;
  background: var(--lime-hi);
  pointer-events: none;
}
.ba-grip {
  position: absolute; top: 50%; left: 50%; z-index: 5;
  transform: translate(-50%, -50%);
  width: 46px; height: 46px;
  background: var(--lime-hi);
  display: grid; place-items: center;
  clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
}
.ba-grip svg { width: 22px; height: 22px; fill: var(--black); }

/* The range IS the control — the visuals above are decoration. Keeping a real
   input means drag, keyboard and screen readers all work without any of it
   being reimplemented in script. */
.ba-range {
  position: absolute; inset: 0; z-index: 6;
  width: 100%; height: 100%; margin: 0;
  opacity: 0; cursor: ew-resize;
  -webkit-appearance: none; appearance: none; background: transparent;
}
.ba-range::-webkit-slider-thumb { -webkit-appearance: none; width: 46px; height: 100vh; }
.ba-range::-moz-range-thumb { width: 46px; height: 100vh; border: 0; opacity: 0; }
.ba-range:focus-visible ~ .ba-grip { outline: 3px solid var(--white); outline-offset: 3px; }

.ba-note {
  margin: .9rem 0 0;
  font-size: .9rem; line-height: 1.5; color: var(--body); text-align: center;
}

/* --------------------------------------------------------------- gallery ---
   A UNIFORM grid, not a mosaic. The version this replaced kept every photo's
   native aspect and let tiles span two columns or two rows; on a phone that
   reads as a camera roll, but on a desktop it reads as a collage that went
   wrong. Every tile is now the same 4:3 box and every source is cropped to it
   in tools/build_assets.py, so the grid lines up in both directions.

   Eight tiles, four across or two across — never three. Nine photos in a
   three-column grid leaves a two-tile orphan row, and there is no arrangement
   of 8 across 4/3/2 that is clean at all three. */
.gal {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 14px;
  margin-top: 2.6rem;
}
.gal button {
  position: relative;
  display: block; width: 100%;
  padding: 0; margin: 0;
  border: 0;
  background: var(--black);
  cursor: pointer;
  overflow: hidden;
  isolation: isolate;
}
/* A tile's ground is a photograph, so neither the light nor the dark ring is
   reliable on its own. The inset shadow lays down a near-black band first and
   the lime ring is then guaranteed something to read against. */
.gal button:focus-visible {
  outline: 4px solid var(--lime-hi);
  outline-offset: -4px;
  box-shadow: inset 0 0 0 10px rgba(0, 0, 0, .8);
}
.gal img {
  width: 100%; height: auto; display: block;
  aspect-ratio: 4 / 3;             /* belt and braces — the files are 4:3 too */
  object-fit: cover;
  transition: transform .5s cubic-bezier(.22,.61,.36,1);
}

/* the lime keyline that draws in on hover */
.gal button::after {
  content: ""; position: absolute; inset: 0; z-index: 3;
  border: 0 solid var(--lime-hi);
  transition: border-width .2s ease;
  pointer-events: none;
}

.gal-cap {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  margin: 0;
  padding: 2.4rem .85rem .8rem;
  background: linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(0,0,0,.55) 42%, rgba(0,0,0,.9) 100%);
  color: var(--white);
  font-size: .84rem; line-height: 1.35; text-align: left;
  transform: translateY(100%);
  transition: transform .32s cubic-bezier(.22,.61,.36,1);
}
.gal-zoom {
  position: absolute; top: .7rem; right: .7rem; z-index: 2;
  width: 38px; height: 38px;
  background: var(--lime-hi);
  display: grid; place-items: center;
  opacity: 0; transform: scale(.75);
  transition: opacity .24s ease, transform .24s cubic-bezier(.22,.61,.36,1);
  clip-path: polygon(0 0, 100% 0, 100% 72%, 72% 100%, 0 100%);
}
.gal-zoom svg { width: 19px; height: 19px; fill: var(--black); }

@media (hover: hover) {
  .gal button:hover img,
  .gal button:focus-visible img { transform: scale(1.06); }
  .gal button:hover .gal-cap,
  .gal button:focus-visible .gal-cap { transform: none; }
  .gal button:hover .gal-zoom,
  .gal button:focus-visible .gal-zoom { opacity: 1; transform: none; }
  .gal button:hover::after { border-width: 4px; }
}
/* On a touch screen there is no hover to reveal any of it, and a transform
   hover sticks after a tap. The caption sits open instead and the tile is
   simply a button. */
@media (hover: none) {
  .gal button:hover img { transform: none; }
  .gal-cap { transform: none; padding-top: 1.8rem; font-size: .78rem; }
  .gal-zoom { display: none; }
}

.gal-hint {
  margin: 1.1rem 0 0; text-align: center;
  font-size: .88rem; color: var(--body);
}

/* lightbox */
.lb {
  position: fixed; inset: 0; z-index: 120;
  background: rgba(0, 0, 0, .93);
  display: grid; place-items: center;
  padding: 3.4rem 1rem;
}
.lb img { max-width: 100%; max-height: 100%; width: auto; height: auto; object-fit: contain; }
.lb-close, .lb-prev, .lb-next {
  position: absolute; z-index: 2;
  background: var(--lime-hi); color: var(--black); border: 0; cursor: pointer;
  width: 48px; height: 48px; display: grid; place-items: center;
}
.lb-close { top: 1rem; right: 1rem; }
.lb-prev { left: 1rem; top: 50%; transform: translateY(-50%); }
.lb-next { right: 1rem; top: 50%; transform: translateY(-50%); }
.lb svg { width: 22px; height: 22px; fill: currentColor; }
.lb-cap {
  position: absolute; left: 0; right: 0; bottom: 0;
  margin: 0; padding: .85rem 1.2rem;
  background: rgba(0, 0, 0, .72); color: var(--mist);
  font-size: .9rem; text-align: center;
}

/* -------------------------------------------------------------- brandmark --- */
.mark-in { display: grid; grid-template-columns: minmax(0, .85fr) minmax(0, 1.15fr); gap: clamp(2rem, 4.5vw, 4rem); align-items: center; }
.mark-fig { margin: 0; text-align: center; }
.mark-fig img {
  width: 100%; max-width: 460px; height: auto; margin-inline: auto;
  border: 3px solid var(--keyline);
}
.mark-fig figcaption {
  margin-top: .9rem;
  font-weight: 600; font-size: .76rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--lime-hi);
}
.why-list { display: grid; gap: 1.5rem; margin-top: 1.9rem; }
.why-list h3 { color: var(--white); font-size: 1.1rem; margin-bottom: .3rem; }
.why-list p { margin: 0; color: var(--mist); font-size: .97rem; }
.why-list li { border-left: var(--key) solid var(--keyline); padding-left: 1.1rem; }

/* ------------------------------------------------------------------ area --- */
.areas { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 2rem; margin-top: 2.2rem; }
.area-col h3 { font-size: 1.05rem; color: var(--ink); margin-bottom: .9rem; padding-bottom: .55rem; border-bottom: 3px solid var(--keyline); }
/* A two-column grid, NOT a wrapping flex — wrapping gives a ragged right edge
   and the columns stop lining up between groups. */
.area-col ul { display: grid; grid-template-columns: repeat(2, 1fr); gap: .4rem 1rem; }
.area-col li { font-size: .95rem; }
.area-col li::before { content: "\203A"; color: var(--lime-ink); font-weight: 700; margin-right: .45rem; }

/* ------------------------------------------------------------------- faq --- */
.faq { margin-top: 2.2rem; border-top: 2px solid var(--line-lt); }
.faq details { border-bottom: 2px solid var(--line-lt); }
.faq summary {
  cursor: pointer; list-style: none;
  padding: 1.15rem 2.6rem 1.15rem 0;
  position: relative;
  font-weight: 600; font-size: 1.04rem; color: var(--ink);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: ""; position: absolute; right: .4rem; top: 50%;
  width: 15px; height: 3px; background: var(--lime-ink);
  transform: translateY(-50%);
}
.faq summary::before {
  content: ""; position: absolute; right: 1.1rem; top: 50%;
  width: 3px; height: 15px; background: var(--lime-ink);
  transform: translateY(-50%);
  transition: opacity .16s ease;
}
.faq details[open] summary::before { opacity: 0; }
.faq-a { padding: 0 0 1.3rem; }
.faq-a p { margin: 0; }

/* ----------------------------------------------------------------- quote --- */
.quote-in { display: grid; grid-template-columns: minmax(0, .82fr) minmax(0, 1.18fr); gap: clamp(2rem, 4vw, 3.4rem); }
.quote-copy p { color: var(--mist); }
.quote-alt { font-size: .97rem; }
.quote-alt a { color: var(--lime-hi); font-weight: 600; }

.qform { display: grid; gap: 1rem; }
.f-row { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
.f-field { display: flex; flex-direction: column; gap: .4rem; }
.f-field label {
  font-weight: 600; font-size: .78rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--lime-hi);
}
.f-field input, .f-field select, .f-field textarea {
  font: 400 1rem/1.5 var(--ui);
  background: var(--coal-2); color: var(--white);
  border: 2px solid #2E3626;
  padding: .8rem .85rem;
  width: 100%;
}
.f-field textarea { resize: vertical; }
.f-field input::placeholder, .f-field textarea::placeholder { color: #7E866F; }
.f-field .is-bad { border-color: #F09393; }
.f-err { margin: 0; font-size: .85rem; color: #F0B3B3; }

/* Honeypot. Off-screen rather than display:none — some bots skip hidden fields
   but happily tick one they can "see". */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }

.form-note { margin: .3rem 0 0; font-size: .95rem; min-height: 1.4em; color: var(--mist); }
.form-note.ok { color: var(--lime-hi); font-weight: 600; }
.form-note.bad { color: #F0B3B3; font-weight: 600; }

/* ---------------------------------------------------------------- footer --- */
.foot { background: var(--black); color: var(--mist); border-top: var(--key) solid var(--lime); padding-top: clamp(2.6rem, 5vw, 4rem); }
/* The badge sits on the SAME vertical line as the header logo — both are the
   first child inside .wrap, so an `auto` first track starting at the wrap's
   padding edge puts them in the same column down the page. A fixed 250px track
   with the badge centred inside it looked arbitrary, because it lined up with
   nothing.

   align-items:center rather than start: the badge is taller than either text
   column, so centring the whole row is what gives the badge and the copy a
   shared centre line instead of a ragged top edge. */
.foot-in {
  display: grid;
  grid-template-columns: auto repeat(2, minmax(0, 1fr));
  gap: 2rem 3rem;
  align-items: center;
}
.foot-brand { justify-self: start; }
.foot-brand img { width: 190px; height: auto; margin: 0; }
.foot h2 { font-size: 1.15rem; color: var(--white); margin-bottom: .85rem; }
.foot p { margin: 0 0 .5rem; font-size: .95rem; }
.foot a { color: var(--lime-hi); text-decoration: none; font-weight: 600; }
@media (hover: hover) { .foot a:hover { text-decoration: underline; } }
.foot-tag {
  margin: clamp(2rem, 4vw, 3rem) 0 0;
  border-top: 2px solid var(--line-dk);
  padding: 1.3rem var(--pad);
  text-align: center;
  font: 400 clamp(1.1rem, 2.2vw, 1.5rem)/1 var(--dsp);
  text-transform: uppercase; letter-spacing: .05em;
  color: var(--lime-hi);
}
.foot-goat { margin: 0; padding: 0 var(--pad) .4rem; text-align: center; font-size: .88rem; color: var(--dim); }
.foot-legal { margin: 0; padding: .3rem var(--pad) 1.5rem; text-align: center; font-size: .82rem; color: #6F7765; }

/* ------------------------------------------------------- sticky call bar --- */
.callbar { display: none; }

/* ============================================================== responsive === */
@media (max-width: 1040px) {
  .stump-in, .mark-in, .quote-in { grid-template-columns: 1fr; }
  .mark-fig { order: -1; }
  .mark-fig img { max-width: 520px; }
  /* Straight from four to two. Eight tiles across three columns leaves a
     two-tile orphan row, which is the exact ragged edge this grid replaced. */
  .gal { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 900px) {
  :root { --head: 96px; }
  .burger { display: grid; }
  .nav-links { display: block; }

  /* Full-viewport drawer. It carries the badge on its own black tile, the
     links, the number set large and the trust line — the same palette as the
     page rather than a blank green panel. */
  .nav {
    position: fixed; inset: 0; z-index: 80;
    background: var(--coal);
    border-left: var(--key) solid var(--lime);
    transform: translateX(100%);
    transition: transform .26s cubic-bezier(.22,.61,.36,1);
    overflow-y: auto;
    padding: 1.1rem 1.4rem 2rem;
    display: flex; flex-direction: column; gap: 1.4rem;
    visibility: hidden;
  }
  .nav.is-open { transform: none; visibility: visible; }

  .nav-head { display: grid; grid-template-columns: auto 1fr; gap: .9rem; align-items: center; position: relative; }
  .nav-close {
    position: absolute; top: -.2rem; right: -.4rem;
    width: 44px; height: 44px; background: transparent; border: 2px solid var(--lime); cursor: pointer;
    display: grid; place-items: center;
  }
  .nav-close svg { width: 20px; height: 20px; fill: var(--lime-hi); }
  .nav-logo img { width: 86px; height: auto; }
  /* The close button is absolutely positioned in this corner, so the name has
     to be kept out from under it — at 360px "ADKINS TREE & STUMP" ran 38px
     past its left edge. */
  .nav-head-txt { padding-right: 54px; }
  .nav-head-txt strong { display: block; font-family: var(--dsp); font-weight: 400; text-transform: uppercase; font-size: clamp(1.05rem, 4.6vw, 1.28rem); color: var(--white); line-height: 1.05; letter-spacing: .02em; }
  .nav-head-txt span { display: block; margin-top: .3rem; font-size: .82rem; color: var(--lime-hi); letter-spacing: .1em; text-transform: uppercase; }

  .nav-links { display: grid; gap: 0; border-top: 2px solid var(--line-dk); }
  .nav-links a {
    display: block; padding: .95rem 0; font-size: 1rem;
    border-bottom: 2px solid var(--line-dk);
    border-top: 0;
  }
  .nav-links a[aria-current="true"] { border-bottom-color: var(--line-dk); color: var(--lime-hi); }

  .nav-foot { display: block; margin-top: auto; }
  .nav-lede { margin: 0 0 .3rem; color: var(--orange); font-weight: 700; letter-spacing: .1em; text-transform: uppercase; font-size: .82rem; }
  .nav-phone { display: block; font: 400 2rem/1 var(--dsp); color: var(--white); text-decoration: none; letter-spacing: .02em; }
  .nav-trust { margin: .7rem 0 0; font-size: .84rem; color: var(--dim); letter-spacing: .04em; text-transform: uppercase; }
  .nav a.nav-cta { display: flex; width: 100%; padding: 1.05rem; font-size: .95rem; }

  /* Stack the two sliders. Side by side on a phone they would be about 160px
     wide each and the wipe would be unusable. */
  .ba-pair { grid-template-columns: 1fr; gap: 2.4rem; max-width: 480px; }

  .proof-in { grid-template-columns: repeat(2, 1fr); }
  .proof-in li + li { box-shadow: none; }
  .proof-in li { border-top: 1px solid var(--line-dk); }
  .proof-in li:nth-child(-n+2) { border-top: 0; }
  .proof-in li:nth-child(2n) { box-shadow: -1px 0 0 var(--line-dk); }

  .foot-in { grid-template-columns: 1fr; }
  .foot-brand img { width: 160px; }

  /* Sticky call bar. Hidden while the drawer is open — it would sit over the
     drawer's own, larger number. */
  .callbar {
    display: block;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 75;
    background: var(--orange); color: var(--black);
    text-align: center; text-decoration: none;
    font: 700 1rem/1 var(--ui); letter-spacing: .1em; text-transform: uppercase;
    padding: 1.05rem;
    border-top: 3px solid var(--black);
  }
  body.drawer-open .callbar { display: none; }
  body { padding-bottom: 52px; }
}

@media (max-width: 700px) {
  .util-in { justify-content: center; }
  /* On a phone the credential strapline is noise and the number is the point. */
  .util-cred { display: none; }
  .f-row { grid-template-columns: 1fr; }
  .hero-btns .btn { width: 100%; }
  .stump-steps li { gap: 0 .7rem; }
  .lb-prev, .lb-next { top: auto; bottom: 1rem; transform: none; }
  .lb-prev { left: 1rem; }
  .lb-next { right: 1rem; }
}

@media (max-width: 420px) {
  .brand img { height: 34px; }
  .banner { font-size: .72rem; letter-spacing: .12em; }
}

/* =================================================================== grind ===
   ANIMATION 1 OF 2 — and it is the real process, not a saw cutting sideways.

   How the machine actually works: the cutter is a HORIZONTAL wheel spinning at
   around 1,000 rpm carrying 8–16 carbide teeth. The operator sets it down a
   couple of inches in from one edge of the stump, sweeps it SIDE TO SIDE across
   the face, drops it a few inches, sweeps back, and repeats — shaving the stump
   off in layers until it and the root flare are below grade. The waste is the
   mulch pile that ends up in the hole.

   So the scene is built as FOUR COMPLETE STUMPS stacked on top of one another,
   each one drawn as the stump would look at that stage, shortest at the back.
   Each pass wipes the front-most one away in the direction the wheel is
   travelling, revealing the shorter stump behind it with a fresh cut face. That
   construction is what avoids the usual clipping mess: no layer ever has to
   half-hide another, because every layer is a whole stump in its own right.

   Passes alternate direction the way an operator's arms do — right to left,
   then left to right — and the wheel drops 32 units between each.

   It is NOT scroll-driven and the section does not pin. Driving a sequence from
   scroll position means the page has to stop moving for it to read, which feels
   like the page has frozen rather than like an effect.

   Base CSS *is* the fallback: an untouched stump with its rings, no wheel, no
   crater. Nothing moves until script adds .is-playing, which it does not do
   under prefers-reduced-motion, without JS, or without IntersectionObserver.
   ============================================================================ */
.grind-scene { transition: opacity .42s ease; }
.grind.is-resetting .grind-scene { opacity: 0; }

/* ---- the stump ---- */
.side     { fill: #7A5735; }
.side-lit { fill: #8D6640; }              /* sunlit face, camera-left */
.bark     { fill: none; stroke: #46311B; stroke-width: 2.5; }
.cap      { fill: #C8A06A; }              /* the cut face */
.cap-edge { fill: none; stroke: #6E4E2C; stroke-width: 2; }
.ring     { fill: none; stroke: #9A7442; stroke-width: 2; opacity: .95; }
.pith     { fill: #7A5735; stroke: none; }

/* ---- the ground ---- */
.turf   { fill: #2C3A1C; }
.soil   { fill: #221A10; }
.crater { fill: #2E2416; opacity: 0; }
.mulch  { fill: #A9834E; opacity: 0; }
.mulch-fleck { fill: #C9A468; opacity: 0; }

/* ---- the machine ---- */
.boom   { fill: #3A4132; stroke: #545C48; stroke-width: 2; }
.cyl    { fill: none; stroke: #98A188; stroke-width: 3; stroke-linecap: round; }
.disc   { fill: #23271E; stroke: #6E7A5C; stroke-width: 2.5; }
.hub    { fill: #4A5340; }
.tooth  { fill: var(--lime-hi); }
.rig    { opacity: 0; }
.chip   { fill: #D8B77E; opacity: 0; }

/* transform-box:fill-box is load-bearing on every one of these. The CSS default
   for an SVG element is view-box, so a rotate() would swing the wheel around
   the corner of the viewBox — a 26-unit disc orbiting 200 units away — instead
   of around its own hub, and a scale() would fling the chips off-frame. */
.wheel, .chip { transform-box: fill-box; transform-origin: 50% 50%; }

/* ---- 1. the rings draw, pith outward, before anything else happens ---- */
.grind.is-playing .ring {
  stroke-dasharray: var(--len);
  stroke-dashoffset: var(--len);
  animation: ring-draw .45s ease-out var(--d, 0s) forwards;
}
@keyframes ring-draw { to { stroke-dashoffset: 0; } }

/* ---- 2. the rig: four sweeps, dropping 32 between each ----
   Percentages are (t - 0.70s) / 3.5s. The pauses at each end of a sweep are
   where the operator drops the wheel for the next pass. */
.grind.is-playing .rig { animation: rig-run 3.5s linear .7s forwards; }
@keyframes rig-run {
  0%     { opacity: 0; transform: translate(200px, -40px); }
  5.7%   { opacity: 1; transform: translate(100px, -20px); }   /* swings in   */
  8.6%   { opacity: 1; transform: translate(90px, 0); }        /* set down    */
  25.7%  { opacity: 1; transform: translate(-90px, 0); }       /* pass 1  <-- */
  28.6%  { opacity: 1; transform: translate(-90px, 32px); }    /* drop        */
  45.7%  { opacity: 1; transform: translate(90px, 32px); }     /* pass 2  --> */
  48.6%  { opacity: 1; transform: translate(90px, 64px); }     /* drop        */
  65.7%  { opacity: 1; transform: translate(-90px, 64px); }    /* pass 3  <-- */
  68.6%  { opacity: 1; transform: translate(-90px, 96px); }    /* drop        */
  85.7%  { opacity: 1; transform: translate(90px, 96px); }     /* pass 4  --> */
  91.4%  { opacity: 1; transform: translate(150px, 60px); }    /* lifts off   */
  100%   { opacity: 0; transform: translate(230px, 10px); }    /* swings out  */
}

/* ~1,000 rpm is about 17 turns a second. Nothing legible survives that, so the
   wheel is geared to read as fast rather than to be accurate — the teeth would
   strobe into a grey ring at the real rate. */
.grind.is-playing .wheel { animation: wheel-spin .26s linear .7s 14; }
@keyframes wheel-spin { to { transform: rotate(360deg); } }

/* ---- 3. each pass wipes the front-most stump away, in its own direction ----
   The clip rects are 610 wide so the trailing edge never enters the stump:
   only the leading edge ever sweeps across it. */
.grind.is-playing .wipe-l { animation: wipe-l .5s linear var(--d) forwards; }
.grind.is-playing .wipe-r { animation: wipe-r .5s linear var(--d) forwards; }
@keyframes wipe-l { to { transform: translateX(-220px); } }
@keyframes wipe-r { to { transform: translateX(220px); } }

/* ---- 4. chips. They live inside .rig, so they always spray off the wheel
     wherever it happens to be, rather than from a fixed spot on the stump. ---- */
.grind.is-playing .chip { animation: chip-spray .5s ease-out var(--d) infinite; }
@keyframes chip-spray {
  0%   { opacity: 0; transform: translate(0, 0) scale(.4); }
  15%  { opacity: 1; }
  100% { opacity: 0; transform: translate(var(--dx), var(--dy)) scale(1); }
}

/* ---- 5. below grade: the crater, then the mulch that came out of it ---- */
.grind.is-playing .crater { animation: fade-in .45s ease-out 3.55s forwards; }
.grind.is-playing .mulch  { animation: fade-in .6s ease-out 3.8s forwards; }
.grind.is-playing .mulch-fleck { animation: fade-in .5s ease-out var(--d) forwards; }
@keyframes fade-in { to { opacity: 1; } }

.grind.is-playing .grass-blade {
  transform-box: fill-box; transform-origin: 50% 100%;
  animation: grass-up .5s ease-out var(--d) backwards;
}
@keyframes grass-up { from { transform: scaleY(0); } to { transform: scaleY(1); } }

/* ------------------------------------------------------ before/after wipe ---
   ANIMATION 2 OF 2. The divider sweeps once when the pair first scrolls into
   view, then it is yours to drag. Driven from script by writing --p, so the
   clip, the divider line and the grip all track one value and cannot drift. */
.ba.is-sweeping .ba-top, .ba.is-sweeping .ba-line, .ba.is-sweeping .ba-grip {
  transition: none;
}

