/* ==========================================================================
   MANA AGRI STORE — MAIN STYLESHEET
   Design system: colors, typography, layout, components, animations.
   Breakpoint overrides live in responsive.css (loaded after this file).
   ========================================================================== */

/* ---------- Design tokens ---------- */
:root {
  /* Colors */
  --primary-green: #3B8F3A;
  --dark-green: #1F4F2D;
  --accent: #7DBA3B;
  --white: #FFFFFF;
  --bg: #F7F9F6;
  --dark: #172417;
  /* Targeted purple accent — header/hero CTA buttons and the 7 shared
     .section-heading elements (see that rule below), not a sitewide
     heading color like the earlier (reverted) --heading experiment. */
  --purple-accent: #5c2b8e;
  --purple-accent-hover: #5a0b87;

  /* Derived / utility colors */
  --text-body: #3A4A3D;
  --text-muted: #6B7A6D;
  --border-soft: rgba(31, 79, 45, 0.12);
  --shadow-soft: 0 20px 40px -20px rgba(23, 36, 23, 0.25);
  --shadow-card: 0 12px 30px -14px rgba(31, 79, 45, 0.28);
  --label-muted: rgba(31, 79, 45, 0.72);
  --input-border: rgba(31, 79, 45, 0.16);

  /* Typography */
  --font-display: 'Plus Jakarta Sans', 'Segoe UI', sans-serif;
  --font-body: 'Inter', 'Segoe UI', sans-serif;

  /* Layout */
  --container-w: 1200px;
  /* 4-7rem -> 2.5-4rem (~40-64px, was ~64-112px): one shared, tighter
     value for the vertical gap at every major section boundary (About,
     Bright Tomorrow, Services, Why Choose Us, Contact, Footer), applied
     uniformly rather than tuned per section — see each section's own
     padding-block/padding-top rule, all of which reference this same
     token so they can't drift out of sync with each other. */
  --section-pad: clamp(2.5rem, 4vw, 4rem);
  /* Shared left-edge inset for the header logo and the hero content
     block, so they line up instead of each having an independently
     tuned padding value. Referenced by both .header__inner (adjusted
     for the logo badge's own internal padding) and .hero__overlay. */
  --content-inset: clamp(1.5rem, 5vw, 5rem);
  --radius-sm: 10px;
  --radius-md: 18px;
  --radius-lg: 28px;

  /* Motion */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --dur-fast: 220ms;
  --dur-med: 480ms;
  --dur-slow: 800ms;
}

/* ---------- Reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
/* overflow-x:hidden fixes a real, repeatedly-flagged bug: .nav (the
   mobile off-canvas menu, responsive.css) is position:fixed with
   inset:0 0 0 auto (right:0) and transform:translateX(100%) to sit
   hidden just past the right edge when closed. That's the correct way
   to hide it, but document.documentElement.scrollWidth still counts
   its transformed (off-screen) position as page content in this
   browser's overflow calculation, which was inflating scrollWidth by
   the nav's own width (up to ~320px) at every viewport <=768px —
   previously misdiagnosed as a harmless "measurement artifact" and
   left unfixed across several earlier sessions. It never produced a
   VISIBLE scrollbar (browsers generally don't rubber-band/scroll to
   reveal fixed-position content), but it was real: any accessibility
   tooling or precise viewport-fit check reading scrollWidth directly
   would flag it. overflow-x:hidden on the root simply clips anything
   extending past the viewport horizontally, closed nav included,
   without touching the nav's own positioning/transform/transition
   logic — confirmed by measurement this removes the overflow entirely
   at every tested width from 320px to 2560px. */
html { scroll-behavior: smooth; overflow-x: hidden; }
body, h1, h2, h3, h4, p, ul, ol, figure, blockquote { margin: 0; }
ul { list-style: none; padding: 0; }
img { max-width: 100%; height: auto; display: block; }
button { font: inherit; background: none; border: none; cursor: pointer; }
a { color: inherit; text-decoration: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

body {
  overflow-x: hidden;
  font-family: var(--font-body);
  font-weight: 400;
  color: var(--text-body);
  background: var(--bg);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  color: var(--dark-green);
  line-height: 1.15;
  font-weight: 700;
}

h1 { font-size: clamp(2.4rem, 4.4vw, 3.6rem); font-weight: 800; letter-spacing: -0.01em; }
h2 { font-size: clamp(1.9rem, 3.2vw, 2.6rem); font-weight: 800; }
h3 { font-size: 1.2rem; font-weight: 700; }

p { color: var(--text-body); text-align: justify; }

.container {
  width: 100%;
  max-width: var(--container-w);
  margin-inline: auto;
  padding-inline: 1.5rem;
}

.skip-link {
  position: absolute;
  top: -100px;
  left: 1rem;
  background: var(--dark-green);
  color: var(--white);
  padding: 0.75rem 1.25rem;
  border-radius: var(--radius-sm);
  z-index: 999;
  transition: top var(--dur-fast) var(--ease-out);
}
.skip-link:focus { top: 1rem; }

/* Visible focus states for accessibility */
a:focus-visible,
button:focus-visible,
input:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}

/* .eyebrow (and .eyebrow--light/--accent) removed — every element that
   used it was promoted to .section-heading below or a plain heading tag
   (verified via grep: zero remaining "eyebrow" references anywhere in
   index.html once that promotion was done), so the class had no
   remaining callers left to serve. */

/* Shared visual treatment for 6 of the original 7 section-level
   headings that must render identically (same H2 size/weight/
   line-height, same purple): "Who we are", "What we do", "A bright
   tomorrow for the farmer", "Services for farmer's flourish", "Why
   choose us", and "Get in touch". The "Farming Smarter, Growing
   Better" motto quote was pulled out of this group by later explicit
   instruction — it was reading too large at H2 scale, and is now a
   real <h3> sized off the sitewide h3 rule instead (see .motto h3).
   The remaining 6 were a mix of plain <p class="eyebrow"> labels
   (small, letter-spaced, green) and real headings before this change;
   tag was promoted to h2 where the element serves as its section's own
   heading (kept as h3 for "What we do" — a nested heading under "Who we
   are", correctly one level down — see the HTML for the per-element
   call). Size/weight/line-height intentionally match the global h2
   rule exactly (clamp(1.9rem, 3.2vw, 2.6rem) / 800 / 1.15) so applying
   this class to an element that's already a real <h2> (Services) is a
   color-only change, not a resize. */
.section-heading {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(1.9rem, 3.2vw, 2.6rem);
  font-weight: 800;
  line-height: 1.15;
  color: var(--purple-accent);
  margin-bottom: 0.9rem;
}

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.95rem;
  padding: 0.9rem 1.8rem;
  border-radius: 999px;
  transition: transform var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out),
              background var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
  white-space: nowrap;
}
.btn--primary {
  background: var(--primary-green);
  color: var(--white);
  box-shadow: 0 10px 24px -8px rgba(59, 143, 58, 0.55);
}
.btn--primary:hover {
  background: var(--dark-green);
  transform: translateY(-2px);
  box-shadow: 0 14px 28px -8px rgba(31, 79, 45, 0.55);
}
.btn--ghost {
  background: transparent;
  color: var(--dark-green);
  border: 1.5px solid var(--border-soft);
}
.btn--ghost:hover {
  background: var(--white);
  border-color: var(--primary-green);
  transform: translateY(-2px);
}
.btn--outline {
  background: transparent;
  color: var(--white);
  border: 1.5px solid rgba(255,255,255,0.4);
}
.btn--outline:hover {
  background: var(--accent);
  color: var(--dark);
  border-color: var(--accent);
  transform: translateY(-2px);
}

/* Signature "contour-line" motif (.contour-line/.section-divider) fully
   removed by explicit instruction — it was the wavy white line sitting
   between .about__tomorrow and .services, and its only instance in the
   codebase (confirmed via grep of index.html, zero remaining
   references to either class). Deleted rather than hidden: markup
   removed from index.html, and this rule block removed rather than
   left as dead CSS. */

/* ==========================================================================
   HEADER
   ========================================================================== */
/* Solid white at all times now — no more transparent-over-hero state
   (see removed .site-header:not(.is-scrolled) overrides below, obsolete
   now that nothing sits transparently over the purple hero).
   Fully opaque, no backdrop-filter — the header is `position:fixed`, so
   it floats directly over the hero's top edge (hero starts at y:0, the
   header doesn't push it down) rather than sitting above it in normal
   flow. An earlier rgba(255,255,255,0.92) + blur(10px) "glass" version
   of this rule was never actually solid: the 8% transparency plus the
   blur let a soft, blurred wash of whatever's underneath show through —
   invisible over the old off-white/photo hero, but a visible
   light-green/white band once the hero became solid purple with a green
   wedge right at its top edge. Full var(--white) opacity removes any
   bleed-through. .is-scrolled still toggles via JS and still compacts
   the padding on scroll — that size behavior is unrelated to color, so
   it's left as-is. */
.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  background: var(--white);
  box-shadow: 0 6px 24px -12px rgba(23, 36, 23, 0.25);
  transition: box-shadow var(--dur-med) var(--ease-out),
              padding var(--dur-med) var(--ease-out);
  padding-block: 1.15rem;
}
.site-header.is-scrolled {
  padding-block: 0.6rem;
}

/* Deliberately not .container here — .container's 1200px cap plus its
   own auto-centering would leave the logo sitting ~380px+ in from the
   true viewport edge on wide screens (max-width slack / 2, plus the
   container's own padding), nowhere near the "24-40px from the edge"
   this needs. header__inner instead spans the full header width with
   its own small edge inset. */
.header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  /* Left inset = --content-inset directly — the logo badge no longer
     has its own internal padding (see .logo__badge below, now that the
     logo asset itself is transparent), so the logo IMAGE's visual left
     edge already lands exactly on --content-inset with no offset
     needed, matching the hero text's left edge below it. Right side has
     no equivalent "content edge" to match (the hero's right column is a
     full-bleed photo, not text), so it keeps its own independent inset. */
  padding-left: var(--content-inset);
  padding-right: clamp(1.5rem, 3vw, 2.5rem);
}

.logo {
  display: flex;
  align-items: center;
}
/* Logo art (assets/logo.png) is a transparent PNG (verified: mode
   RGBA, genuinely varying alpha) — sits directly on the header/footer
   background with no card/badge treatment. Previously framed in a
   white chip because an earlier flat/opaque version of this asset had
   a solid white backdrop baked in; not needed now. */
.logo__badge {
  display: inline-flex;
  align-items: center;
}
.logo__badge img { height: 52px; width: auto; display: block; }

.nav {
  display: flex;
  align-items: center;
  gap: 2rem;
}
.nav__list {
  display: flex;
  gap: 2.1rem;
  align-items: center;
}
.nav__link {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--dark-green);
  position: relative;
  padding-block: 0.3rem;
  transition: color var(--dur-fast) var(--ease-out);
}
.nav__link::after {
  content: '';
  position: absolute;
  left: 0; bottom: 0;
  width: 0;
  height: 2px;
  background: var(--accent);
  transition: width var(--dur-fast) var(--ease-out);
}
.nav__link:hover::after,
.nav__link:focus-visible::after { width: 100%; }

/* Scoped to this one instance via .nav__cta, not .btn--primary itself —
   the same base class is shared by the contact form's submit button,
   which must stay green. Purple fill / white text, always — this was
   previously the "scrolled state" look; now permanent since the header
   never sits transparently over the hero anymore. */
.nav__cta {
  flex-shrink: 0;
  background: var(--purple-accent);
  box-shadow: 0 10px 24px -8px rgba(106, 13, 163, 0.55);
}
.nav__cta:hover {
  background: var(--purple-accent-hover);
  box-shadow: 0 14px 28px -8px rgba(90, 11, 135, 0.55);
}

.nav-toggle {
  display: none;
  flex-direction: column;
  gap: 5px;
  padding: 0.5rem;
  z-index: 110;
}
.nav-toggle span {
  width: 24px;
  height: 2px;
  background: var(--dark-green);
  border-radius: 2px;
  transition: transform var(--dur-fast) var(--ease-out), opacity var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out);
}

/* ==========================================================================
   HERO
   Rebuilt again as a single full-width banner image (assets/hero-slide.png,
   1905x691, ratio 2.757) with text overlaid directly on top — no more
   split panel, no object-fit crop, no .hero background fill (the image
   supplies 100% of the visual). width:100%/height:auto renders the image
   at its natural ratio with zero cropping, guaranteed by construction.

   margin-top clears .site-header, which is position:fixed (out of flow,
   floating over whatever's beneath it) at a measured 89.875px tall
   unscrolled (getBoundingClientRect, not the earlier 88.8px estimate —
   that estimate left a 14px visible gap of body background between the
   header and the hero image, since 6.5rem/104px overshot the header's
   actual height; margin-top is now set to that exact measured value so
   the hero sits flush against the header with zero gap and zero
   overlap) — this pushes the ENTIRE hero (image included) below the
   header instead of letting the header cover the image's top edge, so
   the full image is visible and the text-safe zone below isn't eaten
   into by the header overlap.

   The overlay box spans the FULL hero height (top:0/bottom:0) and
   vertically centers its content via flex, rather than being confined
   to a bottom-anchored sub-box — centering the block's midpoint at 50%
   down the image. That's still safely inside the clean zone pixel-
   mapped off the source PNG: sampled row-by-row, the image's flat
   solid-purple field (no people, no green diagonal, no logo/storefront
   graphics) only holds a consistent ≥845px-wide margin (of 1905px) from
   y=240px (34.7%) down to the bottom edge — above that the green
   diagonal wedge cuts in as close as x=420px. 845/1905=44.3%, so
   width:40% stays inside that measured clean width with margin to
   spare. The 34.7% floor is now just a reference threshold (not a CSS
   value): as long as the centered text block's own height stays under
   ~30% of the hero's height, its top edge can't rise above y=240px
   regardless of viewport — verified by screenshot at every width the
   overlay layout is used at, not just assumed from the math. Because
   there's no cropping anywhere in this layout, this holds at every
   width in that set (image scales uniformly, never crops) — the ONLY
   thing that can break it is a narrow viewport making the image short
   enough that the centered block's fixed rem-based height stops being
   a small-enough fraction of it; see the <=900px override in
   responsive.css for where that's handled by switching to a stacked
   (image, then text below) layout instead of fighting a shrinking
   image further. */
.hero {
  position: relative;
  margin-top: 89.875px;
}
.hero__img {
  display: block;
  width: 100%;
  height: auto;
}
.hero__overlay {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 40%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 0 1.5rem 0 var(--content-inset);
}
.hero__overlay h1 {
  color: var(--white);
  /* Floor raised 1.5rem -> 1.75rem, ceiling 2.5rem -> 2.75rem — the
     overlay reads against a full-bleed, much larger image now than the
     old 55%-column layout this size was originally tuned for, so it
     needed more presence to still feel confident rather than small. */
  font-size: clamp(1.75rem, 2.9vw, 2.75rem);
  /* 1rem -> 1.25rem: modest bump for better rhythm between heading and
     subtext now that the block is vertically centered and has the
     visual weight of the whole image to hold its own against. */
  margin-bottom: 1.25rem;
}
.hero__lede {
  color: rgba(255,255,255,0.88);
  font-size: clamp(0.9rem, 1.3vw, 1.1rem);
  max-width: 40ch;
  /* Overrides the sitewide p{text-align:justify} default — this is a
     short, narrow-column lede (max-width:40ch) where justify would
     create the same word-gap stretching seen elsewhere in narrow
     contexts (service cards, footer). .hero__lede is the only class on
     this element and has exactly one usage in index.html (confirmed
     via grep), so this is scoped to just the hero subtext. */
  text-align: left;
  /* 1.5rem -> 2rem: same rhythm bump as the heading's margin, giving
     the button a clearer beat of separation from the paragraph above. */
  margin-bottom: 2rem;
}
.hero__actions {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
}
/* Scoped to this one instance via the .hero__actions ancestor, not
   .btn--primary itself — the same base class is shared by the header
   nav CTA (also purple, styled separately via .nav__cta) and the
   contact form's submit button, which must stay green. The footer's
   "Become a Partner" uses .btn--outline entirely, so it's unaffected
   by construction, not by exclusion.
   Inverted to a white fill now that the hero's own background is solid
   purple — the old purple-on-purple fill would have vanished entirely. */
.hero__actions .btn--primary {
  background: var(--white);
  color: var(--purple-accent);
  box-shadow: 0 10px 24px -8px rgba(23, 36, 23, 0.35);
}
.hero__actions .btn--primary:hover {
  background: rgba(255,255,255,0.9);
  transform: translateY(-2px);
  box-shadow: 0 14px 28px -8px rgba(23, 36, 23, 0.4);
}
/* ==========================================================================
   ABOUT
   ========================================================================== */
.about { background: var(--bg); position: relative; }
.about__inner {
  padding-block: var(--section-pad);
  display: grid;
  grid-template-columns: 1.1fr 1fr;
  gap: 4rem;
  /* The storefront photo is an inherently wide, banner-shaped subject
     (a building facade) — forcing it to the text column's full height
     would mean either cropping into the shopfront itself or stretching
     it, neither of which reads as intentional. align-items: center
     instead centers the (naturally shorter) image within the row's
     full height, so leftover space is split evenly above and below
     rather than sitting as one dead gap underneath it. */
  align-items: center;
}

.about__media { position: relative; }
/* box-shadow (and the card-like border-radius that went with it)
   removed so this sits directly on the section background with no
   visible box, matching other images on the site. Note: the PNG itself
   (assets/about-right-side.png) is NOT a clean cutout — pixel-checked
   (System.Drawing, 32bppArgb) and only the far outer corners are
   actually alpha=0; the "sky"/negative-space area around the roofline
   and logo (e.g. sampled at 1500,50 and 1900,20) is opaque white
   (RGB 254,254,254, A=255) baked into the file. That white will still
   read as a faint rectangular patch against this section's --bg
   (#F7F9F6, slightly grayer than the image's near-pure white) no
   matter what's behind it in CSS — border-radius was also dropped
   since rounding the corners of a mostly-opaque-white rectangle would
   just make that patch more visually obvious as a "box", not less.
   A real fix needs a properly transparent-background export of the
   illustration, not a CSS workaround. */
.about__media img {
  width: 100%;
  display: block;
}

/* Intro paragraph and "What We Do" as two distinct beats rather than one
   dense block: a thin rule plus real top space above the subhead,
   matching the same divider language as the stats row below. Used only
   here (single instance, verified against the HTML), so no separate
   scoping needed beyond this class itself.
   Typography (size/weight/color/line-height) no longer lives here —
   "What we do" is one of the 7 headings unified under .section-heading
   (applied alongside this class in the HTML), so only this element's
   own structural rhythm (the divider rule + its spacing) stays. The
   0.8rem margin-bottom is deliberately its own value, not
   .section-heading's 0.9rem default — same specificity, so as the
   later rule in the cascade this one wins, which is intentional: it's
   tuned against this element's own border-top/padding-top, not a value
   that needs to match the other 6 headings' spacing. */
.about__subheading {
  margin-top: 2.4rem;
  padding-top: 1.6rem;
  margin-bottom: 0.8rem;
  border-top: 1px solid var(--border-soft);
}
.about__content p { margin-bottom: 1rem; }

.counters {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.5rem;
  margin-top: 2.4rem;
  padding: 2.2rem 0 0.4rem;
  border-top: 1px solid var(--border-soft);
}
.counter { display: flex; flex-direction: column; gap: 0.4rem; }
/* Number + suffix ("6" + "+") wrapped and laid out as a row so they sit
   on one line instead of stacking as separate flex-column children —
   the .counter column itself still stacks value above label. */
.counter__value { display: flex; align-items: baseline; line-height: 1; }
.counter__num,
.counter__suffix {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 2.75rem; /* ~44px, matched across all three so every
    number+label pair baseline-aligns with its neighbors regardless of
    whether the value is a numeral or the word "All" */
  /* dark-green -> purple-accent (#5c2b8e): 9.58:1 against white,
     9.05:1 against --bg, both confirmed. .counter__label stays
     var(--text-muted) — only the large value itself changes. */
  color: var(--purple-accent);
}
.counter__label {
  font-size: 0.82rem;
  color: var(--text-muted);
  font-weight: 500;
  line-height: 1.35;
}

/* Full-bleed right-hand visual + contained text column (same
   --content-inset the header/hero use for their own left edge), instead
   of the previous flat text-on-color block with empty space on the
   right. Solid brand purple per the client's reference design for this
   section (previously a dark-green-family gradient). */
.about__tomorrow {
  position: relative;
  overflow: hidden;
  display: grid;
  grid-template-columns: 1.3fr 1fr;
  background: var(--purple-accent);
}
.about__tomorrow-content {
  display: flex;
  flex-direction: column;
  justify-content: center;
  /* Was deliberately MORE than var(--section-pad) (a dedicated
     clamp(5rem,9vw,8rem), because the image column bleeds full-height
     with no padding of its own so this was the only place breathing
     room needed adding) — now uses the same shared token as every other
     section boundary per the sitewide spacing-reduction pass, rather
     than keeping its own larger special case. Left/right stay their
     own values (3rem / --content-inset) since those are horizontal
     column layout, not the vertical section-to-section rhythm this
     token controls. */
  padding: var(--section-pad) 3rem var(--section-pad) var(--content-inset);
  /* Single shared width constraint for ALL text in this section — the
     H2 and both paragraphs have no width/max-width of their own
     (removed below), so as plain block children of this flex column
     they all fill exactly this box and nothing else. That's what
     guarantees a matching right edge at every viewport by construction
     (earlier per-element attempts — no cap at all, then a px value
     pinned to one specific measurement — either drifted apart at
     widths other than where they were tuned, or matched only
     coincidentally).
     60ch (~605px) -> 680px -> 900px. 680px (tried first, in the
     650-700px range initially requested) still left a visibly large
     gap specifically at 1920px: the .about__tomorrow grid only gives
     the text column 1.3/2.3 of the section width to begin with (its
     own natural width runs ~570px at 1200px up to ~957px at 1920px,
     measured previously), and 680px is well short of that natural
     ceiling — confirmed by screenshot, ~405px of unused purple
     remained before the image at 1920px. 900px sits close enough to
     that ~957px natural ceiling that it barely constrains anything at
     any commonly-tested width (1200/1440/1920px all render at their
     own natural width, unconstrained, since none of them reach 900px)
     — it only starts acting as an actual cap on monitors wider than
     ~1920px, which is exactly the readability-safeguard role a
     max-width is for, without costing visible space at any width this
     was actually tested against. Confirmed by re-measurement: gap
     before the image stays positive (no crowding) at 1200/1440/1920px. */
  max-width: 900px;
}
/* One explicit exception to .section-heading's shared purple: this
   panel's own background IS that same purple (var(--purple-accent),
   see .about__tomorrow above), so #5c2b8e text here would be literally
   invisible. White was confirmed as the fix — it also matches this
   panel's existing paragraph color (rgba(255,255,255,.88)), so the
   heading and body text read as one consistent white-on-purple
   treatment rather than introducing a third color.
   white-space:nowrap forces "A bright tomorrow for the farmer" onto
   one line at every width, per explicit instruction — smaller text is
   acceptable, wrapping is not. This overrides .section-heading's own
   font-size (clamp(1.9rem,3.2vw,2.6rem), tuned for the other 5 shared
   headings, which are too big for this specific longer phrase to fit
   on one line at any but the widest viewports) with a clamp measured
   specifically for this instance: this rule only applies at >900px
   (the desktop 2-column .about__tomorrow layout — see the <=900px
   override in responsive.css for the stacked mobile layout, which
   needs a different, much smaller range since that layout gives this
   column less width at comparable viewport sizes, not more).
   Calibrated by temporarily allowing wrap to measure this column's
   TRUE available width unaffected by nowrap's own min-content sizing
   (a nowrapped element's intrinsic min-width can otherwise force its
   grid/flex ancestors wider than the viewport — confirmed this was
   happening before sizing was fixed), then finding the largest integer
   px per viewport whose single-line width still fit with an 8px
   safety margin: 912px allows up to 25px, 1200px up to 30px, 1440px
   and 1920px up to 29px. clamp(1.5rem/24px, 2.2vw, 1.75rem/28px) stays
   at or under all of those (24px at 912px's 2.2vw=20px→floor, 26.4px
   at 1200px, 28px ceiling at 1440px+) with margin to spare at every
   one — verified by rendering (not just this arithmetic) at 912, 1200,
   1440, 1920px, zero page overflow. */
.about__tomorrow-content .section-heading {
  color: var(--white);
  white-space: nowrap;
  font-size: clamp(1.5rem, 2.2vw, 1.75rem);
}
.about__tomorrow-p {
  color: rgba(255,255,255,0.88);
  /* No max-width here — see .about__tomorrow-content's max-width:60ch,
     the single shared cap all text elements in this section rely on
     instead of individually-tuned values.
     text-align:left is still needed on its own merits, independent of
     the width question: these are <p> elements and would otherwise
     catch the sitewide p{text-align:justify} default (style.css:93),
     which h2/h3 never do (not <p>s) — justify stretches non-last lines
     to touch both edges of the box, which reads as a stretched-gap
     artifact the same way it did in service cards/footer earlier. */
  text-align: left;
  margin-bottom: 1.8rem;
  font-size: 1.05rem;
}
.about__tomorrow-p:last-child { margin-bottom: 0; }

.about__tomorrow-media {
  position: relative;
  min-height: 480px;
  overflow: hidden;
}
.about__tomorrow-media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Centered horizontally to keep both drones + the sunset glow in
     frame; vertical bias toward the crop/field action rather than the
     sky, matching the previous photo's field-biased framing. No color
     treatment — text no longer overlaps this image (it sits in the
     separate purple panel to the left), so the photo shows clean at
     full natural color per the client's reference design. */
  object-position: center 60%;
}

/* ==========================================================================
   SERVICES — uniform grid, real hover interactions
   ========================================================================== */
/* white -> var(--bg), matching About/Contact's shared light-gray tone.
   .why-us directly below stays var(--white) (unchanged) — the two are
   no longer the same color, so its border-top (added specifically
   because Services and Why-Choose-Us used to both be white and ran
   together without one) is now redundant, though harmless to leave;
   see that rule's own comment. */
.services { background: var(--bg); padding-block: var(--section-pad); }
.section-head { max-width: 62ch; margin-bottom: 3rem; }
.section-head h2 { margin-top: 0.4rem; }
/* No margin here — spacing between this and its siblings (the "Why
   choose us" heading above, motto below) is handled entirely by the
   flex gap on the .why-us__content column that wraps all three now. */
.why-us__lede { font-size: 1.05rem; max-width: 68ch; margin: 0; }

/* Every card is the same grid cell size; a row's items still equalize
   in height automatically (grid's default align-items: stretch), and
   min-height on .service-card below gives that a floor so a short card
   next to a long one in the same row doesn't look accidentally small. */
.services__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.25rem;
}

.service-card {
  position: relative;
  display: flex;
  flex-direction: column;
  min-height: 230px;
  border-radius: var(--radius-md);
  padding: 1.9rem;
  overflow: hidden;
  transition: transform var(--dur-med) var(--ease-out),
              box-shadow var(--dur-med) var(--ease-out);
  isolation: isolate;
}
/* Solid alternating fills by grid position (1-indexed: odd = purple,
   even = green), replacing the old off-white-card + reveal-on-hover
   treatment. Shadow on hover renders in the white section background
   around the card, not over the card's own fill, so --shadow-card
   (a dark, 28%-opacity rgba) reads the same regardless of which fill
   color the lifted card has — verified, no per-color shadow needed. */
.services__grid .service-card:nth-child(odd) { background: var(--purple-accent); }
.services__grid .service-card:nth-child(even) { background: #3fb80d; }
.service-card:hover,
.service-card:focus-within {
  transform: translateY(-4px);
  box-shadow: var(--shadow-card);
}
.service-card:hover .service-card__icon,
.service-card:focus-within .service-card__icon {
  transform: scale(1.08) rotate(-6deg);
}

/* No badge/chip behind the icon — it sits directly on the card's own
   solid fill. Glyph toward the box's top-left instead of dead center,
   a small deliberate asymmetry rather than a perfectly centered mark. */
.service-card__icon {
  width: 48px; height: 48px;
  flex-shrink: 0;
  display: flex; align-items: flex-start; justify-content: flex-start;
  margin-bottom: 1.1rem;
  transition: transform var(--dur-med) var(--ease-out);
}
.services__grid .service-card:nth-child(odd) .service-card__icon { color: var(--white); }
.services__grid .service-card:nth-child(even) .service-card__icon { color: var(--dark); }
.service-card h3 {
  margin-bottom: 0.55rem;
  font-size: 1.08rem;
}
/* text-align:left overrides the sitewide p{text-align:justify} default —
   these cards are ~350px wide at the 3-column desktop grid (narrower
   still stacked on mobile), too narrow for justify to space words
   evenly; confirmed by screenshot that it produces visible word-gap
   rivers on any 2+ line description at that width. */
.service-card p {
  font-size: 0.92rem;
  text-align: left;
}
.services__grid .service-card:nth-child(odd) h3,
.services__grid .service-card:nth-child(odd) p {
  color: var(--white);
}
.services__grid .service-card:nth-child(even) h3,
.services__grid .service-card:nth-child(even) p {
  color: var(--dark);
}

/* ==========================================================================
   WHY CHOOSE US
   ========================================================================== */
/* Same white as .services above it, so a thin top border is needed here
   to mark where one section ends and the next begins — without it the
   two run together as one unbroken white block (confirmed by screenshot
   before adding this). */
.why-us {
  background: var(--white);
  border-top: 1px solid var(--border-soft);
  padding-block: var(--section-pad);
}

/* Genuine two-column pairing (not two stacked rows): mascot on the
   left, ALL text (eyebrow, lede, motto) stacked in one column on the
   right. align-items defaults to stretch, which both top-aligns the
   two grid items AND makes them share the row's full height in one
   property — exactly "top-aligned, mascot height matches the text
   column" with no extra rules needed. */
.why-us__inner {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 3rem;
}
/* mascot-cutout.png replaces assets/mascot.png here — that file has no
   alpha channel (flat RGB, a ~#FCFCFC backdrop baked into its
   JPEG-compressed pixels, confirmed directly against the file), which
   read as a visible light-gray box once the mascot was enlarged to
   200px+ (subtle enough to pass unnoticed at the old 108px). The cutout
   was produced by flood-filling the background from the image's own
   edges inward — not a flat color-threshold, which would have also
   erased the character's white dhoti/pants — so it's a real transparent
   PNG that sits on any background color with zero visible box.
   height:100% fills the grid cell (which stretches to the content
   column's height per the align-items note above); width:auto keeps
   its native aspect ratio; max-width is a ceiling only for unusually
   tall text columns so it can't stretch absurdly wide. */
.why-us__mascot {
  height: 100%;
  width: auto;
  max-width: 280px;
  display: block;
}
.why-us__content {
  display: flex;
  flex-direction: column;
  gap: 1.75rem;
}
/* Zeroed out because .why-us__content is a flex column with its own
   gap:1.75rem already providing the space to the lede below — keeping
   .section-heading's own margin-bottom here too would double it up. */
.why-us__content .section-heading { margin-bottom: 0; }

/* Left-aligned now — it used to be a standalone centered pull-quote
   next to a small mascot; inside the new stacked text column (eyebrow
   and lede are both left-aligned) centered text would read as a jarring
   mid-column alignment break, so it's brought in line with its new
   siblings. */
.motto {
  text-align: left;
  /* font-size added: .motto's own font-size was the inherited default
     (1rem/16px), so its max-width:68ch below was computing to a
     DIFFERENT pixel width (686px) than .why-us__lede's own 68ch (720px
     at ITS font-size, 1.05rem/16.8px) — ch is relative to the element's
     OWN font-size, so matching the ch NUMBER alone doesn't guarantee a
     matching pixel width when the two elements' font-sizes differ.
     Setting this to the same 1.05rem makes the two 68ch values resolve
     to the identical 720px, which is what "same max-width" actually
     needs to mean here. Doesn't affect .motto h3's own size — the
     sitewide h3{font-size:1.2rem} rule is a direct match on that
     element, which always wins over inheriting this. */
  font-size: 1.05rem;
  /* 60ch -> 68ch, matching .why-us__lede's max-width exactly (the wider
     of the two paragraphs) so .motto footer below wraps at the same
     column width as the lede above it, rather than the two reading as
     a mismatched pair. Doesn't affect .motto h3 — that's a short,
     nowrap single line regardless of this cap. */
  max-width: 68ch;
  border-left: none;
}
/* Tag changed from <p class="section-heading"> to a real <h3> — pulled
   out of the 7-heading .section-heading unification by explicit later
   instruction (it was rendering too large, H2-scale). No font-size/
   weight/line-height/font-family override needed here at all: the
   sitewide h3{font-size:1.2rem;font-weight:700} + h1,h2,h3,h4{
   font-family:var(--font-display);line-height:1.15} base rules already
   give exactly the "established H3 styling elsewhere" this was asked
   to match, and inheriting them directly (rather than restating the
   same values here) means this can't drift out of sync with that
   baseline later. Only color needs a scoped override (purple, kept per
   explicit instruction — the base h3 rule defaults to dark-green) plus
   the layout mechanics below (nowrap/text-align/margin), which have
   nothing to do with type scale. */
.motto h3 {
  color: var(--purple-accent);
  margin-bottom: 1rem;
  /* Single-line + left-align, same reasoning as before this was resized
     to H3: the sitewide p{text-align:justify} rule doesn't apply to an
     h3 at all (it only targets <p>), so left-align here is now just
     .motto's own inherited text-align:left taking effect normally —
     no override needed to fight anything. white-space:nowrap is kept
     per explicit instruction (single-line behavior stays).
     CORRECTION to an earlier comment here that claimed "no overflow at
     any tested width from 320px to 1920px" — that was wrong, caught by
     a later full-range audit: at 320-~350px viewport (inside the
     .why-us stacked mobile layout), this text's nowrap natural width
     forced .why-us__inner's single grid track — and with it, real
     document content, not just an off-screen artifact — up to 29px
     wider than the viewport (confirmed via body.scrollWidth, which
     dropped to exactly the viewport width the moment nowrap was
     removed). The earlier claim was apparently never actually
     re-verified at the narrow end after this element was resized to
     H3; see the <=350px override in responsive.css, which re-allows
     wrapping specifically in the narrow range where this is real,
     mapped by bisection: overflow at 320px (29px) and 340px (9px),
     zero from 360px up through 768px. */
  white-space: nowrap;
}
.motto footer {
  /* 0.98rem -> 1.05rem, matching .why-us__lede's font-size exactly —
     the two were on slightly different type-scale values (16.8px vs
     15.68px at default root size), which is what made them wrap at
     different points and read as a mismatched pair despite sharing a
     max-width-driven column. Color stays var(--text-muted), a
     deliberate dimmer tone for the attribution line, not in scope here. */
  font-size: 1.05rem;
  color: var(--text-muted);
  font-style: normal;
}

/* ==========================================================================
   CONTACT
   ========================================================================== */
/* --bg (not --white) so it reads as a distinct block between the white
   Why Choose Us section above and the dark footer below; border-top marks
   the seam against Why Choose Us since both are light backgrounds. */
.contact {
  background: var(--bg);
  border-top: 1px solid var(--border-soft);
  padding-block: var(--section-pad);
}
.contact-content {
  display: grid;
  grid-template-columns: 0.85fr 1.15fr;
  gap: 4rem;
  /* Left column is now just heading/lede/one address block — much
     shorter than the form. center (not start) keeps it from reading as
     a small block stranded at the top of a tall empty column; it
     balances against the form's own vertical middle instead. */
  align-items: center;
}

.contact-details__lede {
  margin-top: 0.6rem;
  max-width: 42ch;
  font-size: 1.02rem;
  color: var(--text-muted);
}

.contact-list {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  /* A bit more than before (was 2rem) — with only one item left, this
     is the column's sole supporting block under the heading/lede, so it
     reads better as a deliberately separated element than a tightly
     stacked list entry. */
  margin-top: 2.5rem;
}
.contact-list__item { display: flex; align-items: flex-start; gap: 1rem; }
.contact-list__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px; height: 44px;
  flex-shrink: 0;
  border-radius: var(--radius-sm);
  background: rgba(59, 143, 58, 0.1);
  color: var(--primary-green);
}
.contact-list__text { display: flex; flex-direction: column; gap: 0.4rem; padding-top: 0.3rem; }
.contact-list__label {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 0.8rem;
  color: var(--label-muted);
}
.contact-list__value { font-size: 0.95rem; color: var(--text-body); line-height: 1.55; }

.contact-form-wrap {
  background: var(--white);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-md);
  padding: 2.5rem;
  box-shadow: var(--shadow-card);
}

.contact-form {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.25rem;
}
/* [hidden] and .contact-form's own `display: grid` are equal-specificity
   author rules, so source order alone decides the tie — this rule must
   stay below the block above it to actually hide the form on submit. */
.contact-form[hidden] { display: none; }
.form-row { display: flex; flex-direction: column; gap: 0.4rem; }
.form-row--full { grid-column: 1 / -1; }
.form-row label {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 0.8rem;
  color: var(--purple-accent);
}
.form-row input,
.form-row select,
.form-row textarea {
  width: 100%;
  font: inherit;
  font-size: 0.92rem;
  line-height: 1.3;
  color: var(--text-body);
  background: var(--bg);
  border: 1.5px solid var(--input-border);
  border-radius: var(--radius-sm);
  padding: 0.75rem 0.95rem;
  transition: border-color 150ms ease, box-shadow 150ms ease;
}
.form-row textarea { resize: vertical; min-height: 110px; }
.form-row input:focus-visible,
.form-row select:focus-visible,
.form-row textarea:focus-visible {
  outline: none;
  border-color: var(--primary-green);
  box-shadow: 0 0 0 3px rgba(59, 143, 58, 0.15);
}
.form-row.is-invalid input,
.form-row.is-invalid select,
.form-row.is-invalid textarea {
  border-color: #C0392B;
}
.form-row__error {
  min-height: 1em;
  font-size: 0.8rem;
  color: #C0392B;
}

/* Scoped to this one instance via .contact-form__submit, not
   .btn--primary itself — the same base class is shared by the header
   nav CTA and hero CTA (both already purple, styled separately) and,
   critically, the footer's "Become a Partner", which uses .btn--outline
   entirely and must stay unaffected. White text unchanged: 9.58:1
   against var(--purple-accent) (#5c2b8e). */
.contact-form__submit {
  grid-column: 1 / -1;
  justify-self: start;
  margin-top: 0.2rem;
  padding: 0.75rem 1.6rem;
  background: var(--purple-accent);
  box-shadow: 0 10px 24px -8px rgba(106, 13, 163, 0.55);
}
.contact-form__submit:hover {
  background: var(--purple-accent-hover);
  box-shadow: 0 14px 28px -8px rgba(90, 11, 135, 0.55);
}
.contact-form__submit svg { flex-shrink: 0; }

.form-success {
  margin-top: 1.25rem;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--primary-green);
  background: rgba(59, 143, 58, 0.1);
  border-radius: var(--radius-sm);
  padding: 0.9rem 1.1rem;
}

/* ==========================================================================
   FOOTER
   ========================================================================== */
.site-footer {
  position: relative;
  background: var(--purple-accent);
  color: rgba(255,255,255,0.75);
  /* 4.5rem -> var(--section-pad), same shared token as every other
     section boundary in the sitewide spacing-reduction pass. */
  padding-top: var(--section-pad);
}
.footer__inner {
  display: grid;
  grid-template-columns: 1.4fr 0.8fr 0.8fr 1fr;
  gap: 2.5rem;
  padding-bottom: 3rem;
  border-bottom: 1px solid rgba(255,255,255,0.1);
}
.logo--footer { margin-bottom: 1rem; }
/* Reverted to full color per explicit instruction — this knowingly
   reintroduces the logo's purple wordmark (~1.24:1) and dark tagline
   (~1.28:1) being nearly illegible against the purple footer
   background. Not an oversight; no further contrast fix here unless
   requested again. */
.logo--footer .logo__badge img {
  height: 30px;
}
/* text-align:left — same narrow-column justify-gap issue as
   .service-card p above; this column is ~250-300px in the 4-column
   footer grid, confirmed by screenshot to produce visible word-gap
   rivers under the sitewide p{text-align:justify} default. */
.footer__brand p { color: rgba(255,255,255,0.65); font-size: 0.92rem; max-width: 32ch; text-align: left; }

.footer__secondary-logo {
  max-width: 140px;
  height: auto;
  margin-top: 1rem;
  display: block;
}

.social-icons { display: flex; gap: 0.75rem; margin-top: 1rem; }
.social-icons__link {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.9);
  transition: background-color 0.2s, transform 0.2s;
}
.social-icons__link svg * { transition: fill 0.2s, stroke 0.2s; }
.social-icons__link:hover { transform: scale(1.08); }

.social-icons__link--youtube:hover { background: #FF0000; }
.social-icons__link--instagram:hover { background: #E1306C; }
.social-icons__link--facebook:hover { background: #1877F2; }
.social-icons__link--x:hover { background: #000000; }
.social-icons__link--linkedin:hover { background: #0A66C2; }

/* Each icon's path/rect/circle sets its own brand-color fill or stroke
   as a presentation attribute (see index.html), which always wins over
   an *inherited* CSS value — so a rule on the parent <svg> alone
   (fill/stroke set there) never reaches these children. Targeting
   [fill]/[stroke] directly overrides each element's own attribute value
   instead of trying to inherit past it, and only touches the property
   the element actually uses — elements with no fill attribute (stroke-
   only outlines like the YouTube ring or Instagram's rect/circle) stay
   uncolored-fill, so they don't turn into solid white blobs. */
.social-icons__link:hover svg [fill] { fill: #FFFFFF; }
.social-icons__link:hover svg [stroke] { stroke: #FFFFFF; }

.site-footer h3 {
  color: var(--white);
  font-size: 0.95rem;
  margin-bottom: 1.1rem;
}
.footer__nav ul, .footer__services ul { display: flex; flex-direction: column; gap: 0.7rem; }
.footer__nav a {
  font-size: 0.92rem;
  color: rgba(255,255,255,0.65);
  transition: color var(--dur-fast) var(--ease-out);
}
/* Green as a small underline accent, not as the hover text color itself
   — green-on-purple only measures ~3.67:1, which fails the 4.5:1 needed
   for this text's size (0.92rem), so the text brightens to solid white
   on hover (9.55:1, better than the resting state) while green shows up
   only as a thin decorative underline. */
.footer__nav a:hover {
  color: var(--white);
  text-decoration: underline;
  text-decoration-color: #3fb80d;
  text-underline-offset: 3px;
}
.footer__services li { font-size: 0.92rem; color: rgba(255,255,255,0.65); }

/* text-align:left — same narrow-column justify-gap issue as
   .footer__brand p above. */
.footer__cta p { color: rgba(255,255,255,0.65); font-size: 0.9rem; margin-bottom: 1.3rem; text-align: left; }

.footer__bottom {
  padding-block: 1.5rem;
  font-size: 0.85rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 1rem;
}
/* Targets the actual <p> directly, not just this wrapper — the global
   `p { color: var(--text-body); }` rule (style.css:93) directly matches
   the <p> inside .footer__bottom, and a direct match always beats an
   inherited value regardless of the ancestor's specificity. Setting
   color here on .footer__bottom alone was inherited-only and silently
   lost to that global rule — this is why the previous fix never took
   visible effect. */
.footer__bottom p {
  color: var(--white);
}

/* ==========================================================================
   BACK TO TOP
   ========================================================================== */
.back-to-top {
  position: fixed;
  right: 1.5rem;
  bottom: 1.5rem;
  width: 46px; height: 46px;
  border-radius: 50%;
  background: var(--primary-green);
  color: var(--white);
  display: flex; align-items: center; justify-content: center;
  box-shadow: var(--shadow-card);
  opacity: 0;
  visibility: hidden;
  transform: translateY(10px);
  transition: opacity var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out);
  z-index: 90;
}
.back-to-top.is-visible { opacity: 1; visibility: visible; transform: translateY(0); }
.back-to-top:hover { background: var(--dark-green); }

/* ==========================================================================
   SCROLL-REVEAL ANIMATIONS (vanilla JS toggles .is-visible via IntersectionObserver)
   ========================================================================== */
.reveal {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity var(--dur-slow) var(--ease-out), transform var(--dur-slow) var(--ease-out);
  will-change: opacity, transform;
}
.reveal[data-reveal="left"] { transform: translateX(-32px); }
.reveal[data-reveal="right"] { transform: translateX(32px); }
.reveal.is-visible {
  opacity: 1;
  transform: translate(0, 0);
}

@media (prefers-reduced-motion: reduce) {
  .reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }
}
