@import url('https://fonts.googleapis.com/css2?family=Barlow+Condensed:wght@600;700;800&family=Open+Sans:wght@400;600;700;800&family=Roboto+Condensed:wght@400;700&display=swap');

/* =============================================================
   Dutchman Tree Service — Recent Projects widget
   -------------------------------------------------------------
   Every rule is scoped under .dtsp (or .dtsp-lb for the lightbox,
   which is portaled to <body> so host overflow/transform cannot
   clip it). Design tokens live on .dtsp, not :root, so the host
   theme's variables are neither read nor overwritten.
   ============================================================= */

/* Tokens are declared for BOTH scopes. The lightbox is portaled to <body>, so
   it sits outside .dtsp and inherits none of these; any token used in lightbox
   CSS silently resolved to nothing. That is why the before/after drag handle
   rendered transparent: `background: var(--dts-bone-50)` had no value there.
   Presentation (font, colour, background) stays on .dtsp only, further down,
   so the lightbox keeps its own dark treatment. */
.dtsp, .dtsp-lb, .dtsp-rv {
  --dts-forest-900: #102A1C;
  --dts-forest-700: #234C30;
  --dts-forest-600: #2F6A3E;
  --dts-forest-500: #3E8A4F;
  --dts-forest-300: #A8CFAE;
  --dts-forest-100: #EEF5EE;
  --dts-rust-600:   #B84A18;
  --dts-rust-700:   #8C3A11;
  --dts-bone-50:    #FAF7F0;
  --dts-bone-100:   #F2ECDD;
  --dts-bark-900:   #14110D;
  --dts-bark-700:   #423A32;
  --dts-bark-500:   #6B5F53;
  --dts-bark-200:   #C9BFB1;
  --dts-bark-100:   #E8E2D6;

  --dtsp-bg:        var(--dts-bone-50);
  --dtsp-surface:   #FFFFFF;
  --dtsp-subtle:    var(--dts-bone-100);
  --dtsp-fg1:       var(--dts-bark-900);
  --dtsp-fg2:       var(--dts-bark-700);
  --dtsp-fg3:       var(--dts-bark-500);
  --dtsp-border:    var(--dts-bark-200);
  --dtsp-border-sub:var(--dts-bark-100);
  --dtsp-primary:   var(--dts-forest-600);
  --dtsp-primary-h: var(--dts-forest-700);
  --dtsp-accent:    var(--dts-rust-600);

  --dtsp-display: "Barlow Condensed", "Arial Narrow", Impact, sans-serif;
  --dtsp-body:    "Open Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --dtsp-accent-f:"Roboto Condensed", "Barlow Condensed", sans-serif;

  --dtsp-r-md: 4px;
  --dtsp-r-lg: 8px;
  --dtsp-r-pill: 999px;
  --dtsp-sh-sm: 0 1px 2px rgba(20,17,13,.08);
  --dtsp-sh-md: 0 4px 12px rgba(20,17,13,.10);
  --dtsp-sh-lg: 0 12px 32px rgba(20,17,13,.16);
  --dtsp-ease: cubic-bezier(.2,.8,.2,1);

  --dtsp-height: 680px;
}

.dtsp {
  font-family: var(--dtsp-body);
  font-size: 16px;
  line-height: 1.55;
  color: var(--dtsp-fg1);
  background: var(--dtsp-bg);
  text-align: left;
  -webkit-font-smoothing: antialiased;
}

/* ---------- reset ----------
   Host themes style aggressively, so we neutralise everything we render. The
   selector form here is exact and both halves matter:

     .dtsp :where(button)   ->  specificity (0,1,0)

   `.dtsp` keeps its full weight so these rules BEAT a host theme's bare element
   selectors (`img {}` = (0,0,1), `a {}` = (0,0,1)). `:where()` strips the
   element's own weight so these rules LOSE to our component classes
   (`.dtsp-chip` = (0,1,0), later in the file, so source order hands it the win).

   Get either half wrong and something breaks:
     `.dtsp button`          (0,1,1) beats .dtsp-chip -> our own buttons go bare
     `:where(.dtsp) :where(button)` (0,0,0) loses to host `img{}` -> theme leaks in
   Both of those were live bugs before this comment existed. */
.dtsp, .dtsp :where(*), .dtsp :where(*)::before, .dtsp :where(*)::after { box-sizing: border-box; }
/* `color: inherit` matters here: a host theme's `h2 { color: … }` targets the
   element directly, which beats the colour our container merely passes down. */
.dtsp :where(p, h1, h2, h3, h4, h5, h6, ul, ol, li, figure, blockquote) {
  margin: 0; padding: 0; max-width: none; quotes: none;
  font-size: inherit; font-weight: inherit; font-family: inherit;
  color: inherit; text-transform: none; letter-spacing: normal; line-height: inherit;
}
.dtsp :where(ul, ol, li) { list-style: none; }
.dtsp :where(button) {
  font: inherit; color: inherit; margin: 0; padding: 0; border: 0; border-radius: 0;
  background: none; cursor: pointer; text-transform: none; letter-spacing: normal;
  text-align: inherit; box-shadow: none; -webkit-appearance: none; appearance: none;
}
.dtsp :where(img) {
  max-width: 100%; display: block; border: 0; border-radius: 0;
  box-shadow: none; filter: none; opacity: 1;
}
.dtsp :where(a) {
  text-decoration: none; color: var(--dtsp-primary); background: none;
  text-shadow: none; transition: color 120ms var(--dtsp-ease);
}
.dtsp :where(a):hover { color: var(--dtsp-primary-h); text-decoration: underline; }
.dtsp :where(input) {
  font: inherit; color: inherit; margin: 0; border-radius: 0;
  -webkit-appearance: none; appearance: none;
}
.dtsp :where(svg) { display: inline-block; vertical-align: middle; }
.dtsp :focus-visible { outline: 2px solid var(--dtsp-primary); outline-offset: 2px; }

/* The UA stylesheet hides [hidden] with a bare `display:none` at specificity
   (0,1,0). Every component rule below that sets `display` outranks it, so
   `el.hidden = true` silently did nothing — the "Show more" button stayed on
   screen reading "(-11 left)" and the search clear button never went away.
   !important is the honest fix: hidden must win over any layout rule. */
.dtsp [hidden] { display: none !important; }

.dtsp-sr {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---------- top bar ---------- */
.dtsp-bar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap; padding: 0 0 16px;
}
.dtsp-bar-title {
  font-family: var(--dtsp-display); text-transform: uppercase; font-weight: 800;
  font-size: clamp(24px, 3vw, 34px); line-height: 1.08; letter-spacing: .01em; margin: 0;
}
.dtsp-bar-right { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }

.dtsp-badge {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--dtsp-surface); border: 1px solid var(--dtsp-border);
  border-radius: var(--dtsp-r-pill); padding: 7px 14px;
  color: var(--dtsp-fg1); box-shadow: var(--dtsp-sh-sm);
  transition: box-shadow 220ms var(--dtsp-ease); white-space: nowrap;
}
.dtsp-badge:hover { box-shadow: var(--dtsp-sh-md); color: var(--dtsp-fg1); text-decoration: none; }
.dtsp-badge .dtsp-num { font-weight: 800; font-size: 15px; }
.dtsp-badge .dtsp-count { color: var(--dtsp-fg3); font-family: var(--dtsp-accent-f); font-size: 13px; }
.dtsp-stars { color: #F4B400; letter-spacing: 1px; font-size: 14px; }

.dtsp-cta {
  font-family: var(--dtsp-display); font-weight: 700; text-transform: uppercase;
  letter-spacing: .08em; font-size: 14px; padding: 12px 24px;
  border-radius: var(--dtsp-r-md); background: var(--dtsp-accent); color: #fff;
  transition: background 220ms var(--dtsp-ease);
}
.dtsp-cta:hover { background: var(--dts-rust-700); color: #fff; text-decoration: none; }

/* ---------- controls ---------- */
.dtsp-controls { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; padding: 0 0 16px; }
.dtsp-search { position: relative; flex: 1 1 320px; min-width: 240px; }
.dtsp-search input {
  width: 100%; font-size: 16px; padding: 13px 46px 13px 16px;
  border: 1px solid var(--dtsp-border); border-radius: var(--dtsp-r-md);
  background: var(--dtsp-subtle); color: var(--dtsp-fg1);
}
.dtsp-search input:focus { outline: 2px solid var(--dtsp-primary); outline-offset: 2px; background: var(--dtsp-surface); }
.dtsp-search button {
  position: absolute; right: 5px; top: 50%; transform: translateY(-50%);
  background: var(--dtsp-primary); color: #fff; width: 38px; height: 38px;
  border-radius: var(--dtsp-r-md); display: grid; place-items: center;
}
.dtsp-search button:hover { background: var(--dtsp-primary-h); }
.dtsp-search .dtsp-clear {
  right: 50px; background: none; color: var(--dtsp-fg3); width: 28px; height: 28px;
}
.dtsp-search .dtsp-clear:hover { background: none; color: var(--dtsp-fg1); }

.dtsp-chips { display: flex; gap: 8px; flex-wrap: wrap; }
.dtsp-chip {
  font-family: var(--dtsp-accent-f); font-weight: 700; font-size: 12px;
  letter-spacing: .06em; text-transform: uppercase; padding: 8px 14px;
  border-radius: var(--dtsp-r-pill); background: var(--dtsp-surface);
  border: 1px solid var(--dtsp-border); color: var(--dtsp-fg2);
  transition: all 120ms var(--dtsp-ease); white-space: nowrap;
}
.dtsp-chip:hover { border-color: var(--dts-forest-300); }
.dtsp-chip[aria-pressed="true"] { background: var(--dtsp-primary); border-color: var(--dtsp-primary); color: #fff; }
.dtsp-chip .dtsp-n { opacity: .65; margin-left: 5px; font-weight: 400; }

.dtsp-note {
  font-family: var(--dtsp-accent-f); font-size: 13px; color: var(--dtsp-fg3);
  padding: 0 0 12px; display: flex; align-items: center; gap: 8px;
}
.dtsp-note button { color: var(--dtsp-primary); text-decoration: underline; font-size: 13px; }

/* ---------- layout ---------- */
.dtsp-layout {
  display: grid; grid-template-columns: minmax(400px, 520px) 1fr;
  height: var(--dtsp-height); min-height: 480px;
  border: 1px solid var(--dtsp-border-sub); border-radius: var(--dtsp-r-lg); overflow: hidden;
}
/* min-width:0 is load-bearing. A grid item defaults to min-width:auto, so the
   horizontally-scrolling reviews rail (24 cards wide) would set the pane's
   minimum and blow the column out to several thousand pixels — invisible
   because .dtsp-layout clips it, but Leaflet still sized its canvas to the
   overflowing box and rendered the wrong part of the world. */
.dtsp-pane {
  overflow-y: auto; padding: 20px; background: var(--dtsp-bg);
  scrollbar-width: thin; min-width: 0;
}
.dtsp-mapcol { position: relative; background: var(--dts-forest-100); min-width: 0; }
.dtsp-rail, .dtsp-cards { min-width: 0; }
/* !important, and it has to be. Leaflet reads the container's computed
   position at init and writes `position: relative` INLINE if it finds `static`.
   On the embed path this stylesheet is fetched by the script itself, so it can
   still be in flight at that moment -- Leaflet sees static, stamps the inline
   style, and the insets stop applying because the element is no longer
   positioned absolutely. The map then has zero height: no tiles, no pins. An
   important author declaration is the one thing that outranks an inline style.
   The theme enqueues this in the head, so it never hits the race; embeds do. */
.dtsp-map { position: absolute !important; inset: 0; }
.dtsp-mapfail {
  position: absolute; inset: 0; display: grid; place-items: center; text-align: center;
  font-family: var(--dtsp-accent-f); color: var(--dtsp-fg3); padding: 24px;
}

.dtsp-label {
  font-family: var(--dtsp-display); text-transform: uppercase; font-weight: 800;
  font-size: 20px; letter-spacing: .02em; margin: 0 0 12px;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
}
.dtsp-label a, .dtsp-label .dtsp-sub {
  font-family: var(--dtsp-accent-f); font-size: 12px; letter-spacing: .06em;
  text-transform: uppercase; font-weight: 700;
}
.dtsp-label .dtsp-sub { color: var(--dtsp-fg3); }

/* ---------- reviews rail ---------- */
.dtsp-rail { position: relative; margin-bottom: 28px; }
.dtsp-track {
  display: flex; gap: 12px; overflow-x: auto; scroll-behavior: smooth;
  padding-bottom: 6px; scrollbar-width: thin; scroll-snap-type: x proximity;
}
.dtsp-review {
  flex: 0 0 250px; scroll-snap-align: start; background: var(--dtsp-surface);
  border: 1px solid var(--dtsp-border); border-radius: var(--dtsp-r-md);
  padding: 14px; box-shadow: var(--dtsp-sh-sm); display: flex; flex-direction: column; gap: 9px;
  text-align: left; transition: box-shadow 220ms var(--dtsp-ease), border-color 220ms var(--dtsp-ease);
}
.dtsp-review.dtsp-clickable { cursor: pointer; }
.dtsp-review.dtsp-clickable:hover { box-shadow: var(--dtsp-sh-md); border-color: var(--dts-forest-300); }
.dtsp-review-top { display: flex; align-items: center; gap: 8px; }
.dtsp-review p {
  font-size: 13.5px; line-height: 1.5; color: var(--dtsp-fg2);
  display: -webkit-box; -webkit-line-clamp: 6; -webkit-box-orient: vertical; overflow: hidden;
}
.dtsp-review-who { display: flex; align-items: center; gap: 8px; margin-top: auto; }
.dtsp-avatar {
  width: 26px; height: 26px; border-radius: 50%; background: var(--dts-forest-500);
  color: #fff; display: grid; place-items: center; font-size: 11px; font-weight: 700; flex: none;
}
.dtsp-review-who span {
  font-family: var(--dtsp-accent-f); font-size: 13px; color: var(--dtsp-fg2); font-weight: 700;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dtsp-review-shots { display: flex; gap: 4px; }
.dtsp-review-shots img { width: 44px; height: 44px; object-fit: cover; border-radius: var(--dtsp-r-sm, 3px); }
/* The prev/next buttons live inside the label row rather than being absolutely
   positioned over it, which previously put them on top of the "Read all" link. */
.dtsp-rail-nav { display: flex; align-items: center; gap: 6px; flex: none; }
.dtsp-railbtn {
  width: 30px; height: 30px; border-radius: 50%;
  border: 1px solid var(--dtsp-border); background: var(--dtsp-surface);
  display: grid; place-items: center; box-shadow: var(--dtsp-sh-sm); color: var(--dtsp-fg2);
  transition: border-color 120ms var(--dtsp-ease), opacity 120ms var(--dtsp-ease);
}
.dtsp-railbtn:hover { border-color: var(--dts-forest-300); }
.dtsp-railbtn[disabled] { opacity: .3; cursor: default; }

/* ---------- project cards ---------- */
.dtsp-cards { display: flex; flex-direction: column; gap: 14px; }
.dtsp-card {
  background: var(--dtsp-surface); border: 1px solid var(--dtsp-border);
  border-radius: var(--dtsp-r-lg); overflow: hidden; cursor: pointer;
  box-shadow: var(--dtsp-sh-sm); display: grid; grid-template-columns: 160px 1fr;
  text-align: left; width: 100%;
  transition: box-shadow 220ms var(--dtsp-ease), transform 220ms var(--dtsp-ease), border-color 220ms var(--dtsp-ease);
}
.dtsp-card:hover { box-shadow: var(--dtsp-sh-md); transform: translateY(-2px); border-color: var(--dts-forest-300); }
.dtsp-card.dtsp-active { border-color: var(--dtsp-primary); box-shadow: var(--dtsp-sh-md); }
.dtsp-shot { position: relative; background: var(--dts-forest-100); min-height: 150px; overflow: hidden; }
.dtsp-shot img { width: 100%; height: 100%; object-fit: cover; }
.dtsp-shot-n {
  position: absolute; left: 8px; bottom: 8px; display: inline-flex; align-items: center; gap: 4px;
  background: rgba(20,17,13,.72); color: #fff; font-family: var(--dtsp-accent-f);
  font-size: 11px; font-weight: 700; padding: 3px 8px; border-radius: var(--dtsp-r-pill);
}
.dtsp-body { padding: 14px; display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.dtsp-svc {
  align-self: flex-start; font-family: var(--dtsp-accent-f); font-weight: 700; font-size: 10px;
  letter-spacing: .08em; text-transform: uppercase; color: #fff; padding: 3px 9px;
  border-radius: var(--dtsp-r-pill);
}
.dtsp-title {
  font-family: var(--dtsp-display); text-transform: uppercase; font-weight: 700;
  font-size: 17px; line-height: 1.12; letter-spacing: .02em; color: var(--dtsp-fg1);
}
.dtsp-meta {
  font-family: var(--dtsp-accent-f); font-size: 12px; color: var(--dtsp-fg3);
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
}
.dtsp-summary {
  font-size: 13px; line-height: 1.45; color: var(--dtsp-fg2);
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.dtsp-quote {
  margin-top: 2px; padding-top: 8px; border-top: 1px dashed var(--dtsp-border-sub);
  font-size: 12.5px; color: var(--dtsp-fg2); display: flex; gap: 8px; align-items: flex-start;
}
.dtsp-quote .dtsp-stars { font-size: 12px; flex: none; }
.dtsp-quote span { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }

.dtsp-more {
  margin: 18px auto 4px; display: block; font-family: var(--dtsp-display);
  text-transform: uppercase; font-weight: 700; letter-spacing: .08em; font-size: 13px;
  padding: 12px 28px; border: 1px solid var(--dtsp-primary); color: var(--dtsp-primary);
  border-radius: var(--dtsp-r-md); background: var(--dtsp-surface);
}
.dtsp-more:hover { background: var(--dtsp-primary); color: #fff; }
.dtsp-empty { color: var(--dtsp-fg3); font-family: var(--dtsp-accent-f); padding: 32px; text-align: center; }
.dtsp-skel { height: 150px; border-radius: var(--dtsp-r-lg); background:
  linear-gradient(90deg, var(--dtsp-subtle) 25%, #fff 50%, var(--dtsp-subtle) 75%);
  background-size: 400% 100%; animation: dtsp-shimmer 1.4s infinite; }
@keyframes dtsp-shimmer { from { background-position: 100% 0 } to { background-position: 0 0 } }

/* ---------- map pins ---------- */
.dtsp-pin {
  width: 28px; height: 28px; border-radius: 50% 50% 50% 0; transform: rotate(-45deg);
  border: 2px solid #fff; box-shadow: var(--dtsp-sh-md); display: grid; place-items: center;
}
.dtsp-pin svg { transform: rotate(45deg); width: 14px; height: 14px; color: #fff; }
.dtsp-pin.dtsp-pin-review { border-radius: 50%; transform: none; }
.dtsp-pin.dtsp-pin-review svg { transform: none; }
.dtsp .marker-cluster-small, .dtsp .marker-cluster-medium, .dtsp .marker-cluster-large,
.dtsp-mapcol .marker-cluster-small, .dtsp-mapcol .marker-cluster-medium, .dtsp-mapcol .marker-cluster-large {
  background: rgba(47,106,62,.3);
}
.dtsp-mapcol .marker-cluster div {
  background: var(--dtsp-primary); color: #fff; font-family: var(--dtsp-body); font-weight: 800;
}
.dtsp-mapcol .leaflet-popup-content-wrapper { border-radius: var(--dtsp-r-md); }
.dtsp-mapcol .leaflet-popup-content { margin: 12px 14px; font-family: var(--dtsp-body); }
.dtsp-pop-title {
  font-family: var(--dtsp-display); text-transform: uppercase; font-weight: 700;
  font-size: 15px; color: var(--dtsp-fg1); margin-bottom: 2px; line-height: 1.15;
}
.dtsp-pop-meta { font-family: var(--dtsp-accent-f); font-size: 12px; color: var(--dtsp-fg3); }
.dtsp-pop-quote { margin-top: 6px; font-size: 12.5px; color: var(--dtsp-fg2); line-height: 1.45; }
.dtsp-pop-btn {
  margin-top: 8px; font-family: var(--dtsp-accent-f); font-weight: 700; font-size: 12px;
  text-transform: uppercase; letter-spacing: .06em; color: var(--dtsp-primary); text-decoration: underline;
}

/* ---------- lightbox (portaled to <body>) ---------- */
.dtsp-lb {
  position: fixed; inset: 0; z-index: 2147483000; display: none; overflow: hidden;
  background: rgba(11,26,18,.985);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  font-family: "Open Sans", -apple-system, "Segoe UI", sans-serif; color: #fff;
}
.dtsp-lb.dtsp-open { display: grid; grid-template-rows: auto minmax(0, 1fr) auto; }
.dtsp-lb * { box-sizing: border-box; }
.dtsp-lb-head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;
  padding: 16px 20px; border-bottom: 1px solid rgba(255,255,255,.14);
}
.dtsp-lb-title {
  font-family: "Barlow Condensed", "Arial Narrow", Impact, sans-serif;
  text-transform: uppercase; font-weight: 800; font-size: 22px; line-height: 1.1; margin: 0;
}
.dtsp-lb-meta {
  font-family: "Roboto Condensed", sans-serif; font-size: 13px;
  color: rgba(255,255,255,.72); margin-top: 2px;
}
.dtsp-lb-close {
  background: rgba(255,255,255,.12); color: #fff; width: 40px; height: 40px; flex: none;
  border-radius: 50%; display: grid; place-items: center; border: 0; cursor: pointer; font-size: 22px;
}
.dtsp-lb-close:hover { background: rgba(255,255,255,.24); }
/* The image is positioned against the stage rather than sized with
   max-height:100%. A percentage max-height needs a definite containing height,
   which a 1fr grid row does not reliably provide — the photo rendered at its
   natural 900px and covered the thumbnail strip. Insets + object-fit sidestep
   the whole question. */
.dtsp-lb-stage { position: relative; min-height: 0; overflow: hidden; }
.dtsp-lb-stage img {
  /* Width/height must be explicit: on an absolutely-positioned replaced element
     `auto` resolves to the image's intrinsic size and the insets are ignored. */
  position: absolute; top: 16px; left: 16px;
  width: calc(100% - 32px); height: calc(100% - 32px);
  object-fit: contain; border-radius: 4px;
}
/* z-index, because the stage content sits between the two buttons in the DOM:
   prev, then the photo (or the comparison slider), then next. All are
   positioned with z-index auto, so paint order is document order -- next ended
   up above the photo and prev below it, and only the left button was dead to
   clicks. Lifting both buttons out of that ordering fixes prev without moving
   any markup. */
.dtsp-lb-nav {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 2;
  background: rgba(255,255,255,.14); color: #fff; width: 46px; height: 46px;
  border-radius: 50%; display: grid; place-items: center; border: 0; cursor: pointer;
}
.dtsp-lb-nav:hover { background: rgba(255,255,255,.28); }
.dtsp-lb-prev { left: 16px; } .dtsp-lb-next { right: 16px; }
.dtsp-lb-foot { padding: 10px 20px 18px; }
.dtsp-lb-cap {
  font-size: 13.5px; color: rgba(255,255,255,.8); text-align: center;
  margin-bottom: 10px; min-height: 20px;
}
.dtsp-lb-strip { display: flex; gap: 8px; overflow-x: auto; justify-content: flex-start; padding-bottom: 4px; }
.dtsp-lb-strip img {
  width: 66px; height: 50px; object-fit: cover; border-radius: 3px; cursor: pointer;
  opacity: .5; border: 2px solid transparent; flex: none; transition: opacity 120ms;
}
.dtsp-lb-strip img:hover { opacity: .85; }
.dtsp-lb-strip img.dtsp-on { opacity: 1; border-color: #fff; }

/* ---------- responsive ---------- */
@media (max-width: 900px) {
  .dtsp-layout { grid-template-columns: 1fr; height: auto; }
  .dtsp-mapcol { height: 360px; order: -1; }
  .dtsp-pane { max-height: none; overflow: visible; }
  .dtsp-card { grid-template-columns: 120px 1fr; }
  .dtsp-shot { min-height: 130px; }
  .dtsp-lb-nav { width: 38px; height: 38px; }
  .dtsp-lb-prev { left: 6px; } .dtsp-lb-next { right: 6px; }
  /* Five stacked chips ate half the screen; scroll them on one line instead. */
  .dtsp-chips {
    flex-wrap: nowrap; overflow-x: auto; width: 100%;
    scrollbar-width: none; -ms-overflow-style: none;
    padding-bottom: 2px; scroll-snap-type: x proximity;
  }
  .dtsp-chips::-webkit-scrollbar { display: none; }
  .dtsp-chip { flex: none; scroll-snap-align: start; }
}
@media (max-width: 520px) {
  .dtsp-card { grid-template-columns: 1fr; }
  .dtsp-shot { min-height: 180px; }
  .dtsp-bar { flex-direction: column; align-items: flex-start; }
}
@media (prefers-reduced-motion: reduce) {
  .dtsp *, .dtsp-lb * { animation-duration: .01ms !important; transition-duration: .01ms !important; }
  .dtsp-track { scroll-behavior: auto; }
}

/* ---------- before/after comparison ----------
   Two images stacked in one frame; the "after" is revealed by a clip whose
   width follows a range input. The input is the real control (keyboard,
   screen readers, platform touch handling) and is visually replaced by the
   divider drawn over it. */
/* Fills the lightbox stage and centres inside it. The frame takes its height
   from the grid row and derives width from the photo's aspect ratio, so a tall
   drone portrait is bounded by the stage rather than stretching to full width
   and running off the bottom (which it did: 1400x3043 in a 900px stage). */
.dtsp-ba {
  position: absolute; inset: 16px;
  display: grid; grid-template-rows: minmax(0, 1fr) auto;
  justify-items: center; align-items: center; gap: 10px;
}
.dtsp-ba-frame {
  position: relative;
  height: 100%;
  width: auto;
  max-width: 100%;
  overflow: hidden;
  border-radius: 4px;
  background: var(--dts-forest-900);
  touch-action: none;          /* dragging pans the divider, not the page */
  user-select: none;
  cursor: ew-resize;
}
.dtsp-ba-frame img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
  pointer-events: none;
}
/* Passthrough. The reveal is done with clip-path on the after image itself, so
   both images stay at full frame size and remain perfectly registered as the
   divider moves. */
.dtsp-ba-clip { position: absolute; inset: 0; }
/* Holds the After label only. It must not swallow drags meant for the
   frame, and it has no photo of its own to show. */
.dtsp-ba-clip-after { pointer-events: none; }
.dtsp-ba-divider {
  position: absolute; top: 0; bottom: 0; left: 50%;
  width: 2px; margin-left: -1px;
  background: rgba(250,247,240,.9);
  pointer-events: none;
  box-shadow: 0 0 0 1px rgba(16,42,28,.35);
}
.dtsp-ba-divider span {
  position: absolute; top: 50%; left: 50%;
  transform: translate(-50%,-50%);
  width: 40px; height: 40px; border-radius: 50%;
  background: var(--dts-bone-50);
  box-shadow: 0 2px 10px rgba(16,42,28,.45);
}
.dtsp-ba-divider span::before,
.dtsp-ba-divider span::after {
  content: ""; position: absolute; top: 50%; width: 0; height: 0;
  border-top: 5px solid transparent; border-bottom: 5px solid transparent;
  transform: translateY(-50%);
}
.dtsp-ba-divider span::before { left: 9px; border-right: 7px solid var(--dts-forest-700); }
.dtsp-ba-divider span::after { right: 9px; border-left: 7px solid var(--dts-forest-700); }

/* The control itself: full-frame hit area, invisible, but still focusable. */
.dtsp-ba-range {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  margin: 0; padding: 0;
  opacity: 0;
  cursor: ew-resize;
  -webkit-appearance: none; appearance: none;
  background: none;
}
.dtsp-ba-range:focus-visible ~ .dtsp-ba-divider span {
  outline: 3px solid var(--dts-rust-500);
  outline-offset: 3px;
}

.dtsp-ba-tag {
  position: absolute; top: 14px;
  font-family: var(--dtsp-accent-f);
  font-size: 10px; font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase;
  padding: 5px 10px; border-radius: var(--dtsp-r-pill);
  background: rgba(16,42,28,.78); color: var(--dts-bone-50);
  pointer-events: none;
}
/* Matches the image order: before occupies the left of the frame. */
.dtsp-ba-tag-before { left: 14px; }
.dtsp-ba-tag-after { right: 14px; }

.dtsp-ba-label {
  margin-top: 10px;
  font-family: var(--dtsp-accent-f);
  font-size: 12px; letter-spacing: .1em; text-transform: uppercase;
  color: rgba(250,247,240,.75);
  text-align: center;
}

/* Card badge so the comparison is discoverable before opening it. */
.dtsp-shot-ba {
  position: absolute; left: 8px; top: 8px;
  background: var(--dts-rust-600); color: #fff;
  font-family: var(--dtsp-accent-f); font-size: 10px; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase;
  padding: 3px 8px; border-radius: var(--dtsp-r-pill);
}

/* Inline variant: a comparison rendered inside a card media well rather than
   the lightbox stage. The well already has its own aspect ratio, so the frame
   fills it instead of sizing to the photo, and the caption is dropped because
   the card carries its own heading. */
.dtsp-ba-inline { position: absolute; inset: 0; display: block; }
.dtsp-ba-inline .dtsp-ba-frame {
  width: 100%; height: 100%;
  border-radius: 0;
}
/* Uncropped variant: the frame keeps the photo's aspect ratio and the host well
   is sized to match, so a tall drone portrait is shown whole rather than having
   its middle third cropped out by a 4/3 card well. */
.dtsp-ba-uncropped .dtsp-ba-frame { aspect-ratio: var(--dtsp-ba-ar) !important; height: auto; }
.dtsp-ba-uncropped img { object-fit: contain; background: var(--dts-forest-900); }
.dtsp-ba-inline .dtsp-ba-label { display: none; }
/* Bottom, not top: the card's own category chip occupies the top-left corner
   and the "After" tag landed underneath it. */
.dtsp-ba-inline .dtsp-ba-tag {
  top: auto; bottom: 10px;
  font-size: 9px; padding: 4px 8px;
}
.dtsp-ba-inline .dtsp-ba-divider span { width: 32px; height: 32px; }

/* ---------- feature card: full-width row, media beside the copy ----------
   A portrait before/after cannot work inside a 4/3 well, and at span-8 its true
   ratio would be nearly 1800px tall. So the feature card takes the full row and
   puts the media in a fixed column beside the text, where the photo can run
   full height at its real proportions. */
/* Height first, width second. A fixed-width media column would resolve its
   height from the row, and the row is sized by the copy beside it -- which is
   how a 1200px-tall drone photo ended up showing as a 110px sliver. So give the
   media a definite height and let `aspect-ratio` compute the width; `auto` on
   the track then sizes the column to whatever that comes out to. --dtsp-ba-ar
   arrives inline from PHP, so this is right on first paint, before any JS. */
/* Eight of twelve, not the whole row. Full width left the copy column far
   wider than the text needs and pushed a card down into the next row for
   nothing; at span 8 a normal card sits beside it. */
.card.card-feature { grid-column: span 8; display: grid; grid-template-columns: minmax(200px, 300px) 1fr; }
/* Width fixed, height taken from the row. Deriving the height from the ratio
   instead left the media stopping partway down while the card beside it -- the
   one that sets the row height -- ran on, so a quarter of the card was empty.
   The photo is contained rather than cropped, so the whole survey still shows;
   it letterboxes against the dark green instead of losing its top and bottom. */
.card.card-feature .card-media {
  aspect-ratio: auto;
  align-self: stretch;
  height: auto; min-height: 380px;
  width: auto;
}
.card.card-feature .dtsp-ba img {
  object-fit: contain !important;
  /* White, not the dark green: the labels are a translucent green pill, so on a
     green band they read as a shape rather than as text. White also lets the
     letterbox disappear into the card instead of framing it. The lightbox keeps
     the dark fill -- it sits on a dark backdrop, where white would glare. */
  background: #fff;
}
/* Opaque here so the pills sit crisply on the white fill wherever the photo
   ends, rather than washing out to pale green. */
.card.card-feature .dtsp-ba-tag {
  background: var(--dts-forest-900);
  z-index: 2;
}
/* Wide enough to swallow the letterbox. The column is a little wider than the
   old 300px and the photo covers rather than fits, so it reaches the top and
   bottom edges; the copy beside it simply wraps a line or two further down,
   which the card has room for. Only above 960px, where the feature card spans
   eight columns and the row is tall. Below that it runs full width, the row is
   much shorter, and covering a 552x1200 photo there would crop a third of it
   away -- so it keeps fitting inside the box. */
@media (min-width: 961px) {
  .card.card-feature { grid-template-columns: minmax(260px, 344px) 1fr; }
  .card.card-feature .dtsp-ba img { object-fit: cover !important; }
}
/* The well already carries the photo's ratio, so the frame just fills it. */
.card.card-feature .dtsp-ba-frame { aspect-ratio: auto !important; height: 100%; }
.card.card-feature .card-body { align-self: center; padding: 32px; }
.card.card-feature .card-body h3 { font-size: clamp(24px, 2.4vw, 34px); }
/* site.css collapses every card to full width at 960px via [class*="span-"],
   which this class does not match. Without its own reset, `span 8` would create
   eight implicit columns in the one-column mobile grid and squeeze the cards
   beside it to a sliver. */
@media (max-width: 960px) {
  .card.card-feature { grid-column: 1 / -1; }
}
@media (max-width: 860px) {
  .card.card-feature { grid-template-columns: 1fr; }
  /* Stacked, still height-first. Letting the width drive it here would make a
     portrait pair 1500px tall on a phone -- a whole screen and a half of one
     card. Cap the height and let the narrower column centre itself. */
  /* Stacked, the row is one card tall, so give the media an explicit height
     again -- `auto` on a stretched item with nothing beside it is zero. */
  .card.card-feature .card-media {
    height: clamp(320px, 58vh, 520px);
    min-height: 0; width: 100%;
  }
  .card.card-feature .card-body { padding: 24px; }
}


/* ---------- review modal ----------
   Portaled to <body> like the lightbox, so it declares the tokens itself (see
   the selector list at the top of this file) rather than inheriting them from
   .dtsp. Light surface, because a review is a document to read, not a photo to
   look at -- the dark lightbox treatment would fight the text. */
.dtsp-rv {
  position: fixed; inset: 0; z-index: 2147483000; display: none;
  background: rgba(11,26,18,.62);
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
  font-family: var(--dtsp-body); padding: 20px;
}
.dtsp-rv.dtsp-open { display: grid; place-items: center; }
.dtsp-rv * { box-sizing: border-box; }
.dtsp-rv-box {
  position: relative; width: min(640px, 100%); max-height: min(84vh, 760px);
  display: grid; grid-template-rows: auto minmax(0, 1fr) auto;
  background: var(--dtsp-surface); color: var(--dtsp-fg);
  border-radius: var(--dtsp-r-md); box-shadow: 0 24px 60px rgba(11,26,18,.4);
  overflow: hidden;
}
.dtsp-rv-close {
  position: absolute; top: 12px; right: 12px; z-index: 2;
  width: 34px; height: 34px; border-radius: 50%; border: 1px solid var(--dtsp-border);
  background: var(--dtsp-surface); color: var(--dtsp-fg2);
  display: grid; place-items: center; cursor: pointer;
}
.dtsp-rv-close:hover { background: var(--dts-bone-100, #f3efe6); }
.dtsp-rv-head {
  display: flex; align-items: center; gap: 12px;
  padding: 18px 56px 14px 20px; border-bottom: 1px solid var(--dtsp-border);
}
.dtsp-rv-av { width: 38px; height: 38px; font-size: 14px; }
.dtsp-rv-who {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  font-family: var(--dtsp-accent-f); font-weight: 700; font-size: 15px;
}
.dtsp-rv-meta {
  display: flex; align-items: center; gap: 6px;
  font-size: 12.5px; color: var(--dtsp-fg2); margin-top: 3px;
}
/* Scrolls on its own so the header and the map button stay put. */
.dtsp-rv-body { overflow-y: auto; padding: 18px 20px 20px; }
.dtsp-rv-text {
  margin: 0; font-size: 15px; line-height: 1.62; color: var(--dtsp-fg);
  white-space: pre-wrap;     /* customers write in paragraphs */
}
.dtsp-rv-reply {
  margin-top: 18px; padding: 14px 16px;
  background: var(--dts-bone-100, #f3efe6); border-radius: var(--dtsp-r-sm, 4px);
  border-left: 3px solid var(--dts-forest-500);
}
.dtsp-rv-reply-who {
  font-family: var(--dtsp-accent-f); font-weight: 700; font-size: 12px;
  letter-spacing: .06em; text-transform: uppercase; color: var(--dts-forest-500);
  margin-bottom: 6px;
}
.dtsp-rv-reply p {
  margin: 0; font-size: 14px; line-height: 1.6; color: var(--dtsp-fg2);
  white-space: pre-wrap;
}
.dtsp-rv-shots { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 18px; }
.dtsp-rv-shots img {
  width: 84px; height: 64px; object-fit: cover; cursor: pointer;
  border-radius: var(--dtsp-r-sm, 4px);
}
.dtsp-rv-foot { padding: 14px 20px; border-top: 1px solid var(--dtsp-border); }
.dtsp-rv-map {
  font-family: var(--dtsp-accent-f); font-weight: 700; font-size: 13px;
  padding: 9px 16px; border-radius: var(--dtsp-r-pill);
  border: 1px solid var(--dtsp-border); background: var(--dtsp-surface);
  color: var(--dtsp-fg); cursor: pointer;
}
.dtsp-rv-map:hover { background: var(--dts-forest-500); color: #fff; border-color: var(--dts-forest-500); }
@media (max-width: 560px) {
  .dtsp-rv { padding: 0; }
  .dtsp-rv-box { max-height: 100vh; height: 100%; width: 100%; border-radius: 0; }
}
