*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; accent-color: var(--primary); }

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.7;
  color: var(--ink);
  background: var(--surface-100);
  -webkit-font-smoothing: antialiased;
  overflow-x: clip; /* decorative bugs sit near the edges; never let them scroll the page sideways */
}

img { display: block; max-width: 100%; height: auto; }
a { color: inherit; text-decoration: none; }
h1, h2, h3, p, blockquote, figure, ul, ol { margin: 0; }
ul, ol { padding: 0; list-style: none; }

h1, h2, h3 {
  font-family: var(--font-head);
  color: var(--ink);
  line-height: 1.1;
  letter-spacing: var(--track-head);
  text-wrap: balance;
}
p { text-wrap: pretty; max-width: var(--measure); }

::selection { background: var(--primary); color: var(--primary-ink); }

:focus-visible {
  outline: 3px solid var(--primary);
  outline-offset: 3px;
  border-radius: var(--r-sm);
}

.skip-link {
  position: absolute;
  left: var(--s-3);
  top: -100px;
  z-index: 100;
  display: inline-flex;
  align-items: center;
  min-height: var(--touch);
  padding: 0 var(--s-3);
  background: var(--primary);
  color: var(--primary-ink);
  border-radius: var(--r-sm);
  font-weight: 600;
}
.skip-link:focus { top: var(--s-3); }

.container {
  width: 100%;
  max-width: 1360px;
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* Sections own their vertical rhythm; nothing else sets padding-block on one. */
.section { position: relative; padding-block: var(--section-y); }
.section--tint { background: var(--g-50); }
.section--deep { background: var(--field-deep); color: var(--primary-ink); }
.section--deep h2, .section--deep h3 { color: var(--primary-ink); }
.section--deep :focus-visible { outline-color: var(--primary-ink); }

.h2 {
  font-size: clamp(1.875rem, 1.25rem + 2.6vw, 3.25rem);
  font-weight: 700;
  letter-spacing: var(--track-display);
  max-width: 18ch;
}

/* ---------- Deep field ----------
   Flat green over a large area goes dead. Two soft radial pools plus grain give
   it a lit, physical feel without adding a colour. */
.field {
  position: relative;
  isolation: isolate;
  background: var(--field-deep);
  color: var(--primary-ink);
}
.field::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -2;
  background:
    radial-gradient(70% 55% at 12% 0%, color-mix(in srgb, var(--g-600) 85%, transparent) 0%, transparent 62%),
    radial-gradient(60% 60% at 100% 100%, color-mix(in srgb, var(--g-950) 70%, transparent) 0%, transparent 60%);
}
.field::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image: var(--grain);
  background-size: 160px 160px;
  opacity: .16;
  mix-blend-mode: overlay;
  pointer-events: none;
}

/* ---------- Section label: a dot, a word, and a rule that runs out ---------- */
.rule {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  max-width: none;
  margin-bottom: var(--s-4);
  color: var(--primary);
}
.rule::before {
  content: "";
  width: 7px;
  height: 7px;
  flex: none;
  border-radius: var(--r-pill);
  background: currentColor;
}
.rule::after {
  content: "";
  flex: 1;
  height: 1px;
  background: linear-gradient(to right, currentColor, transparent);
  opacity: .5;
}
.rule span { font-family: var(--font-mono); font-size: 13px; line-height: 1; letter-spacing: .02em; }
.field .rule, .section--deep .rule { color: var(--primary-ink); }

/* ---------- Decorative insects ----------
   Line-art SVG, not photographs. They are pure decoration: aria-hidden, never
   placed over the form or any trust claim, and always low contrast so they read
   as a texture rather than an infestation. In the hero they sit OUTSIDE the
   traced perimeter, which is the whole point of the product. */
.bugs { position: absolute; inset: 0; z-index: 0; pointer-events: none; overflow: clip; }
.bug {
  position: absolute;
  width: var(--bug-size, 30px);
  height: var(--bug-size, 30px);
  color: currentColor;
  opacity: var(--bug-opacity, .18);
  will-change: transform;
  animation: bug-drift var(--bug-dur, 18s) ease-in-out infinite alternate;
  animation-delay: var(--bug-delay, 0s);
}
.bug svg { width: 100%; height: 100%; display: block; }

@keyframes bug-drift {
  from { transform: translate3d(0, 0, 0) rotate(var(--bug-rot, 0deg)); }
  to   { transform: translate3d(var(--bug-x, 10px), var(--bug-y, -14px), 0) rotate(calc(var(--bug-rot, 0deg) + var(--bug-spin, 12deg))); }
}

/* ---------- The one orchestrated load moment ----------
   The perimeter draws itself around the hero, its labels arrive on the line,
   then the copy. It animates the actual idea: someone walking the outside of
   your house. Nothing else on the site auto-animates on scroll. */
@keyframes draw-perimeter { to { stroke-dashoffset: 0; } }
@keyframes rise { from { opacity: 0; transform: translate3d(0, 14px, 0); } to { opacity: 1; transform: none; } }
@keyframes tick-in { from { opacity: 0; transform: scale(.7); } to { opacity: 1; transform: none; } }

/* the rect carries pathLength="1", so one dash unit is the whole perimeter
   regardless of how wide the frame renders — no JS measurement needed */
/* The hidden states live INSIDE prefers-reduced-motion: no-preference, so the
   default is visible. If the query does not match, or animations never run, the
   content is already on screen rather than stuck at opacity 0. Hiding first and
   revealing later is the common pattern and it fails to a blank page. */
@media (prefers-reduced-motion: no-preference) {
  .js .hero__perimeter rect { stroke-dasharray: 1; stroke-dashoffset: 1; animation: draw-perimeter 1.8s var(--ease-out) forwards .15s; }
  .js .hero__stagger > * { opacity: 0; animation: rise .8s var(--ease-spring) forwards; }
  .js .perimeter__tick { opacity: 0; animation: tick-in .5s var(--ease-spring) forwards; }
}
.js .hero__stagger > :nth-child(1) { animation-delay: .75s; }
.js .hero__stagger > :nth-child(2) { animation-delay: .87s; }
.js .hero__stagger > :nth-child(3) { animation-delay: .99s; }
.js .hero__stagger > :nth-child(4) { animation-delay: 1.11s; }
.js .hero__stagger > :nth-child(5) { animation-delay: 1.23s; }
.js .perimeter__tick--a { animation-delay: .95s; }
.js .perimeter__tick--c { animation-delay: 1.15s; }
.js .perimeter__tick--b { animation-delay: 1.35s; }

/* Placeholders that must not ship unnoticed. */
[data-placeholder] { outline: 2px dashed var(--accent-strong); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  /* the sequence must not leave anything invisible when motion is off */
  .js .hero__stagger > *, .js .perimeter__tick { opacity: 1; }
  .js .hero__perimeter rect { stroke-dashoffset: 0; }
  .bug { animation: none; }
}

/* ---------- Insect placements ----------
   Hand-placed rather than random, so nothing ever lands on the form, a trust
   claim, or a headline. In the hero they are all OUTSIDE the traced perimeter:
   the line is what keeps them out, which is exactly what the company sells.
   Sizes step down on small screens so they stay decoration, not clutter. */
.bug--a { top: 3%;  left: 1.5%;  --bug-size: 24px; --bug-rot: -22deg; --bug-x: 12px;  --bug-y: -9px;  --bug-dur: 19s; }
.bug--b { top: 1%;  right: 4%;   --bug-size: 21px; --bug-rot: 34deg;  --bug-x: -10px; --bug-y: 12px;  --bug-dur: 23s; --bug-delay: -4s; }
.bug--c { bottom: 5%; left: 4%;  --bug-size: 26px; --bug-rot: 12deg;  --bug-x: 16px;  --bug-y: -12px; --bug-dur: 21s; --bug-delay: -9s; }
.bug--d { bottom: 2%; right: 2%; --bug-size: 22px; --bug-rot: -40deg; --bug-x: -13px; --bug-y: -10px; --bug-dur: 25s; --bug-delay: -2s; }
.bug--e { top: 46%; left: 0.5%;  --bug-size: 19px; --bug-rot: 68deg;  --bug-x: 9px;   --bug-y: 14px;  --bug-dur: 27s; --bug-delay: -13s; }
.bug--f { top: 62%; right: 1%;   --bug-size: 20px; --bug-rot: -12deg; --bug-x: -11px; --bug-y: -15px; --bug-dur: 22s; --bug-delay: -6s; }

/* on the deep green fields they read as a faint etching */
.field .bug { --bug-opacity: .22; color: var(--primary-ink); }
/* on paper they are darker but fainter, so body copy always wins */
.section .bug, .proof .bug { --bug-opacity: .13; color: var(--primary); }

@media (max-width: 639px) {
  .bug { --bug-size: 18px !important; --bug-opacity: .16; }
  .bug--e, .bug--f { display: none; } /* not enough margin beside the frame on a phone */
}
