/*
 * Hand-written styles shared by every page on the marketing site — the rules
 * Tailwind utilities cannot express: keyframes, pseudo-element texture, the
 * FAQ disclosure state machine, and the header geometry tokens.
 *
 * Loaded after assets/tailwind.css so these win on equal specificity.
 *
 * This file exists so the Content-Security-Policy can forbid inline <style>
 * blocks. Do not move rules back into the pages.
 */

/* ── Header geometry — one source of truth ─────────────────────────────────
 * The fixed nav's height is set here, never by transparent padding inside the
 * logo file, and anchor scroll offsets derive from the same variable. Change
 * --nav-h and the header, the hero clearance and every in-page anchor follow.
 *
 * --logo-h is deliberately close to --nav-h. The header lockup is
 * logo-header.png, which is the brand mark cropped just below "Twin Oak" — the
 * "LANDSCAPING LLC" rule under it rendered about 3px tall at header scale and
 * was unreadable texture, while still taking a fifth of the vertical budget
 * away from the part of the logo people actually read. With that line gone the
 * lockup can run nearly the full height of the bar without crowding it.
 */
:root {
  --nav-h: 68px;
  --logo-h: 52px;
}

@media (min-width: 1024px) {
  :root {
    --nav-h: 76px;
    --logo-h: 60px;
  }
}

.nav-bar  { height: var(--nav-h); }
.logo-img { height: var(--logo-h); filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.10)); }

html {
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--nav-h) + 12px);
}

/* ── Entrance animation ─────────────────────────────────────────────────── */
@keyframes fadeUp {
  from { opacity: 0; transform: translateY(28px); }
  to   { opacity: 1; transform: translateY(0); }
}

.au { animation: fadeUp 0.85s cubic-bezier(0.22, 1, 0.36, 1) forwards; opacity: 0; }
.d1 { animation-delay: .10s; }
.d2 { animation-delay: .24s; }
.d3 { animation-delay: .38s; }
.d4 { animation-delay: .52s; }
.d5 { animation-delay: .66s; }
.d6 { animation-delay: .80s; }

/* ── Film grain over the dark green sections ───────────────────────────── */
.grain::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 2;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 512 512' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.09'/%3E%3C/svg%3E");
}

/* ── FAQ disclosure ────────────────────────────────────────────────────────
 * display:none is what removes a closed answer from the accessibility tree;
 * site.js keeps aria-expanded in step with the .open class.
 */
.faq-answer { display: none; }
.faq-item.open .faq-answer  { display: block; }
.faq-item.open .faq-chevron { transform: rotate(180deg); }
.faq-chevron { transition: transform .25s; }

/* ── Cards ─────────────────────────────────────────────────────────────── */
.svc-card,
.rel-card { transition: border-color .25s, box-shadow .25s, transform .25s; }

.svc-card:hover {
  border-color: #4a6a38;
  box-shadow: 0 12px 40px rgba(74, 106, 56, .13), 0 2px 8px rgba(0, 0, 0, .06);
  transform: translateY(-3px);
}

.rel-card:hover {
  border-color: #4a6a38;
  box-shadow: 0 12px 36px rgba(74, 106, 56, .13), 0 2px 8px rgba(0, 0, 0, .05);
  transform: translateY(-3px);
}

.step-card { transition: transform .25s cubic-bezier(0.22, 1, 0.36, 1), box-shadow .25s; }
.step-card:hover {
  transform: translateY(-3px);
  box-shadow: 0 14px 40px rgba(58, 77, 43, .16), 0 2px 8px rgba(0, 0, 0, .05);
}

/* ── Secondary services ────────────────────────────────────────────────────
 * The six out-of-season services share the .svc-card markup with the two the
 * page is actually selling, and must not share their weight. Compacting them
 * here rather than editing six near-identical cards means the hierarchy is one
 * rule, and restoring parity in spring is deleting one rule.
 *
 * The icon disc keeps its 52px box for layout but the glyph inside shrinks, so
 * the row heights stay even whichever card has the longest description.
 */
.svc-secondary .svc-card { padding: 1.25rem 1.375rem; }
.svc-secondary .svc-card h3 { font-size: 1rem; margin-bottom: .375rem; }
.svc-secondary .svc-card > div:first-child {
  width: 38px;
  height: 38px;
  margin-bottom: .875rem;
}
.svc-secondary .svc-card > div:first-child svg { width: 1.125rem; height: 1.125rem; }
.svc-secondary .svc-card p { font-size: .8125rem; }

/* The "Learn more" row is revealed on hover, so it is invisible but still
 * occupies its line — which left every compact card with a band of dead space
 * under the description. The whole card is a link and lifts on hover; it does
 * not need a second affordance at this size. */
.svc-secondary .svc-card > div:last-of-type { display: none; }

/* ── Portfolio gallery ─────────────────────────────────────────────────── */
.gallery-item img       { transition: transform .55s cubic-bezier(0.22, 1, 0.36, 1); }
.gallery-item:hover img { transform: scale(1.06); }
.gallery-item .ov       { transition: opacity .3s; }
.gallery-item:hover .ov { opacity: 1 !important; }
.gallery-item:hover .ov-label { opacity: 1 !important; }
.ov-label { transition: opacity .3s; }

/* ── Button hover treatments ───────────────────────────────────────────────
 * These were `onmouseover`/`onmouseout` attributes writing to element.style.
 * Inline handlers are script under CSP, so with `script-src 'self'` they stop
 * running and the buttons go inert on hover. As CSS they also pick up keyboard
 * focus and touch-press states, which the JS version never had.
 *
 * The base colours stay as inline `style` attributes on the elements; only the
 * state changes live here, so :hover has to win with a slightly heavier hand.
 */
.btn-brown:hover,
.btn-brown:focus-visible { background: #9a7248 !important; }

.btn-cream:hover,
.btn-cream:focus-visible { background: #f9f7f0 !important; }

.btn-forest:hover,
.btn-forest:focus-visible { background: #4a6235 !important; }

.btn-ghost-cream:hover,
.btn-ghost-cream:focus-visible {
  border-color: rgba(245, 241, 232, .8) !important;
  color: #F5F1E8;
}

.btn-ghost-white:hover,
.btn-ghost-white:focus-visible {
  border-color: rgba(245, 241, 232, .7);
  color: #F5F1E8;
}

/* ── Mobile action bar ─────────────────────────────────────────────────────
 * Pads itself clear of the iOS home indicator and the Android gesture bar.
 * Without this the second row of a two-action bar sits under the system
 * affordance and the bottom few pixels of both buttons are unreachable.
 */
.mobile-bar { padding-bottom: calc(0.625rem + env(safe-area-inset-bottom, 0px)); }

/* The bar is fixed, so the last rows of the footer would otherwise sit under
 * it with no way to scroll them clear. Only below the lg breakpoint, which is
 * the only place the bar exists. */
@media (max-width: 1023px) {
  body:has(.mobile-bar) {
    padding-bottom: calc(4.5rem + env(safe-area-inset-bottom, 0px));
  }
}

/* ── Sticky call button ────────────────────────────────────────────────────
 * home.js adds .call-btn-managed once it takes control, then toggles
 * .call-btn-hidden while the estimate form is on screen. Without JS the button
 * simply stays visible, which is the safe default.
 */
.call-btn-managed {
  transition: opacity .25s cubic-bezier(0.22, 1, 0.36, 1),
              transform .25s cubic-bezier(0.22, 1, 0.36, 1);
}

.call-btn-hidden {
  opacity: 0;
  transform: translateY(12px) scale(.94);
  pointer-events: none;
}

/* ── Motion preferences ────────────────────────────────────────────────────
 * Honour a reduced-motion request: entrance animations resolve immediately
 * rather than being skipped, so nothing is left stuck at opacity 0.
 */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  .au {
    animation: none;
    opacity: 1;
  }

  .svc-card,
  .rel-card,
  .step-card,
  .gallery-item img,
  .call-btn-managed,
  .faq-chevron {
    transition-duration: .01ms;
  }

  /* The bar still has to disappear over the form — that is a mis-tap guard,
   * not decoration — but it does it without sliding. */
  .call-btn-hidden { transform: none; }

  .svc-card:hover,
  .rel-card:hover,
  .step-card:hover,
  .gallery-item:hover img {
    transform: none;
  }
}
