/*
Theme Name: Pure Valley Farms
Theme URI: https://www.purevalleyfarms.ca
Author: Pure Valley Farms
Description: Custom block theme for Pure Valley Farms — a holistic family farm near Rosthern, Saskatchewan. Warm rustic-modern: forest green, charcoal, cream, burnt orange. Built as a block theme (theme.json + block templates) so the design lives in editable files rather than page-builder meta.
Version: 0.5.5
Requires at least: 6.9
Tested up to: 6.9
Requires PHP: 7.4
License: GPL-2.0-or-later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: purevalley
Tags: block-theme, e-commerce, full-site-editing
*/

/* ============================================================
   Design tokens live in theme.json. This file is only for the
   handful of things theme.json cannot express.
   ============================================================ */

/* --- Paper texture on the cream body (owner request 2026-07-29) ---
   Built from the farm's real Squarespace background,
   `Site assets/Logo & site pics/WEBSITE TEXTURED BACKGROUND.jpg`.

   ⚠️ DO NOT turn this back into a small repeating tile. That was the first
   attempt (512px square, multiply-blended) and the owner correctly called it
   blotchy: on Squarespace the image was ONE large instance stretched across
   the page, so a repeating square reads as a pattern no matter how fine the
   grain. The fix is a full-width image that only ever repeats DOWN the page,
   at a seam that cannot be seen.

   The shipped asset: vignette flattened 90% (the original darkens from ~233 in
   the centre to ~190 at the corners, which would band when repeated), grain
   scaled ×0.60, tinted so its mean is exactly the cream token
   (245.5/242.5/235.5 ≈ #F6F3EC), then MIRRORED top-to-bottom so `repeat-y`
   joins image-bottom to its own reflection — measured seam difference 0.0.
   1600×4802 WebP q82, 51KB. Recipe in HANDOFF.md.

   `background-size: 100% auto` + `repeat-y` deliberately avoids
   `background-attachment: fixed`, which is what you'd normally reach for to
   stop a background repeating — iOS Safari mishandles it, and `cover` on a
   long document scales the grain into huge soft blobs. Full width + a seamless
   vertical repeat needs no `fixed` and behaves identically on every device.

   Applied to `body` on purpose: the cream sections that need it (featured
   products, the story block, all content pages, shop/product pages) simply
   inherit it, while the hero band, trust strip and footer set their own
   background-color and stay clean. One rule, no per-section plumbing. The image
   is already cream-toned, so no blend mode — but body's background-color stays
   as the fallback if the image ever fails to load. */
body {
  background-image: url('assets/img/paper-bg.webp');
  background-repeat: repeat-y;
  background-position: center top;
  background-size: 100% auto;
}

/* --- Hero copy entrance (owner request 2026-07-29: make the hook line pop) ---
   Pure CSS, runs once on load — the hero is above the fold so it needs no
   scroll trigger. `both` fill is important: it holds the from-state before the
   delay AND the to-state after, so text can never be left invisible. The h1
   gets a slight overshoot easing (the "pop"); everything else just rises, on a
   short stagger so the eye lands on the headline first. */
@keyframes pvf-pop {
  from { opacity: 0; transform: translateY(18px) scale(.965); }
  to   { opacity: 1; transform: none; }
}
@keyframes pvf-rise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}
.pvf-hero__copy h1 {
  animation: pvf-pop .72s cubic-bezier(.22, 1.18, .36, 1) both;
}
.pvf-hero__copy .wp-block-column p {
  animation: pvf-rise .6s cubic-bezier(.2, .8, .2, 1) .14s both;
}
.pvf-hero__copy .wp-block-buttons {
  animation: pvf-rise .6s cubic-bezier(.2, .8, .2, 1) .26s both;
}
.pvf-hero__copy > p {
  animation: pvf-rise .6s cubic-bezier(.2, .8, .2, 1) .38s both;
}
@media (prefers-reduced-motion: reduce) {
  /* Show everything immediately — no transform, no fade. */
  .pvf-hero__copy h1,
  .pvf-hero__copy .wp-block-column p,
  .pvf-hero__copy .wp-block-buttons,
  .pvf-hero__copy > p {
    animation: none;
  }
}

/* --- Sticky header: no divider line at rest, soft shadow once scrolled.
       (Owner decision 2026-07-20: the hard border under the logo was removed
       so the hero banner butts directly against the menu.) --- */
.pvf-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--wp--preset--color--white);
  transition: box-shadow 0.2s ease;
}
.pvf-header.is-scrolled {
  box-shadow: 0 2px 14px rgba(38, 36, 33, 0.13);
}
@media (prefers-reduced-motion: reduce) {
  .pvf-header { transition: none; }
}

/* --- Brand mark in the header (added 2026-07-30, owner request) ----------
   Subpages had NO logo and no route home but the browser back button — the
   hero logo exists only in front-page.html. This also fixes a compositional
   problem: the nav was centred, which left the entire top-left corner empty
   and made the missing mark conspicuous. */
.pvf-navrow {
  max-width: var(--wp--style--global--content-size);
  margin-inline: auto;
  gap: 22px;
}

/* WooCommerce injects the customer-account and mini-cart blocks as DIRECT
   children of this row (they are not in header.html — Woo adds them to the
   header template part itself). That left FOUR flex children under
   `space-between`, which spread the two icons ~157px apart with a gap in the
   middle — measured 2026-07-31: account ended at x=1084, cart began at x=1241.
   Giving the nav `margin-inline:auto` makes IT absorb all the free space
   instead: auto margins are resolved before justify-content, so the two icons
   collapse together at the right and the menu still sits optically centred.
   Do NOT "simplify" this to justify-content:flex-end — that would drag the
   menu right along with the icons. */
.pvf-navrow > nav.wp-block-navigation {
  margin-inline: auto !important;
}
/* Woo ships these icons at 19px, which reads as an afterthought next to the
   menu (owner, 2026-07-31). */
.pvf-navrow .wc-block-customer-account__link svg,
.pvf-navrow .wc-block-mini-cart__button svg {
  width: 26px !important;
  height: 26px !important;
}
.pvf-navrow .wc-block-mini-cart__button { padding: 0 !important; }
/* Child combinator, NOT descendant — same trap as .pvf-hero__banner. */
.pvf-brand { flex: 0 0 auto; display: block; line-height: 0; }
.pvf-brand > img {
  /* 52px was tried first: the logo's fine arch lettering ("NATURALLY
     BETTER") turned to mush. 64px is the smallest size it stays legible. */
  height: 64px;
  width: auto;
  display: block;
}

/* On the HOMEPAGE the hero carries a large logo immediately below this one,
   so showing both ~200px apart reads as redundant. Fade rather than hide:
   opacity keeps the flex space reserved so the nav never shifts. Reuses the
   existing .is-scrolled hook from assets/js/header.js. */
.home .pvf-brand { opacity: 0; transition: opacity 0.25s ease; }
.home .pvf-header.is-scrolled .pvf-brand { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .home .pvf-brand { transition: none; }
}

/* --- Nav: tracked-out slab caps -----------------------------------------
   Was EB Garamond 1.12rem/400 — which, because the font never actually
   loaded (see the font note in theme.json), rendered as whatever serif the
   visitor happened to own. Caps + 0.13em tracking in the slab is the
   feed-store / ranch-signage idiom, and echoes the tracked caps already used
   for the footer column heads. Family/size/weight/tracking live in
   theme.json (core/navigation); only the interaction state lives here,
   because theme.json cannot express :hover or ::after. */
.pvf-header .wp-block-navigation-item__content {
  position: relative;
  padding-bottom: 4px;
}
.pvf-header .wp-block-navigation-item__content::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: var(--wp--preset--color--green);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.18s ease;
}
.pvf-header .wp-block-navigation-item__content:hover::after,
.pvf-header .current-menu-item > .wp-block-navigation-item__content::after,
.pvf-header .wp-block-navigation-item__content[aria-current="page"]::after {
  transform: scaleX(1);
}
@media (prefers-reduced-motion: reduce) {
  .pvf-header .wp-block-navigation-item__content::after { transition: none; }
}

/* Tablet band. WP's overlayMenu:"mobile" only collapses the nav to a
   hamburger below 600px, so between roughly 600px and 900px all five items
   render inline — and caps + 0.13em tracking made them wide enough to wrap
   onto a second line once the logo took its share of the row (reproduced at
   640px on 2026-07-30: the menu broke into "SHOP / OUR STORY" above
   "DELIVERY & PICKUP / FAQ / CONTACT"). Tighten type and logo through that
   band so it stays on one line. Measured need: brand + items + icons ≈ 640px
   at full size, against a row of only viewport-48px. */
@media (max-width: 900px) and (min-width: 601px) {
  .pvf-header .wp-block-navigation {
    font-size: 0.82rem !important;
    letter-spacing: 0.06em !important;
  }
  .pvf-navrow { gap: 12px; }
  .pvf-brand > img { height: 52px; }
  .pvf-navrow .wc-block-customer-account__link svg,
  .pvf-navrow .wc-block-mini-cart__button svg {
    width: 23px !important;
    height: 23px !important;
  }
}

@media (max-width: 781px) {
  .pvf-brand > img { height: 48px; }
  /* Keep the mark visible on mobile even on the homepage: the nav collapses
     to a hamburger here, and a header containing nothing but a hamburger
     reads as broken. At 48px against the hero logo's 46vw the two no longer
     look like the same element repeated. */
  .home .pvf-brand { opacity: 1; }
}

/* --- Section title: centred green rule + breathing room ------------------
   The heading sat directly on top of the product images (owner, 2026-07-31).
   The rule is a pseudo-element, NOT text-decoration:underline — a real
   underline on a heading reads as a broken link, and it would hug the
   descenders of "p"/"g". Uses the same green as the nav hover rule so the two
   read as one system. */
.pvf-section-title {
  margin-bottom: 2.75rem !important;
  padding-bottom: 0.85rem;
  position: relative;
}
.pvf-section-title::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: 0;
  transform: translateX(-50%);
  width: 72px;
  height: 3px;
  border-radius: 2px;
  background: var(--wp--preset--color--green);
}

/* --- "Shop All Beef": the row-level CTA ----------------------------------
   It was green on green, the same size as the per-product buttons, and only a
   block-gap below them — so it read as a fifth product button rather than the
   way out to the full catalogue. Burnt orange is already in the palette and
   was other­wise unused; it gives an unambiguous hierarchy (green = act on one
   product, orange = see everything) without introducing a new colour. */
.pvf-shop-all {
  margin-top: 3.25rem !important;
}
.pvf-shop-all .wp-block-button__link {
  font-size: 1.02rem !important;
  padding: 17px 42px !important;
  border-color: var(--wp--preset--color--orange) !important;
}
.pvf-shop-all .wp-block-button__link:hover {
  background-color: #A83F14 !important;
  border-color: #A83F14 !important;
}

/* --- Product loop: floats -> CSS grid ------------------------------------
   WooCommerce still ships a float-based loop (`ul.products` is display:block
   with `li.product` floated left/right). Floats do not equalise row heights,
   so any product whose title wraps to a second line pushes its OWN price and
   button down and breaks alignment across the row. Measured on the homepage
   featured row 2026-07-30: "Ground Beef – Hamburger" wrapped to two lines and
   ran 336px tall against 220/236/241px for its neighbours, throwing its price
   and CTA out of line on the most important row on the site.

   Grid equalises the rows; `margin-top:auto` pins every CTA to a common
   baseline no matter how long the title runs; the square aspect-ratio stops
   mixed source crops (the ground-beef shot is a different shape from the
   rest) from making the row look ragged. */
ul.products {
  display: grid !important;
  gap: 32px 28px;
  margin: 0 0 var(--wp--preset--spacing--50) !important;
  padding: 0 !important;
  list-style: none !important;
}
/* Kill WooCommerce's float clearfix — it leaves phantom grid tracks. */
ul.products::before,
ul.products::after { content: none !important; }

ul.products.columns-4 { grid-template-columns: repeat(4, 1fr); }
ul.products.columns-3 { grid-template-columns: repeat(3, 1fr); }
ul.products.columns-2 { grid-template-columns: repeat(2, 1fr); }

ul.products > li.product {
  display: flex !important;
  flex-direction: column;
  position: relative; /* keeps the Sale! badge anchored */
  float: none !important;
  clear: none !important;
  width: auto !important;
  margin: 0 !important;
}
ul.products > li.product img {
  width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  display: block;
}
/* Pin the CTA to the bottom of every card.
   ⚠️ The margin-top:auto MUST sit on the direct flex child. WooCommerce wraps
   the add-to-cart link in a bare <p>, so `li.product .button` (descendant)
   targets a node that is NOT a flex item and the auto margin silently does
   nothing — measured 2026-07-30: cards equalised to 398px but the buttons
   still sat at 941/1009/941/959. Both selectors are listed because the
   wrapper is version-dependent; some Woo templates emit the link bare. */
ul.products > li.product > p:last-child,
ul.products > li.product > .button:last-child {
  margin-top: auto !important;
  margin-bottom: 0 !important;
}

@media (max-width: 900px) {
  ul.products.columns-4,
  ul.products.columns-3 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 520px) {
  ul.products.columns-4,
  ul.products.columns-3,
  ul.products.columns-2 { grid-template-columns: 1fr; }
}

/* --- Torn-paper hero banner ---
   CRITICAL: never vertically crop or background-cover this image — the torn
   edges are baked into the pixels and cropping destroys the effect. It must
   render at its natural ~3.26:1 ratio as an <img> on a WHITE band (#FDFDFD);
   on cream you would see a rectangular seam where the tear fades out. */
.pvf-hero { background: var(--wp--custom--hero--band-color); }
.pvf-hero__banner { position: relative; width: 100%; max-width: 1800px; margin-inline: auto; }
/* Child combinator, NOT descendant: the logo <img> lives inside the banner
   div, and a bare `.pvf-hero__banner img` also catches it — on mobile that
   forced the logo to 250px tall + object-fit:cover, i.e. a zoomed center
   crop (v0.3.0 bug, found on staging 2026-07-28). */
.pvf-hero__banner > img { width: 100%; height: auto; display: block; }

/* Logo overlaid on the sky, seated below the tear (tear bottoms out ~5%). */
.pvf-hero__logo {
  position: absolute;
  z-index: 3;
  left: 50%;
  transform: translateX(-50%);
  top: var(--wp--custom--hero--logo-top-offset);
  width: clamp(200px, 22vw, 312px);
}
/* Subtle white glow only — measured 1.38:1 contrast for the green arch against
   the raw sky, which is invisible. This lifts it without a visible halo.
   Do NOT replace with a large radial-gradient box; that was tried and read as
   a pasted-on white patch. */
.pvf-hero__logo img {
  width: 100%;
  height: auto;
  display: block;
  filter: drop-shadow(0 1px 5px rgba(255, 255, 255, 0.9))
          drop-shadow(0 0 16px rgba(255, 255, 255, 0.65));
}

/* --- Kill the root block-gap between the header and main ---
   WP's .wp-site-blocks emits margin-block-start: var(--wp--style--block-gap)
   (24px) on every root block, which let the cream body show through as an
   off-white strip between the white menu row and the hero tear (owner-reported
   on mobile, 2026-07-29, present at all widths). Sections carry their own
   padding, so zeroing this is safe site-wide. */
.wp-site-blocks > main { margin-block-start: 0; }

/* --- Barbed-wire section dividers ---
   The gradient puts the colour boundary exactly through the wire's centre so
   the wire "sits on the fence line" rather than above or below it. One
   modifier per colour transition. The SVG inside uses a fixed-scale pattern
   (120px repeat) — do NOT add a viewBox or preserveAspectRatio, or the barbs
   compress on narrow screens. Each SVG instance needs a unique pattern id. */
.pvf-wire-divider { line-height: 0; }
.pvf-wire-divider svg { display: block; width: 100%; height: 30px; }
.pvf-wire-divider--white-to-cream {
  background: linear-gradient(to bottom,
    var(--wp--custom--hero--band-color) 50%,
    var(--wp--preset--color--cream) 50%);
}
.pvf-wire-divider--to-deep {
  background: linear-gradient(to bottom,
    var(--wp--preset--color--cream) 50%,
    var(--wp--preset--color--cream-deep) 50%);
}
.pvf-wire-divider--from-deep {
  background: linear-gradient(to bottom,
    var(--wp--preset--color--cream-deep) 50%,
    var(--wp--preset--color--cream) 50%);
  /* Must touch the strip above it — no cream sliver between them. */
  margin-block-start: 0 !important;
}
/* Whatever follows a to-deep wire (the cream-deep strip) must butt against it. */
.pvf-wire-divider--to-deep + * { margin-block-start: 0 !important; }
/* (No wire above the footer — owner decision 2026-07-29: straight edge there.) */

/* --- Trust strip ("Why Naturally Better") v2 — owner-directed 2026-07-29 ---
   Kraft-paper texture band, text in the LEFT THIRD, ranch photo (media 172,
   trust-strip-ranch.webp) filling the RIGHT TWO-THIRDS behind an angled white
   divider that rises lower-left → upper-right. The wire dividers above/below
   use --to-deep/--from-deep whose gradients END ON the kraft tone below, so
   if you change the tone change it in theme.json (custom.trustStrip.bg) AND
   in those two gradients' expectations — they reference the same var. */
.pvf-trust-strip { position: relative; overflow: hidden; }
/* WP emits preset background classes with !important, so this needs it too. */
.pvf-trust-strip.has-cream-deep-background-color {
  background-color: var(--wp--custom--trust-strip--bg) !important;
  background-image:
    linear-gradient(to bottom, rgba(109,103,92,.12), rgba(109,103,92,0) 14%, rgba(109,103,92,0) 86%, rgba(109,103,92,.12)),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/><feColorMatrix type='matrix' values='0 0 0 0 0.35 0 0 0 0 0.29 0 0 0 0 0.20 0 0 0 0.07 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
}
/* Copy sits left, photo right, both keyed to the PAGE CONTENT COLUMN rather
   than to viewport percentages — that's what keeps the diagonal off the text
   at every width (a plain `width:66%` overlapped the last bullet at 1440px and
   got worse on ultrawide; measured 2026-07-29).

   Two `!important` blocks are load-bearing, not laziness — WP's constrained
   layout rule `.wp-block-group.is-layout-constrained > :where(...)` is 0-2-0
   specificity and beats a plain `.pvf-trust-strip > h2` (0-1-1):
     · it sets margin-inline:auto, which re-centred the copy onto the photo
     · it sets max-width:contentSize, which capped the photo at 1140px so it
       stopped short of the right edge instead of bleeding off it
   Verified worst-case text→diagonal gap (px) at: 1120→44 · 1280→66 · 1440→46
   · 1920→70 · 2560→74; stacked and clear at 1024 and 375. */
.pvf-trust-strip > h2,
.pvf-trust-strip > .pvf-trust-list {
  text-align: left;
  position: relative; /* sit above the photo layer */
  z-index: 2;
}

@media (min-width: 1120px) {
  .pvf-trust-strip > h2,
  .pvf-trust-strip > .pvf-trust-list {
    max-width: 320px;
    /* Left edge lines up with the hero h1 and the section headings (x=153 at
       1440px). Uses the content-size var so it can't drift from theme.json. */
    margin-left: max(0px, calc((100% - var(--wp--style--global--content-size)) / 2)) !important;
    margin-right: auto !important;
  }
  .pvf-trust-media {
    position: absolute;
    top: 0; right: 0; bottom: 0;
    /* Occupy from one third into the content column out to the right viewport
       edge. The min()/max() pair mirrors how WP computes that column, so this
       holds whether the viewport is narrower or wider than contentSize.

       ⚠️ Size this with an explicit `width`, NOT with `left` + `width:auto`.
       Both compute the identical box, but the left/auto form left the clipped
       photo unpainted — the container's white background showed instead
       (reproduced on staging 2026-07-29 at 1440px: styles, decoded pixels and
       hit-testing all looked correct, yet nothing rendered; swapping to an
       explicit width fixed it immediately). Almost certainly an engine bug
       compositing a clip-path on an absolutely-positioned, auto-width box. */
    width: calc(
      100%
      - max(24px, (100% - var(--wp--style--global--content-size)) / 2)
      - min(var(--wp--style--global--content-size), 100% - 48px) / 3
    );
    max-width: none !important; /* beat the constrained-layout cap */
    margin: 0 !important;
    /* The white sliver between this container's clip and the img's tighter clip
       IS the angled divider line — don't "clean up" the double clip-path. */
    background: var(--wp--custom--hero--band-color);
    clip-path: polygon(0% 100%, 100% 100%, 100% 0%, 18% 0%);
    /* ⚠️ REGRESSION GUARD (v0.5.2, found 2026-07-30). The explicit-width fix
       above was NOT sufficient on its own — the photo was painting as solid
       white again on v0.5.1 at 1440px, reproduced on a clean load with no DOM
       manipulation. Geometry was flawless every time (box 907×449, img decoded
       at 2528×1696, opacity 1, both clip-paths applied), which is exactly the
       signature of a compositing failure rather than a layout error.
       Promoting the element to its own layer forces the clip to composite and
       fixes it. Verified live before shipping. Keep BOTH this and the explicit
       width — they guard the same bug by different means, and the width form
       alone already regressed once. */
    transform: translateZ(0);
    will-change: transform;
  }
  .pvf-trust-media img {
    width: 100%; height: 100%;
    object-fit: cover;
    object-position: 62% center;
    display: block;
    clip-path: polygon(1.3% 100%, 100% 100%, 100% 0%, 19% 0%);
  }
}

/* Below the split's comfortable minimum: stack it. Text full width, photo
   becomes a band underneath with a gentler angle. Breakpoint is 1120px (=
   contentSize) because the 1/3–2/3 split needs the whole content column to
   exist — at 1024px the third was narrower than the copy and they collided. */
@media (max-width: 1119px) {
  .pvf-trust-strip > h2,
  .pvf-trust-strip > .pvf-trust-list {
    max-width: none;
    margin-left: 0 !important;
  }
  .pvf-trust-media {
    position: static;
    width: 100%;
    max-width: none !important;
    height: 190px;
    margin: 18px 0 0 !important;
    background: var(--wp--custom--hero--band-color);
    clip-path: polygon(0% 12%, 100% 0%, 100% 100%, 0% 100%);
  }
  .pvf-trust-media img {
    width: 100%; height: 100%;
    object-fit: cover;
    object-position: 62% 70%;
    display: block;
    clip-path: polygon(0% 15%, 100% 3%, 100% 100%, 0% 100%);
  }
}

/* --- Footer v2 --- */
.wp-site-blocks > footer { margin-block-start: 0; }
.pvf-footer2 { background: var(--wp--preset--color--charcoal); color: var(--wp--preset--color--cream-deep); }
.pvf-footer2 a { color: var(--wp--preset--color--cream-deep); text-decoration: none; }
.pvf-footer2 a:hover { color: #fff; text-decoration: underline; }
.pvf-footer2__grid {
  max-width: 1140px; margin: 0 auto; padding: 56px 24px 40px;
  display: grid; grid-template-columns: 1.6fr 1fr 1fr 1.3fr; gap: 40px;
}
.pvf-footer2__wordmark { font-family: var(--wp--preset--font-family--display); font-size: 1.35rem; color: #fff; letter-spacing: .02em; }
.pvf-footer2__arch { color: #7CB342; font-size: .72rem; letter-spacing: .28em; font-weight: 700; margin-top: 2px; }
.pvf-footer2__tag { font-size: .86rem; color: #B9B2A4; margin-top: 14px; line-height: 1.55; max-width: 34ch; }
.pvf-footer2__social { display: flex; gap: 12px; margin-top: 18px; }
.pvf-footer2__social a {
  display: flex; width: 38px; height: 38px; border-radius: 50%;
  background: rgba(237,232,220,.1); align-items: center; justify-content: center;
  transition: background .15s;
}
.pvf-footer2__social a:hover { background: var(--wp--preset--color--green-deep); }
.pvf-footer2__social svg { width: 17px; height: 17px; fill: var(--wp--preset--color--cream-deep); }
.pvf-footer2 h4 { font-size: .72rem; letter-spacing: .22em; color: #8f8778; margin: 0 0 14px; font-weight: 700; }
.pvf-footer2 ul { list-style: none; margin: 0; padding: 0; }
.pvf-footer2 li { margin: 0 0 9px; font-size: .9rem; }
.pvf-footer2__contact li { color: #CFC8B8; }
.pvf-footer2__badge {
  display: inline-block; margin-top: 10px; padding: 5px 10px;
  border: 1px solid rgba(237,232,220,.25); border-radius: 4px;
  font-size: .78rem; color: var(--wp--preset--color--cream-deep);
}
.pvf-footer2__bar { border-top: 1px solid rgba(237,232,220,.14); }
.pvf-footer2__barin {
  max-width: 1140px; margin: 0 auto; padding: 16px 24px;
  display: flex; flex-wrap: wrap; gap: 8px; justify-content: space-between;
  font-size: .78rem; color: #8f8778;
}
.pvf-footer2__barin a { color: #8f8778; }
@media (max-width: 860px) {
  .pvf-footer2__grid { grid-template-columns: 1fr 1fr; padding: 40px 20px 28px; gap: 28px; }
  /* Brand column spans the full row — in a half-width column the wordmark
     wrapped onto three lines (measured at 375px, 2026-07-29). */
  .pvf-footer2__grid > div:first-child { grid-column: 1 / -1; }
  .pvf-footer2__wordmark { font-size: 1.2rem; }
}

@media (max-width: 760px) {
  /* At 390px wide the untouched 3.26:1 banner renders only ~120px tall — a
     useless sliver. Crop LEFT/RIGHT instead: the torn edges run along the
     top and bottom, so a horizontal crop preserves them. */
  .pvf-hero__banner > img {
    height: var(--wp--custom--hero--mobile-banner-height);
    object-fit: cover;
    object-position: 45% center;
  }
  /* `cover` here crops left/right only, so the FULL image height is still
     visible — the tear therefore sits at the same 3–11% band as on desktop and
     needs the same clearance. Was 11%, which put the logo's arch right on the
     deepest part of the tear. */
  .pvf-hero__logo { width: clamp(158px, 46vw, 208px); top: 16%; }
}

/* --- Fulfillment badges (the structural answer to the local-vs-shipped split) --- */
.pvf-badge {
  display: inline-block;
  width: max-content;
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: 9px;
}
.pvf-badge--local {
  background: var(--wp--preset--color--badge-local);
  color: var(--wp--custom--badge--local-text);
  border: 1px solid var(--wp--custom--badge--local-border);
}
.pvf-badge--ship {
  background: var(--wp--preset--color--badge-ship);
  color: var(--wp--custom--badge--ship-text);
  border: 1px solid var(--wp--custom--badge--ship-border);
}

/* --- Category tiles: real product photo + bottom scrim + slab label --- */
.pvf-tile {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: flex-start;
  gap: 7px;
  aspect-ratio: 4 / 3;
  padding: 16px;
  border-radius: var(--wp--custom--tile--radius);
  overflow: hidden;
  text-decoration: none;
  background-color: var(--wp--preset--color--charcoal);
  background-size: cover;
  background-position: center;
  transition: transform 0.15s ease;
}
.pvf-tile::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--wp--custom--tile--scrim);
}
.pvf-tile:hover { transform: translateY(-3px); }
@media (prefers-reduced-motion: reduce) {
  .pvf-tile, .pvf-tile:hover { transition: none; transform: none; }
}
.pvf-tile__label {
  position: relative;
  font-family: var(--wp--preset--font-family--display);
  color: #fff;
  font-size: clamp(0.95rem, 1.2vw, 1.12rem);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  line-height: 1.25;
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.55);
}
.pvf-tile__rule {
  position: relative;
  width: 34px;
  height: 3px;
  border-radius: 2px;
  background: var(--wp--preset--color--orange);
}
.pvf-tile__badge {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 2;
  background: var(--wp--preset--color--orange);
  color: #fff;
  font-size: 0.58rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  padding: 3px 7px;
  border-radius: 9px;
}

/* --- Accessibility: keep a visible focus ring everywhere --- */
a:focus-visible,
button:focus-visible,
input:focus-visible,
.wp-block-button__link:focus-visible {
  outline: 2px solid var(--wp--preset--color--green);
  outline-offset: 2px;
}

/* --- Wide content must scroll in its own container, never the page body --- */
.pvf-scroll-x { overflow-x: auto; }
