/* ============================================================================
   CASTLE SPATIAL LAYER — v1.0
   A site-wide "spatial UI" system: real depth tokens, a single virtual light
   source, pointer-reactive parallax, glass elevation and a floating command
   dock. Loaded LAST in <head> so it can refine the existing inline styles
   without fighting them.

   Design rules
   ------------
   1. One light source. It lives at --sp-light-x / --sp-light-y (top-center by
      default) and every highlight, rim and contact shadow is derived from it.
   2. Depth is a ladder, not a guess. --sp-e1 … --sp-e5 (elevation 1–5).
      Higher elevation = larger blur + more spread + stronger rim light.
   3. Motion is transform/opacity only. Nothing here can trigger layout.
   4. Everything degrades: reduced-motion, coarse pointers, reduced-data and
      no-JS all fall back to a flat, fully readable page.
   ========================================================================== */

/* Decorative layers (.sp-field-layer, .hero-blob, offset Tailwind blobs) are
   deliberately wider than the viewport for parallax headroom. Without this they
   produce a real horizontal scrollbar between ~760px and ~1100px. `clip` is
   used instead of `hidden` because it does NOT create a scroll container, so
   position: sticky / fixed descendants keep working. */
html, body { overflow-x: clip; }

:root {
  /* Perspective depth of the whole scene */
  --sp-persp: 1100px;

  /* Virtual light source (page coordinates, updated by JS on pointer move) */
  --sp-light-x: 50%;
  --sp-light-y: -10%;

  /* Ink used for all shadows — warm mossy ink, never pure black */
  --sp-shadow-rgb: 30, 42, 36;

  /* ---- Elevation ladder (light surfaces) ------------------------------- */
  --sp-e1:
    0 1px 2px  rgba(var(--sp-shadow-rgb), .05),
    0 2px 6px -2px rgba(var(--sp-shadow-rgb), .08);
  --sp-e2:
    0 2px 4px  rgba(var(--sp-shadow-rgb), .05),
    0 8px 18px -6px rgba(var(--sp-shadow-rgb), .12);
  --sp-e3:
    0 3px 6px  rgba(var(--sp-shadow-rgb), .06),
    0 16px 32px -10px rgba(var(--sp-shadow-rgb), .16),
    0 1px 0 0 rgba(255,255,255,.7) inset;
  --sp-e4:
    0 4px 8px  rgba(var(--sp-shadow-rgb), .07),
    0 26px 52px -14px rgba(var(--sp-shadow-rgb), .22),
    0 1px 0 0 rgba(255,255,255,.8) inset;
  --sp-e5:
    0 6px 12px rgba(var(--sp-shadow-rgb), .08),
    0 40px 80px -20px rgba(var(--sp-shadow-rgb), .28),
    0 1px 0 0 rgba(255,255,255,.85) inset;

  /* ---- Elevation ladder (dark surfaces) -------------------------------- */
  --sp-de3:
    0 18px 40px -12px rgba(0,0,0,.5),
    inset 0 1px 0 rgba(255,255,255,.10);
  --sp-de4:
    0 30px 64px -18px rgba(0,0,0,.6),
    inset 0 1px 0 rgba(255,255,255,.14);

  /* Motion curves */
  --sp-ease: cubic-bezier(.22, 1, .36, 1);
  --sp-ease-spring: cubic-bezier(.34, 1.4, .64, 1);

  /* Tilt magnitude, tuned per-surface by JS */
  --sp-tilt-max: 7;
}

/* ============================================================================
   1. SCENE — sections that host spatial children get a shared perspective so
   sibling cards tilt as if they live in the same room.
   ========================================================================== */
html.sp-on .sp-scene {
  perspective: var(--sp-persp);
  perspective-origin: 50% 40%;
}

/* ============================================================================
   2. SPATIAL SURFACE — the core card behaviour.
   JS tags cards with .sp-surface and feeds:
     --rx / --ry  pointer tilt (deg, already used by the legacy service-card CSS)
     --sp-mx/--sp-my  pointer position inside the card (%) for the glare
     --sp-in      0..1 how "engaged" the surface is (hover / focus / in-view)
   ========================================================================== */
html.sp-on .sp-surface {
  position: relative;
  transform:
    translate3d(0, var(--sp-lift, 0px), 0)
    rotateX(calc(var(--ry, 0) * -1deg))
    rotateY(calc(var(--rx, 0) * 1deg))
    scale(var(--sp-scale, 1));
  transition:
    transform .5s var(--sp-ease),
    box-shadow .45s var(--sp-ease),
    border-color .3s ease,
    background-color .3s ease;
  will-change: auto;
}
html.sp-on .sp-surface.is-tilting {
  transition: transform .09s linear, box-shadow .45s var(--sp-ease);
  will-change: transform;
}

/* Engaged (hover / keyboard focus) = one step up the elevation ladder */
html.sp-on .sp-surface:hover,
html.sp-on .sp-surface:focus-visible,
html.sp-on .sp-surface:focus-within {
  --sp-lift: -8px;
  --sp-scale: 1.012;
  z-index: 2;
}

/* Touch devices: whatever sits in the reading band is the "engaged" surface */
html.sp-on .sp-surface.sp-near { box-shadow: var(--sp-e3); }
html.sp-on .sp-surface--dark.sp-near { box-shadow: var(--sp-de3); }

/* ---- Specular glare: a soft highlight that tracks the pointer ------------ */
html.sp-on .sp-glare {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  transition: opacity .35s ease;
  z-index: 3;
  background:
    radial-gradient(
      420px circle at var(--sp-mx, 50%) var(--sp-my, 0%),
      rgba(255,255,255,.55) 0%,
      rgba(255,255,255,.18) 32%,
      transparent 62%
    );
  mix-blend-mode: soft-light;
}
html.sp-on .sp-surface:hover > .sp-glare,
html.sp-on .sp-surface:focus-within > .sp-glare { opacity: 1; }

/* Dark surfaces get a cooler, tighter specular so glass reads as glass */
html.sp-on .sp-surface--dark > .sp-glare {
  background:
    radial-gradient(
      360px circle at var(--sp-mx, 50%) var(--sp-my, 0%),
      rgba(255,255,255,.30) 0%,
      rgba(167,201,164,.12) 40%,
      transparent 68%
    );
  mix-blend-mode: screen;
}

/* ---- Rim light: a 1px edge lit from the virtual light source ------------- */
html.sp-on .sp-rim::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  z-index: 4;
  padding: 1px;
  background: linear-gradient(
    calc(180deg + var(--rx, 0) * 2deg),
    rgba(255,255,255,.85),
    rgba(255,255,255,0) 42%,
    rgba(var(--sp-shadow-rgb), .10) 100%
  );
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  opacity: 0;
  transition: opacity .35s ease;
}
html.sp-on .sp-surface:hover.sp-rim::after,
html.sp-on .sp-surface:focus-within.sp-rim::after { opacity: 1; }

/* ---- Cast shadow: the drop shadow slides AWAY from the virtual light, so the
   card feels lit from one direction instead of glowing evenly. Done with
   box-shadow (not an extra element) so overflow:hidden cards still cast. --- */
html.sp-on .sp-surface:hover,
html.sp-on .sp-surface:focus-within {
  box-shadow:
    calc(var(--rx, 0) * -0.9px) 6px 12px rgba(var(--sp-shadow-rgb), .07),
    calc(var(--rx, 0) * -2.2px) 28px 54px -16px rgba(var(--sp-shadow-rgb), .24),
    inset 0 1px 0 rgba(255,255,255,.8);
}
html.sp-on .sp-surface--dark:hover,
html.sp-on .sp-surface--dark:focus-within {
  box-shadow:
    calc(var(--rx, 0) * -2.2px) 30px 64px -18px rgba(0,0,0,.6),
    inset 0 1px 0 rgba(255,255,255,.14);
}

/* ---- Layered parallax: children drift by depth (2.5D, clip-safe) -------- */
html.sp-on .sp-layer {
  transition: transform .5s var(--sp-ease);
  transform: translate3d(
    calc(var(--rx, 0) * var(--sp-d, 0) * 0.55px),
    calc(var(--ry, 0) * var(--sp-d, 0) * 0.55px),
    0
  );
}
html.sp-on .sp-surface.is-tilting .sp-layer { transition: transform .09s linear; }

/* Depth presets used by the JS auto-tagger */
.sp-d1 { --sp-d: 1; }   /* body copy      — barely moves */
.sp-d2 { --sp-d: 2; }   /* headings       */
.sp-d3 { --sp-d: 3; }   /* imagery        */
.sp-d4 { --sp-d: 4.5; } /* badges / icons — floats highest */

/* Media inside a spatial surface gets a slow depth zoom, not a jumpy one */
html.sp-on .sp-surface img { transition: transform .7s var(--sp-ease), filter .5s ease; }
html.sp-on .sp-surface:hover img { filter: saturate(1.06) contrast(1.02); }

/* ============================================================================
   3. DEPTH REVEAL — upgrade the existing .reveal system so content arrives
   from behind the screen plane instead of just sliding up.
   ========================================================================== */
html.sp-on .reveal {
  transform: translate3d(0, 26px, 0) scale(.985);
}
html.sp-on .reveal.in {
  transform: none;
}
html.sp-on .sp-scene > .reveal,
html.sp-on .sp-scene .reveal {
  transition:
    opacity .85s var(--sp-ease),
    transform .85s var(--sp-ease),
    filter .85s var(--sp-ease);
}

/* ============================================================================
   4. AMBIENT DEPTH FIELD — three parallax layers of soft motes behind hero /
   testimonial / CTA sections. Injected by JS, animated by one shared rAF.
   ========================================================================== */
html.sp-on .sp-field {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 1;
  contain: strict;
}
html.sp-on .sp-field-layer {
  position: absolute;
  inset: -12% -6%;
  background-repeat: repeat;
  will-change: transform;
  transform: translate3d(
    calc(var(--sp-px, 0) * var(--sp-fd, 1) * 1px),
    calc(var(--sp-py, 0) * var(--sp-fd, 1) * 1px + var(--sp-scrolly, 0px) * var(--sp-fd, 1)),
    0
  );
}
/* Layer 1 — far, tiny, dim */
.sp-field-layer.l1 {
  --sp-fd: .35;
  opacity: .30;
  background-image: radial-gradient(circle, rgba(255,255,255,.85) 0 1px, transparent 1.6px);
  background-size: 120px 120px;
}
/* Layer 2 — mid, leaf-tinted */
.sp-field-layer.l2 {
  --sp-fd: .7;
  opacity: .26;
  background-image: radial-gradient(circle, rgba(167,201,164,.95) 0 1.6px, transparent 2.4px);
  background-size: 190px 170px;
}
/* Layer 3 — near, warm accent, sparse */
.sp-field-layer.l3 {
  --sp-fd: 1.15;
  opacity: .20;
  background-image: radial-gradient(circle, rgba(241,201,168,.95) 0 2.2px, transparent 3px);
  background-size: 320px 280px;
}
/* On light sections the motes flip to ink so they stay visible */
.sp-field--light .sp-field-layer.l1 { background-image: radial-gradient(circle, rgba(30,42,36,.40) 0 1px, transparent 1.6px); opacity: .22; }
.sp-field--light .sp-field-layer.l2 { background-image: radial-gradient(circle, rgba(31,111,74,.45) 0 1.6px, transparent 2.4px); opacity: .18; }
.sp-field--light .sp-field-layer.l3 { background-image: radial-gradient(circle, rgba(194,102,59,.45) 0 2.2px, transparent 3px); opacity: .14; }

/* ============================================================================
   5. AREA LIGHT — dark sections get a large soft light that follows the
   pointer, so glass panels on top of them look genuinely lit.
   ========================================================================== */
.sp-lit { position: relative; isolation: isolate; }
html.sp-on .sp-lit > .sp-lit-glow {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  opacity: 0;
  transition: opacity .6s ease;
  background: radial-gradient(
    620px circle at var(--sp-mx, 50%) var(--sp-my, 30%),
    rgba(63,163,114,.22) 0%,
    rgba(194,102,59,.10) 38%,
    transparent 70%
  );
}
html.sp-on .sp-lit.is-lit > .sp-lit-glow { opacity: 1; }

/* ============================================================================
   6. MAGNETIC CTA — primary actions lean toward the pointer, catch a specular
   sweep, and depress into the page on click.
   ========================================================================== */
html.sp-on .sp-magnetic {
  position: relative;
  transform: translate3d(var(--sp-magx, 0px), var(--sp-magy, 0px), 0) scale(var(--sp-magscale, 1));
  transition: transform .35s var(--sp-ease), box-shadow .35s var(--sp-ease), filter .3s ease;
}
html.sp-on .sp-magnetic.is-magnetic { transition: transform .12s linear, box-shadow .3s ease; }
html.sp-on .sp-magnetic:hover  { --sp-magscale: 1.03; }
html.sp-on .sp-magnetic:active { --sp-magscale: .975; filter: brightness(.97); }
html.sp-on .sp-magnetic > .sp-sheen {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  overflow: hidden;
  pointer-events: none;
}
html.sp-on .sp-magnetic > .sp-sheen::before {
  content: '';
  position: absolute;
  top: -40%;
  bottom: -40%;
  width: 40%;
  left: -60%;
  background: linear-gradient(100deg, transparent, rgba(255,255,255,.42), transparent);
  transform: skewX(-18deg);
  transition: left .65s var(--sp-ease);
}
html.sp-on .sp-magnetic:hover > .sp-sheen::before { left: 120%; }

/* Focus ring that respects the spatial look */
.sp-magnetic:focus-visible,
.sp-surface:focus-visible {
  outline: 2px solid #C2663B;
  outline-offset: 3px;
}

/* ============================================================================
   7. SPATIAL DOCK — a floating glass command bar. Mobile: bottom-centered
   pill. Desktop: bottom-centred horizontal bar. Injected by JS.
   ========================================================================== */
.sp-dock {
  position: fixed;
  z-index: 60;
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 5px;
  border-radius: 999px;
  background: rgba(251,248,241,.55);
  border: 1px solid rgba(255,255,255,.55);
  box-shadow:
    0 12px 34px -14px rgba(var(--sp-shadow-rgb), .38),
    0 1px 2px rgba(var(--sp-shadow-rgb), .06),
    inset 0 1px 0 rgba(255,255,255,.75);
  backdrop-filter: blur(18px) saturate(170%);
  -webkit-backdrop-filter: blur(18px) saturate(170%);
  transform: translate3d(0, 0, 0);
  transition: transform .45s var(--sp-ease), opacity .35s ease;
  /* Mobile placement */
  left: 50%;
  bottom: max(14px, env(safe-area-inset-bottom, 0px));
  translate: -50% 0;
}
.sp-dock.is-hidden {
  opacity: 0;
  transform: translate3d(0, 130%, 0);
  pointer-events: none;
}
.sp-dock-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 42px;
  padding: 0 15px;
  border-radius: 999px;
  font: 700 .8125rem/1 'Plus Jakarta Sans', system-ui, sans-serif;
  letter-spacing: .01em;
  white-space: nowrap;
  color: rgba(var(--sp-shadow-rgb), .87);
  background: rgba(255,255,255,.6);
  border: 1px solid rgba(30,42,36,.08);
  transition: transform .25s var(--sp-ease-spring), background-color .25s ease, color .25s ease, box-shadow .25s ease;
}
.sp-dock-btn i { font-size: .9rem; }
.sp-dock-btn:hover { transform: translateY(-2px); background: #fff; box-shadow: var(--sp-e2); }
.sp-dock-btn:active { transform: translateY(0) scale(.97); }
.sp-dock-btn--call {
  background: #1F6F4A;
  color: #FBF8F1;
  border-color: rgba(255,255,255,.18);
  box-shadow: 0 8px 20px -8px rgba(31,111,74,.55);
}
.sp-dock-btn--call:hover { background: #13502F; color: #fff; }
.sp-dock-btn--cta {
  background: #C2663B;
  color: #FBF8F1;
  border-color: rgba(255,255,255,.18);
  box-shadow: 0 8px 22px -8px rgba(194,102,59,.6);
}
.sp-dock-btn--cta:hover { background: #A0502C; color: #fff; }
.sp-dock-btn--icon { padding: 0; width: 42px; justify-content: center; }
.sp-dock-btn[aria-pressed="false"] { color: rgba(var(--sp-shadow-rgb), .38); }

/* Depth toggle tooltip */
.sp-dock-btn[data-sp-tip]::after {
  content: attr(data-sp-tip);
  position: absolute;
  bottom: calc(100% + 10px);
  left: 50%;
  translate: -50% 0;
  padding: 5px 9px;
  border-radius: 8px;
  font-size: .6875rem;
  font-weight: 600;
  white-space: nowrap;
  color: #FBF8F1;
  background: rgba(14,22,18,.92);
  opacity: 0;
  pointer-events: none;
  transition: opacity .2s ease, translate .2s ease;
}
.sp-dock-btn[data-sp-tip]:hover::after { opacity: 1; translate: -50% -2px; }

/* Desktop: a bottom-centred horizontal action bar.
   Centre-bottom is the position the survival brain already accepts from mobile
   app bars, so it reads as a system affordance rather than an ad. Labels stay
   visible — a collapsed icon rail forces the logic brain to guess, and guessing
   is friction right at the decision point. */
@media (min-width: 1024px) {
  .sp-dock {
    left: 50%;
    right: auto;
    bottom: 24px;
    translate: -50% 0;
    flex-direction: row;
    align-items: center;
    border-radius: 999px;
    padding: 6px;
    gap: 6px;
  }
  .sp-dock-btn { width: auto; justify-content: center; }
  .sp-dock-btn--icon { width: 42px; align-self: center; }

  /* Labels always legible on desktop — no collapse. */
  .sp-dock-btn > span {
    display: inline-block;
    max-width: none;
    opacity: 1;
    overflow: visible;
    white-space: nowrap;
  }
  .sp-dock-btn:has(> span) { padding: 0 16px; }

  /* Tooltips sit above the bar now that it is horizontal. */
  .sp-dock-btn[data-sp-tip]::after {
    bottom: calc(100% + 10px);
    top: auto;
    left: 50%;
    right: auto;
    translate: -50% 0;
  }
  .sp-dock-btn[data-sp-tip]:hover::after { translate: -50% -2px; }

  /* Slim divider before the utility icons so the two CTAs read as the primary pair */
  .sp-dock-btn--icon:first-of-type::before {
    content: '';
    position: absolute;
    left: -4px;
    top: 9px;
    bottom: 9px;
    width: 1px;
    background: rgba(30,42,36,.10);
  }
}

/* Keep the dock clear of the GorillaDesk chat bubble on small screens */
@media (max-width: 1023px) {
  .sp-dock { bottom: max(78px, calc(env(safe-area-inset-bottom, 0px) + 78px)); }
}

/* ============================================================================
   8. SURFACE REFINEMENTS — map existing components onto the depth ladder.
   ========================================================================== */
html.sp-on .service-card,
html.sp-on .pest-card {
  box-shadow: var(--sp-e2);
  border-color: rgba(30,42,36,.07);
}
html.sp-on .service-card:hover,
html.sp-on .pest-card:hover { box-shadow: var(--sp-e4); }

html.sp-on .neumo-card { box-shadow: var(--sp-e2), inset 0 1px 0 rgba(255,255,255,.85); }
html.sp-on .neumo-card:hover { box-shadow: var(--sp-e3); }

html.sp-on .glass { box-shadow: var(--sp-de3); }
html.sp-on .glass:hover { box-shadow: var(--sp-de4); }

html.sp-on .process-step { box-shadow: var(--sp-e1); }
html.sp-on .process-step.is-active { box-shadow: var(--sp-e3); }

/* Stat cards get a floating numeral: the number sits above its label in Z */
html.sp-on .stat-card .stat-num {
  transition: transform .6s var(--sp-ease), text-shadow .6s ease;
}
html.sp-on .stat-card.is-active .stat-num {
  transform: translate3d(0, -2px, 0);
  text-shadow: 0 10px 24px rgba(31,111,74,.22);
}

/* Header becomes a true floating plane once scrolled */
html.sp-on #site-header.nav-scrolled {
  box-shadow:
    0 1px 0 rgba(30,42,36,.06),
    0 10px 30px -14px rgba(var(--sp-shadow-rgb), .30);
}

/* ============================================================================
   9. SPATIAL SCROLL DEPTH — sections recede slightly as they leave the
   viewport, which reads as physical space rather than a flat scroll.
   ========================================================================== */
html.sp-on .sp-depth-out {
  transform: translate3d(0, 0, 0) scale(calc(1 - var(--sp-out, 0) * .02));
  opacity: calc(1 - var(--sp-out, 0) * .12);
  transition: none;
}

/* ============================================================================
   10. GRACEFUL DEGRADATION
   ========================================================================== */

/* Depth switched OFF (dock toggle) → the injected decorative nodes must not
   affect layout at all, so they are removed from the box model entirely. */
html:not(.sp-on) .sp-glare,
html:not(.sp-on) .sp-sheen,
html:not(.sp-on) .sp-field,
html:not(.sp-on) .sp-lit-glow { display: none !important; }

/* No JS → nothing spatial is injected; .sp-on is never set, so the page is
   exactly the original design. */

/* Coarse pointers: no tilt, no magnetism — replace with an honest press state */
@media (hover: none), (pointer: coarse) {
  .sp-surface,
  .sp-layer,
  .sp-magnetic { transform: none !important; }
  .sp-glare, .sp-rim::after { display: none !important; }
  .sp-surface:active { --sp-scale: .985; transform: scale(.985) !important; }
  .sp-magnetic:active { transform: scale(.97) !important; }
}

/* Reduced motion: keep depth (shadows, glass, rim) but remove all movement */
@media (prefers-reduced-motion: reduce) {
  .sp-surface,
  .sp-layer,
  .sp-magnetic,
  .sp-field-layer,
  html.sp-on .sp-depth-out {
    transform: none !important;
    transition: box-shadow .3s ease, background-color .3s ease, border-color .3s ease !important;
  }
  .sp-field { display: none !important; }
  .sp-magnetic > .sp-sheen { display: none !important; }
  html.sp-on .reveal { transform: none !important; opacity: 1 !important; }
  html.sp-on .sp-depth-out { opacity: 1 !important; }
  .sp-dock { transition: none; }
}

/* Data-saver: drop the ambient field and the blur (both are the expensive bits) */
@media (prefers-reduced-data: reduce) {
  .sp-field { display: none !important; }
  .sp-dock { backdrop-filter: none; -webkit-backdrop-filter: none; background: rgba(251,248,241,.96); }
}

/* Print: flatten everything */
@media print {
  .sp-dock, .sp-field, .sp-glare, .sp-lit-glow { display: none !important; }
  .sp-surface { transform: none !important; box-shadow: none !important; }
}
