/* ==========================================================================
   Raul's Landscaping — Atlantic County, NJ

   PALETTE: deep olive, terracotta, warm sand. Earth and clay pots rather than
   bright turf. Every pair below was measured before use and the ratio is in
   the comment; nothing here is estimated.

   The terracotta needed three steps, not one. A single mid-tone clay fails at
   2.73:1 on the dark header, so there is a light variant for use on --canopy
   and a dark one for use as text on --sand. Each step has exactly one job.

   Mobile first. Breakpoints at 480, 768, 1024. Tested 320 → 1440.
   ========================================================================== */

/* -------------------------------------------------------------- fonts
   Self-hosted, latin subset only. No external request, nothing render
   blocking, and font-display:swap so text paints immediately in the
   fallback and reflows once.                                             */

@font-face {
  font-family: "Fraunces";
  src: url("../fonts/fraunces-700.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Source Sans 3";
  src: url("../fonts/sourcesans-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Source Sans 3";
  src: url("../fonts/sourcesans-600.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

:root {
  --canopy: #22331c;   /* header, footer, dark bands */
  --olive: #3e5a2e;    /* headings, secondary button, input borders */
  --clay: #b5541f;     /* primary button — white on it is 4.94:1 */
  --clay-dk: #8f3f14;  /* clay as text on sand — 6.56:1 */
  --clay-lt: #de8149;  /* clay as text on canopy — 4.71:1 */
  --sand: #f7f3ea;     /* page background */
  --bone: #ede7d9;     /* alternating band */
  --sage: #d6e2c8;     /* cards, footer text on dark — 9.99:1 on canopy */
  --ink: #1a2116;      /* body text — 14.90:1 on sand */
  --muted: #53604c;    /* secondary text — 6.03:1 on sand */
  --error: #9b2226;    /* form validation — 7.15:1 on sand */

  --display: "Fraunces", Georgia, "Times New Roman", serif;
  --body: "Source Sans 3", system-ui, -apple-system, "Segoe UI", sans-serif;

  --gutter: 1.25rem;
  --radius: 10px;
  --maxw: 68rem;

  --shadow: 0 1px 2px rgba(26, 33, 22, 0.07), 0 6px 18px rgba(26, 33, 22, 0.06);
}

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* The sticky header must not cover a section you just jumped to. */
  scroll-padding-top: 5.5rem;
}

body {
  margin: 0;
  background: var(--sand);
  color: var(--ink);
  font-family: var(--body);
  font-size: 1.0625rem;
  line-height: 1.65;
  /* Belt and braces against sideways scroll at 320px. */
  overflow-x: hidden;
}

h1, h2, h3 {
  font-family: var(--display);
  font-weight: 700;
  line-height: 1.12;
  color: var(--canopy);
  margin: 0 0 0.6rem;
  letter-spacing: -0.01em;
}
h1 { font-size: clamp(2rem, 1.55rem + 2.1vw, 3.25rem); }
h2 { font-size: clamp(1.6rem, 1.35rem + 1.2vw, 2.35rem); }
h3 { font-size: 1.2rem; }
p { margin: 0 0 1rem; }

a { color: var(--clay-dk); }
a:hover { color: var(--clay); }

img { max-width: 100%; height: auto; }

.wrap { width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 var(--gutter); }

.section { padding: 3rem 0; }
.section-alt { background: var(--bone); }
.lede { max-width: 60ch; color: var(--muted); font-size: 1.125rem; }

/* Every interactive thing gets the same unmissable ring. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible {
  outline: 3px solid var(--clay);
  outline-offset: 3px;
  border-radius: 3px;
}
.site-header a:focus-visible,
.site-footer a:focus-visible { outline-color: var(--clay-lt); }

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  min-height: 48px;
}
.skip-link:focus {
  left: 0.75rem;
  top: 0.75rem;
  display: inline-flex;
  align-items: center;
  min-height: 48px;
  padding: 0 1rem;
  background: var(--clay);
  color: #fff;
  font-weight: 600;
  text-decoration: none;
  border-radius: var(--radius);
}

/* ------------------------------------------------------------- buttons
   48px is the floor everywhere. The primary sits at 52 so it still clears
   it once a browser rounds things off.                                   */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: 52px;
  padding: 0.7rem 1.4rem;
  border: 2px solid transparent;
  border-radius: var(--radius);
  font-family: var(--body);
  font-size: 1.0625rem;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease, transform 0.08s ease;
}
.btn:active { transform: translateY(1px); }

.btn-primary { background: var(--clay); color: #fff; }        /* 4.94:1 */
.btn-primary:hover { background: #9d4818; color: #fff; }

.btn-secondary {
  background: transparent;
  color: var(--canopy);
  border-color: var(--olive);
}
.btn-secondary:hover { background: var(--sage); color: var(--canopy); }

.btn-ghost-dark {
  background: transparent;
  color: var(--sand);
  border-color: rgba(214, 226, 200, 0.55);
}
.btn-ghost-dark:hover { background: rgba(214, 226, 200, 0.14); color: #fff; }

.btn-block { width: 100%; }

/* -------------------------------------------------------- sticky header */

.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--canopy);
  border-bottom: 3px solid var(--olive);
}
.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  min-height: 68px;
  padding: 0.5rem var(--gutter);
  max-width: var(--maxw);
  margin: 0 auto;
}
.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  color: var(--sand);
  text-decoration: none;
  font-family: var(--display);
  font-weight: 700;
  font-size: 1.15rem;
  line-height: 1.05;
}
.brand svg { flex: none; }
.brand:hover { color: #fff; }

/* -------------------------------------------------- 48px tap targets

   Three links came in under 48px on the first keyboard/touch audit: the
   brand in the header at 39px, and the two inline phone links inside
   paragraphs at 26px and 25px.

   The brand just gets a min-height. The inline ones cannot — an inline-flex
   phone number inside a sentence breaks the line box. They get vertical
   padding instead, which grows the hit area to 48px without taking the
   number out of the sentence it belongs in. The negative margin keeps the
   surrounding paragraph leading unchanged.
   ------------------------------------------------------------------- */

.brand { min-height: 48px; }

p a[href^="tel:"],
p a[href^="sms:"] {
  display: inline-block;
  padding: 0.7rem 0.15rem;
  margin: -0.7rem -0.15rem;
  font-weight: 600;
}

.header-call {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-height: 48px;
  padding: 0 1rem;
  background: var(--clay);
  color: #fff;
  border-radius: var(--radius);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}
.header-call:hover { background: #c75f26; color: #fff; }
.header-call .call-word { display: none; }

/* 320px. The full number plus the brand does not fit beside itself on the
   smallest phone still in use, so the number drops and the button reads
   "Call". The aria-label on the link keeps the number for screen readers. */
@media (max-width: 359px) {
  .header-call .call-word { display: inline; }
  .header-call .call-num { display: none; }
  .header-call { padding: 0 0.85rem; }
  .brand { font-size: 1rem; }
  .brand svg { width: 28px; height: 28px; }
}

/* ------------------------------------------------------------------ hero
   At 375x667 the name, the one-liner and the Call button all sit above the
   fold. The image is deliberately below them in the source and capped in
   height so it can never push the button off the first screen.            */

.hero {
  background: var(--canopy);
  color: var(--sand);
  padding: 2rem 0 0;
}
.hero h1 { color: var(--sand); margin-bottom: 0.75rem; }
.hero-sub {
  max-width: 34ch;
  color: var(--sage);
  font-size: 1.1875rem;
  margin-bottom: 0.35rem;
}
.hero-free {
  color: var(--clay-lt);            /* 4.71:1 on canopy */
  font-weight: 600;
  margin-bottom: 1.25rem;
}
.hero-actions { display: flex; flex-direction: column; gap: 0.75rem; }
.hero-actions .btn { width: 100%; }
.hero-figure { margin: 1.75rem 0 0; }
.hero-figure img {
  display: block;
  width: 100%;
  height: auto;
  max-height: 40vh;
  object-fit: cover;
  border-top: 4px solid var(--olive);
}

/* -------------------------------------------------------------- services */

.grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
  margin-top: 1.75rem;
  padding: 0;
  list-style: none;
}
.card {
  background: #fff;
  border: 1px solid #ded6c4;
  border-radius: var(--radius);
  padding: 1.35rem 1.25rem;
  box-shadow: var(--shadow);
}
.card h3 { margin-bottom: 0.4rem; }
.card p { margin: 0; color: var(--muted); }

/* ------------------------------------------------------- photo cards

   The service cards used to lead with a small line icon. Next to real
   photographs everywhere else on the page they read as clip art, so each
   card now opens with a photograph instead.

   The card loses its own padding and hands it to .card-body, which lets the
   image sit flush to the edges; overflow:hidden is what keeps the square
   corners of the photo inside the card's rounded ones.                    */

.card-media { padding: 0; overflow: hidden; }
.card-media .card-body { padding: 1.25rem 1.25rem 1.4rem; }

.card-photo { display: block; }
.card-photo img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-bottom: 3px solid var(--olive);
}

/* ------------------------------------------------------------------- why */

.why { counter-reset: why; }
.why .card { display: flex; gap: 1rem; align-items: flex-start; }
.why-num {
  flex: none;
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  background: var(--clay);
  color: #fff;
  font-family: var(--display);
  font-size: 1.15rem;
}

/* --------------------------------------------------------------- gallery */

.gallery { display: grid; gap: 1.5rem; margin-top: 1.75rem; }
.ba {
  background: #fff;
  border: 1px solid #ded6c4;
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow);
}
.ba-pair { display: grid; grid-template-columns: 1fr 1fr; }
.ba-pair figure { margin: 0; position: relative; }
.ba-pair img { display: block; width: 100%; height: auto; }
.ba-tag {
  position: absolute;
  left: 0.5rem;
  top: 0.5rem;
  padding: 0.2rem 0.6rem;
  border-radius: 999px;
  font-size: 0.8125rem;
  font-weight: 600;
  background: rgba(34, 51, 28, 0.88);
  color: var(--sand);
}
.ba-tag.is-after { background: var(--clay); color: #fff; }
.ba-caption { padding: 0.9rem 1.1rem; margin: 0; color: var(--muted); font-size: 0.95rem; }

/* ----------------------------------------------------------- service area */

.towns {
  margin: 1.25rem 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.towns li {
  background: #fff;
  border: 1px solid #ded6c4;
  border-radius: 999px;
  padding: 0.4rem 0.9rem;
  font-weight: 600;
  color: var(--olive);
}

/* ------------------------------------------------------------------ form */

.form-card {
  background: #fff;
  border: 1px solid #ded6c4;
  border-radius: var(--radius);
  padding: 1.35rem 1.25rem;
  box-shadow: var(--shadow);
  margin-top: 1.5rem;
}
.field { margin-bottom: 1.1rem; }
.field label { display: block; font-weight: 600; margin-bottom: 0.3rem; }
.req { color: var(--clay-dk); }
.hint { display: block; font-weight: 400; color: var(--muted); font-size: 0.9rem; }

input, select, textarea {
  width: 100%;
  min-height: 48px;
  padding: 0.65rem 0.8rem;
  border: 2px solid var(--olive);   /* 7.76:1 on white */
  border-radius: var(--radius);
  background: #fff;
  color: var(--ink);
  font-family: var(--body);
  /* 16px floor — anything smaller makes iOS zoom on focus. */
  font-size: 1rem;
}
textarea { min-height: 7rem; resize: vertical; }
input::placeholder, textarea::placeholder { color: var(--muted); }

input[aria-invalid="true"],
select[aria-invalid="true"],
textarea[aria-invalid="true"] { border-color: var(--error); }

.error-msg {
  display: block;
  margin-top: 0.35rem;
  color: var(--error);
  font-weight: 600;
  font-size: 0.95rem;
}
.error-msg:empty { display: none; }

/* The honeypot. Off-screen rather than display:none, which some bots skip. */
.hp {
  position: absolute !important;
  left: -9999px !important;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.form-status { margin: 1rem 0 0; padding: 0.9rem 1rem; border-radius: var(--radius); font-weight: 600; }
.form-status:empty { display: none; padding: 0; margin: 0; }
.form-status.is-ok { background: var(--sage); color: #1d4a22; border-left: 5px solid var(--olive); }
.form-status.is-bad { background: #f7e3e2; color: #7d1d21; border-left: 5px solid var(--error); }

.btn[aria-busy="true"] { opacity: 0.85; cursor: progress; }
.spinner {
  width: 18px;
  height: 18px;
  border: 2.5px solid rgba(255, 255, 255, 0.45);
  border-top-color: #fff;
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ---------------------------------------------------------------- footer */

.site-footer {
  background: var(--canopy);
  color: var(--sage);
  padding: 2.5rem 0 1.5rem;
}
.site-footer h2 { color: var(--sand); font-size: 1.35rem; }
.site-footer a { color: var(--clay-lt); }
.site-footer a:hover { color: #f0a071; }
.footer-grid { display: grid; gap: 1.5rem; }
.footer-phone {
  display: inline-flex;
  align-items: center;
  min-height: 48px;
  font-size: 1.35rem;
  font-weight: 600;
}
.footer-bottom {
  margin-top: 1.75rem;
  padding-top: 1.25rem;
  border-top: 1px solid rgba(214, 226, 200, 0.25);
  font-size: 0.9rem;
}

/* ------------------------------------------------------- reveal on scroll
   Opt-in: the class is only added by JS after IntersectionObserver fires, so
   with JS disabled everything is simply visible from the start.            */

.reveal { opacity: 0; transform: translateY(14px); }
.reveal.is-visible {
  opacity: 1;
  transform: none;
  transition: opacity 0.5s ease, transform 0.5s ease;
}

/* ===================================================================
   480px and up
   =================================================================== */
@media (min-width: 480px) {
  .hero-actions { flex-direction: row; flex-wrap: wrap; }
  .hero-actions .btn { width: auto; min-width: 13.5rem; }
  .header-call .call-word { display: inline; }
}

/* ===================================================================
   768px and up
   =================================================================== */
@media (min-width: 768px) {
  .section { padding: 4.5rem 0; }
  .hero { padding-top: 3.5rem; }
  .grid { grid-template-columns: repeat(2, 1fr); gap: 1.25rem; }
  .gallery { grid-template-columns: repeat(2, 1fr); }
  .footer-grid { grid-template-columns: repeat(3, 1fr); }
  .brand { font-size: 1.35rem; }
  .form-card { padding: 2rem; }
  .form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 0 1rem; }
}

/* ===================================================================
   1024px and up
   =================================================================== */
@media (min-width: 1024px) {
  .grid { grid-template-columns: repeat(3, 1fr); }
  .hero-figure img { max-height: 46vh; }
}

/* ------------------------------------------------- reduced motion
   Anyone who asked their OS for less motion gets none: no smooth scroll,
   no fade-ins, no spinner rotation.                                     */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal { opacity: 1; transform: none; }
  .reveal.is-visible { transition: none; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

/* -------------------------------------------------------------- print
   Someone printing this wants the phone number and what he does. Strip
   the furniture, put the real URL and number where they can be read.     */

@media print {
  .site-header, .hero-figure, .gallery, .skip-link,
  .hero-actions, #quote form, .form-status { display: none !important; }

  body { background: #fff; color: #000; font-size: 12pt; }
  .section { padding: 0.75rem 0; }
  .card, .form-card, .towns li { border: 1px solid #999; box-shadow: none; }
  .hero, .site-footer { background: #fff !important; color: #000 !important; }
  .hero h1, .hero-sub, .hero-free,
  .site-footer, .site-footer h2, .site-footer a { color: #000 !important; }

  a[href^="tel:"]::after { content: " (" attr(href) ")"; }
  a[href^="tel:"] { text-decoration: none; }
  #quote::after {
    content: "To book: call or text 609-271-7705.";
    display: block;
    font-weight: 700;
    margin-top: 0.5rem;
  }
}
