/* ==========================================================================
   Jobson Garden — site motion (2026-10-09)
   One motion language for every page. Elements are tagged automatically by
   assets/js/site-motion.js (data-m="words|up|fade|card|img"); nothing here
   hides anything unless that script has run and added html.m-on, so a
   failure leaves a normal, static page.
   Replaces the scattered older effects (data-rv, data-float, .reveal and the
   per-page entrance keyframes), which are neutralised below so nothing
   animates twice.
   ========================================================================== */

@property --ps { syntax: '<number>'; inherits: false; initial-value: 1; }

:root {
  --m-ease: cubic-bezier(0.16, 1, 0.3, 1);
  --m-dist: 1;                       /* 0.5 for visitors with reduced motion */
}
html.m-soft { --m-dist: 0.5; }

/* ---- Older systems, switched off ---------------------------------------- */
html.m-on [data-rv], html.m-on [data-rv].rv-in,
html.m-on [data-float], html.m-on [data-float].float-in,
html.m-on .reveal, html.m-on .reveal.is-in,
html.m-on .page-cover__eyebrow, html.m-on .page-cover__title, html.m-on .page-cover__lede,
html.m-on .contact-head__eyebrow, html.m-on .contact-head__title, html.m-on .contact-head__subtitle,
html.m-on .contact-card, html.m-on .contact-feature-media, html.m-on .contact-info-col, html.m-on .contact-promo-card,
html.m-on #plantation .feature__media, html.m-on #plantation .feature__body,
html.m-on .blog-col-left .blog-card-tall, html.m-on .blog-col-right .blog-row,
html.m-on .page-cover__img {
  animation: none !important;
  opacity: 1;
  transform: none;
}

/* Fix (2026-10-10): cover titles (h1 with data-rv inside [data-motion]) stayed
   at opacity 0 — motion.css's ".js [data-motion] [data-rv]" outranks the
   neutraliser above, and headlines (data-m="words") have no reveal rule of
   their own because only their words move. */
html.m-on [data-m="words"] { opacity: 1 !important; transform: none !important; animation: none !important; }

/* ---- Hidden states (only once tagged, only before revealed) ------------- */
html.m-on [data-m="up"]:not(.m-in) {
  opacity: 0 !important;
  transform: translate3d(0, calc(30px * var(--m-dist)), 0) !important;
}
html.m-on [data-m="fade"]:not(.m-in) {
  opacity: 0 !important;
  transform: translate3d(calc(-14px * var(--m-dist)), 0, 0) !important;
}
html.m-on [data-m="card"]:not(.m-in) {
  opacity: 0 !important;
  transform: translate3d(0, calc(54px * var(--m-dist)), 0) scale(0.97) !important;
}
html.m-on [data-m="img"] {
  transform: translate3d(0, var(--py, 0px), 0) scale(calc(var(--pz, 1) * var(--ps)));
  will-change: transform;
}
html.m-on [data-m="img"]:not(.m-in) {
  --ps: 1.16;
  opacity: 0 !important;
  clip-path: inset(16% 12% 16% 12% round 24px);
}

/* ---- Revealed ------------------------------------------------------------ */
html.m-on [data-m="up"].m-in,
html.m-on [data-m="fade"].m-in,
html.m-on [data-m="card"].m-in {
  opacity: 1 !important;
  transform: none !important;
  transition:
    opacity 0.9s ease var(--d, 0ms),
    transform 1.25s var(--m-ease) var(--d, 0ms),
    box-shadow 0.5s ease !important;
}
html.m-on [data-m="img"].m-in {
  opacity: 1 !important;
  clip-path: inset(0 0 0 0 round 0);
  transition:
    opacity 0.7s ease var(--d, 0ms),
    clip-path 1.4s var(--m-ease) var(--d, 0ms),
    --ps 1.8s var(--m-ease) var(--d, 0ms) !important;
}
/* After the entrance, hovers react instantly. */
html.m-on [data-m].m-done { --d: 0ms; }

/* ---- Headlines: word by word -------------------------------------------- */
html.m-on [data-m="words"] .mw { display: inline-block; overflow: hidden; vertical-align: bottom; padding-bottom: 0.1em; margin-bottom: -0.1em; }
html.m-on [data-m="words"] .mw > span {
  display: inline-block;
  transform: translate3d(0, 112%, 0) rotate(5deg);
  transform-origin: left bottom;
}
html.m-on [data-m="words"].m-in .mw > span {
  transform: none;
  transition: transform 1.05s var(--m-ease) calc(var(--d, 0ms) + var(--i) * 55ms);
}

/* ---- Cards lift on hover ------------------------------------------------- */
@media (hover: hover) {
  html.m-on [data-m="card"].m-done.m-hover:hover {
    transform: translate3d(0, -7px, 0) !important;
    box-shadow: 0 26px 46px -28px rgba(26, 35, 27, 0.38);
    transition: transform 0.55s var(--m-ease), box-shadow 0.55s ease !important;
  }
  html.m-on .m-hover img { transition: transform 1.1s var(--m-ease); }
  html.m-on .m-hover:hover img[data-m="img"].m-done { --ps: 1.05; transition: --ps 1.1s var(--m-ease) !important; }
}

/* ---- Scroll progress line ----------------------------------------------- */
.m-progress {
  position: fixed; left: 0; top: 0; z-index: 300;
  width: 100%; height: 3px;
  background: linear-gradient(90deg, var(--leaf), var(--accent));
  transform-origin: left center; transform: scaleX(0);
  pointer-events: none;
}

/* ---- Page transition curtain -------------------------------------------- */
.m-curtain {
  position: fixed; inset: 0; z-index: 9999;
  display: grid; place-items: center;
  background: var(--primary);
  color: #fff; font-family: var(--font-display); font-size: 1.1rem; letter-spacing: 0.02em;
  transform: translate3d(0, 100%, 0);
  pointer-events: none;
}
.m-curtain span { opacity: 0; transform: translate3d(0, 12px, 0); transition: opacity 0.3s ease, transform 0.5s var(--m-ease); }
/* Arriving from a transition: the class is set in <head>, so this covers the
   page from the very first paint, then lifts away. Pure CSS, no waiting. */
html.pt-in body::after {
  content: 'jobson garden';
  position: fixed; inset: 0; z-index: 9999;
  display: grid; place-items: center;
  background: var(--primary); color: rgba(255, 255, 255, 0.9);
  font-family: var(--font-display); font-size: 1.1rem; letter-spacing: 0.02em;
  animation: mCurtainOut 0.9s cubic-bezier(0.7, 0, 0.2, 1) 0.2s forwards;
  pointer-events: none;
}
html.pt-out .m-curtain { animation: mCurtainIn 0.55s cubic-bezier(0.7, 0, 0.2, 1) forwards; pointer-events: all; }
html.pt-out .m-curtain span { opacity: 1; transform: none; transition-delay: 0.25s; }
@keyframes mCurtainIn  { from { transform: translate3d(0, 100%, 0); } to { transform: none; } }
@keyframes mCurtainOut { from { transform: none; } to { transform: translate3d(0, -100%, 0); } }
@keyframes mFadeOut { to { opacity: 0; } }

/* ---- Reviews: scroll-driven strip ---------------------------------------- */
html.m-on .g-marquee-viewport { overflow: hidden; }
html.m-on .g-marquee-track { animation: none !important; will-change: transform; }

/* ---- Smooth scroll (Lenis) ---------------------------------------------- */
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
.lenis.lenis-stopped { overflow: hidden; }

/* ==========================================================================
   Transitions (2026-10-13) — a softer, cinematic hand-off between sections and
   between pages. Only transform and opacity move. Both are skipped when the
   visitor asks for reduced motion, and the browser simply ignores them if it
   cannot do them (older phones): the page then looks exactly as before.
   ========================================================================== */

/* 1. Page to page: a quick cross-fade. No cover screen, no waiting. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
  ::view-transition-old(root) { animation: 160ms cubic-bezier(0.4, 0, 1, 1) both jgVtOut; }
  ::view-transition-new(root) { animation: 260ms cubic-bezier(0, 0, 0.2, 1) both jgVtIn; }
}
@keyframes jgVtOut { to { opacity: 0; } }
@keyframes jgVtIn  { from { opacity: 0; } }

/* 2. Section to section: each band settles into place as it scrolls in,
      growing from a slightly smaller card and brightening as it arrives.
      Ends before the section is fully in view, then leaves no transform
      behind (so pinned or fixed things inside are never affected). */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    .section, .about-green, .about-process, .about-quote, .blog-cta-strip,
    .home-initiatives, .g-reviews-section {
      transform-origin: 50% 0;
      animation: jgSettle linear backwards;
      animation-timeline: view();
      animation-range: entry 0% entry 55%;
    }
  }
}
@keyframes jgSettle {
  from { opacity: 0.35; transform: translate3d(0, 5vh, 0) scale(0.94); }
  to   { opacity: 1;    transform: none; }
}

/* No white strip between the last section and the footer (2026-10-13). The
   footer's usual top margin only suited pages whose last block is white. */
body.page-services .site-footer, body.page-blog .site-footer, body.page-about .site-footer { margin-top: 0; }

/* Unwanted blank space (2026-10-13). Home: the 'What we grow' card had ~210px of
   white under it before the footer, and a tall empty corner under the three
   plant cards. Contact / reviews: a 96px white strip above the footer. */
body.page-index .site-footer { margin-top: 0; }
.home-initiatives { padding-bottom: clamp(1.5rem, 3vw, 2.5rem); }
body.page-contact .site-footer, body.page-review .site-footer { margin-top: clamp(1.5rem, 3vw, 2.5rem); }
@media (min-width: 1025px) {
  .initiative-card__media img { aspect-ratio: 4 / 5; }
}

/* Compact footer on every page (2026-10-13). The map sat under the contact
   lines, which made the last column twice as tall as the others and left a
   blank block to its left. Now the map stands beside the contact lines,
   the footer is about half as tall, and on phones Explore and Our Work share
   a row. */
.site-footer { padding-block: clamp(2.5rem, 4vw, 3.5rem) 1.25rem; }
.site-footer__legal { margin-top: clamp(1.5rem, 3vw, 2.25rem); padding-top: 1rem; }
.site-footer__brand .brand__logo { margin-bottom: 1rem; }
.site-footer__inner { grid-template-columns: 1.05fr 0.7fr 0.95fr 2.3fr; gap: clamp(1.25rem, 2.5vw, 2.5rem); }
.site-footer__contact {
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  column-gap: clamp(1rem, 2vw, 1.75rem); align-content: start;
}
.site-footer__contact > * { grid-column: 1; }
.site-footer__contact > .site-footer__heading { grid-column: 1 / -1; }
.site-footer__contact > .site-footer__map {
  grid-column: 2; grid-row: 2 / span 3; margin-top: 0;
  aspect-ratio: auto; max-height: none; height: 100%; min-height: 11rem;
}
.site-footer__contact > .site-footer__directions { grid-column: 2; grid-row: 5; }
@media (max-width: 1024px) {
  .site-footer__inner { grid-template-columns: 1fr 1fr; }
  .site-footer__contact { grid-column: 1 / -1; }
}
@media (max-width: 768px) {
  .site-footer { padding-top: 2.25rem; padding-bottom: calc(1.25rem + var(--bottom-nav-h, 88px)); }
  .site-footer__inner { grid-template-columns: 1fr 1fr; gap: 1.5rem 1rem; }
  .site-footer__brand, .site-footer__contact { grid-column: 1 / -1; }
  .site-footer__contact { grid-template-columns: 1fr; }
  .site-footer__contact > .site-footer__map { grid-column: 1; grid-row: auto; height: auto; aspect-ratio: 16 / 9; min-height: 0; margin-top: 0.75rem; }
  .site-footer__contact > .site-footer__directions { grid-column: 1; grid-row: auto; }
  .site-footer__links a { min-height: 40px; }
  .site-footer__legal { gap: 0.25rem; }
}
