/*
Theme Name:   Larkhaven Vineyards
Theme URI:    https://forwineries.com/templates/larkhaven/
Description:  A quiet, editorial WordPress theme for Napa Valley wineries, inspired by the volcanic hillside estates of the Coombsville AVA. Includes native Commerce7 integration (shop, wine club, and cart) and works with the free version of Elementor, so every new page automatically inherits the site's header, footer, and typography. Part of the For Wineries collection at forwineries.com.
Author:       ForWineries.com
Author URI:   https://forwineries.com
Version:      1.0.4
License:      GNU General Public License v2 or later
License URI:  https://www.gnu.org/licenses/gpl-2.0.html
Text Domain:  larkhaven
Tags:         wine, winery, commerce7, e-commerce, elementor-compatible, editorial, custom-colors, custom-menu, featured-images, translation-ready
*/

/* =========================================================
   1. DESIGN TOKENS
   The canonical --fw-* tokens (clay, cream, charcoal, radius, space-*,
   etc.) are NOT declared here — they come from functions.php's
   lh_fw_config_array()['tokens'] and are emitted as one :root block by
   ForWineries\Core\DesignTokens (core/src/DesignTokens.php), enqueued
   ahead of this stylesheet. Declaring them again here would just be a
   second, driftable source of truth for the exact values already in
   functions.php. This block is ONLY for genuinely one-off tokens beyond
   the canonical 26 — see forwineries-theme-core/docs/DESIGN-TOKEN-SCHEMA.md.
========================================================= */
:root {
  --fw-gold-light: #d9c199; /* lighter accent shade used for a handful of hover/highlight states — Larkhaven-specific, not part of the shared token vocabulary */
}

/* =========================================================
   2. RESET / BASE
========================================================= */
*, *::before, *::after { box-sizing: border-box; }

/* Skip-to-content link (WCAG 2.4.1 "Bypass Blocks") — off-screen until
   keyboard-focused, then jumps straight above the header. Landing target
   is <main id="lh-main">, opened in header.php right after </header> and
   closed in footer.php right before <footer>, so it wraps every
   template's content automatically with zero per-template changes. */
.lh-skip-link {
  position: absolute;
  top: -100px;
  left: 0;
  z-index: 9999;
  background: var(--fw-charcoal);
  color: var(--fw-cream);
  padding: 12px 20px;
  font-family: var(--fw-font-body);
  font-size: 0.9rem;
  text-decoration: none;
  transition: top 0.15s ease;
}
.lh-skip-link:focus { top: 0; }

/* Baseline visible focus ring for every keyboard-focusable element that
   doesn't already define its own focus treatment — WCAG 2.4.7 "Focus
   Visible". Nothing in this file sets outline:none, so this is additive,
   not a fight against a suppressed default. */
:focus-visible {
  outline: 2px solid var(--fw-clay);
  outline-offset: 2px;
}
/* The merlot outline above has ~1.2:1 contrast against merlot-dark —
   invisible on our own dark-background sections (footer, hero, club
   cards). WCAG 1.4.11 wants focus indicators at 3:1 against their
   background; gold-light clears that everywhere it's needed here. */
#lh-footer :focus-visible,
.fw-hero :focus-visible,
.fw-club-card :focus-visible {
  outline-color: var(--fw-gold-light);
}

/* Root cause of every "pink button" bug chased throughout this project —
   it was never Commerce7, a branding plugin, or anything else in this
   file: the Hello Elementor PARENT theme's own reset.css gives every
   plain, unstyled <button>/[type="button"]/[type="submit"] a hardcoded
   pink (#c36) outline by default and a solid pink fill on hover/focus.
   Any element without more specific CSS of its own — e.g. Commerce7's
   icon-only cart-close button, which carries no class at all — falls
   straight into this default. Confirmed via live DevTools: the winning
   rule was listed as reset.css:1.
   Overridden here with the exact same selector list, using the site's
   neutral charcoal instead of pink, WITH !important — checked the actual
   live <link> order and this child theme's stylesheet loads BEFORE
   Hello Elementor's reset.css on this site (hello-elementor enqueues its
   own reset.css late), so an equal-specificity rule here without
   !important still loses the cascade tie to the parent's later rule.
   !important is the correct tool for exactly this one case: overriding a
   parent theme's core stylesheet whose load order we don't control.
   Any button with its own class (.fw-btn, .c7-btn, .c7-link, etc) already
   has higher specificity and is completely unaffected regardless — this
   only changes genuinely unstyled buttons. */
/* Bare-button fallback restores a real bordered/outline look — a plain
   button with no box at all reads as broken, not "clean". A bordered
   outline that fills solid on hover is the right treatment for a TEXT
   button (e.g. one with no other class anywhere on the site). Anything
   that already has its own class (.fw-btn, .c7-btn, .c7-btn--primary,
   .c7-link, etc) has higher specificity and is unaffected regardless. */
/* :not(.c7-reservation-availability *) — Commerce7's own tasting-
   reservation widget (calendar day cells, its own "Check Availability"
   button) renders entirely client-side from commerce7.js with complete
   button styling already; this blanket bare-button fallback was
   bleeding into every calendar day <button> too, forcing our border/
   fill treatment onto cells Commerce7 already styles and breaking the
   calendar grid's layout/spacing. */
[type="button"]:where(:not(.c7-reservation-availability *)),
[type="submit"]:where(:not(.c7-reservation-availability *)),
button:where(:not(.c7-reservation-availability *)) {
  background-color: transparent !important;
  border: 1px solid var(--fw-charcoal) !important;
  border-radius: var(--fw-radius) !important;
  color: var(--fw-charcoal) !important;
}
[type="button"]:where(:not(.c7-reservation-availability *)):focus,
[type="button"]:where(:not(.c7-reservation-availability *)):hover,
[type="submit"]:where(:not(.c7-reservation-availability *)):focus,
[type="submit"]:where(:not(.c7-reservation-availability *)):hover,
button:where(:not(.c7-reservation-availability *)):focus,
button:where(:not(.c7-reservation-availability *)):hover {
  background-color: var(--fw-charcoal) !important;
  border-color: var(--fw-charcoal) !important;
  color: var(--fw-cream) !important;
  text-decoration: none !important;
}

/* ...EXCEPT icon-only buttons — an SVG icon with no visible text label,
   like Commerce7's cart toggle and side-cart close button (both bare
   <button> elements containing only an icon, confirmed via DevTools).
   Boxing an icon in a bordered/filled button looks wrong; these get a
   completely chrome-free treatment instead, in every state.

   The cart toggle specifically also carries the .c7-link class, whose own
   rule (further down, .c7-link.c7-link — two classes, !important) is
   MORE specific than a plain button:has(svg) (two type-level selectors —
   class beats type at equal !important, regardless of source order), so
   it was winning and putting the border/hover-fill back. .c7-link.c7-link
   :has(svg) below is specific enough to beat that base rule, but ONLY
   when an svg icon is actually present — "Remove" (.c7-link, no icon) is
   completely unaffected and keeps its normal bordered/fill-on-hover look. */
button:has(svg), [type="button"]:has(svg),
.c7-link.c7-link:has(svg) {
  border: none !important;
  background-color: transparent !important;
  color: inherit !important;
  padding: 0 !important;
  min-height: 0 !important;
}
button:has(svg):hover, button:has(svg):focus,
[type="button"]:has(svg):hover, [type="button"]:has(svg):focus,
.c7-link.c7-link:has(svg):hover, .c7-link.c7-link:has(svg):focus {
  background-color: transparent !important;
  color: inherit !important;
}
html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  /* Prevents horizontal scroll from full-bleed sections. Deliberately on
     <html>, not <body>: overflow-x:hidden on body with no overflow-y set
     forces the browser to compute overflow-y as auto too (per the CSS
     Overflow spec, when only one axis is non-visible the other becomes
     auto), turning body into its own scroll container. That breaks any
     position:fixed descendant — including Commerce7's .c7-side-cart drawer
     — which then renders relative to that scrolling body box instead of
     the real viewport, producing a squished, mispositioned panel instead
     of a proper full-height right-side drawer. */
  overflow-x: hidden;
}

body {
  background: var(--fw-cream);
  color: var(--fw-charcoal);
  font-family: var(--fw-font-body);
  font-size: 17px;
  font-weight: 300;
  line-height: 1.7;
  letter-spacing: 0.01em;
  width: 100%;
}

img, video, iframe, table { max-width: 100%; height: auto; }
/* :not(.c7-reservation-availability *) — same problem as the bare-button
   reset above: Commerce7's reservation-availability widget renders its
   calendar day grid as a real <table> internally. Without this
   exclusion, this reset's display:block strips the table's row/column
   layout, scrambling the calendar into overlapping cells (a nav control
   bleeding into a date cell) instead of a real grid — the reservation
   calendar effectively fails to display. */
table:where(:not(.c7-reservation-availability *)) { display: block; overflow-x: auto; }

@media (max-width: 600px) {
  body { font-size: 16px; }
}

h1, h2, h3, h4, h5, h6 {
  font-family: var(--fw-font-heading);
  font-weight: 500;
  color: var(--fw-clay-dark);
  line-height: 1.2;
  letter-spacing: 0.01em;
  margin: 0 0 var(--fw-space-sm);
}

h1 { font-size: clamp(2.6rem, 4vw, 4.2rem); }
h2 { font-size: clamp(2rem, 3vw, 2.9rem); }
h3 { font-size: clamp(1.5rem, 2vw, 1.9rem); }

p { margin: 0 0 var(--fw-space-sm); }

/* Scoped away from Commerce7's own mount points (#c7-content, #c7-cart,
   #c7-account) — those regions must be styled entirely by commerce7.css's
   own --c7-link-color etc. (see inc/commerce7.php), not by our global
   anchor color, or its buttons/links pick up our merlot tint by accident.
   :where() keeps this at the same specificity as a plain "a" selector so
   it still loses cleanly to Commerce7's own more specific component
   classes on the rare occasion the two overlap. */
a:where(:not(#c7-content *, #c7-cart *, #c7-account *)) {
  color: var(--fw-clay);
  text-decoration: none;
  transition: color .2s ease;
}
a:where(:not(#c7-content *, #c7-cart *, #c7-account *)):hover { color: var(--fw-olive); }

img { max-width: 100%; display: block; }

.fw-eyebrow {
  display: inline-block;
  font-family: var(--fw-font-body);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--fw-olive);
  margin-bottom: var(--fw-space-xs);
}
/* Breadcrumb trail (functions.php, lh_render_breadcrumbs()) — reuses
   .fw-eyebrow's font/size/color/uppercase wholesale, only toning down
   the letter-spacing: 0.28em reads fine for one short word but is too
   spaced-out across a whole "Home / The Estate / Team" trail. */
.fw-breadcrumbs.fw-eyebrow { display: block; letter-spacing: 0.08em; margin-bottom: var(--fw-space-md); }
.fw-breadcrumbs a { color: var(--fw-olive); text-decoration: none; }
.fw-breadcrumbs a:hover { color: var(--fw-clay); text-decoration: underline; }
.fw-breadcrumbs [aria-current="page"] { color: var(--fw-charcoal-soft); }
.fw-breadcrumb-sep { margin: 0 6px; color: var(--fw-charcoal-soft); opacity: 0.5; }

.fw-container {
  max-width: var(--fw-container);
  margin: 0 auto;
  padding: 0 var(--fw-space-md);
}
@media (max-width: 600px) {
  .fw-container { padding: 0 var(--fw-space-sm); }
}

.fw-btn { width: auto; }
@media (max-width: 480px) {
  .fw-btn { width: 100%; justify-content: center; }
}

.fw-btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 14px 32px;
  font-family: var(--fw-font-body);
  font-size: 0.78rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  border: 1px solid var(--fw-clay);
  color: var(--fw-clay);
  background: transparent;
  border-radius: var(--fw-radius);
  cursor: pointer;
}
.fw-btn:hover { background: var(--fw-clay); color: var(--fw-cream); }
.fw-btn--solid { background: var(--fw-clay); color: var(--fw-cream); }
.fw-btn--solid:hover { background: var(--fw-clay-dark); color: var(--fw-cream); }
.fw-btn--accent {
  border-color: var(--fw-olive);
  color: var(--fw-gold-light);
  background: rgba(20, 8, 11, 0.32);
}
.fw-btn--accent:hover { background: var(--fw-olive); color: var(--fw-clay-dark); }

/* =========================================================
   3. PLACEHOLDER IMAGERY
   Elegant CSS-only stand-ins. Each block is tagged with the
   exact replacement spec in a corner label — search Unsplash /
   Pexels for the suggested term, drop the real photo in, then
   delete the .ph-tag span (or just leave it, it's display:none
   ready via .lh-no-tags on <body> if you want to hide labels
   site-wide while still deciding).
========================================================= */
.ph-img {
  position: relative;
  width: 100%;
  min-height: 320px;
  border-radius: var(--fw-radius);
  /* A dark neutral instead of the browser's default transparent (which
     shows the page background through, usually a much lighter cream) —
     the gap between this box existing and its background-image finishing
     its download reads as an intentional dark photo box settling in,
     not a broken/blank load (2026-09-11 audit, worst on the hero: it's
     the single biggest box on the page and often the LCP candidate). */
  background-color: var(--fw-ink);
  background-size: cover;
  background-position: center;
  /* Explicit no-repeat: the ph-* fallbacks below intentionally use
     background-IMAGE (not the background shorthand) so this size/repeat
     pair is never reset — a shorthand there once silently reverted
     size to auto and tiled hero photos on tall viewports. */
  background-repeat: no-repeat;
  overflow: hidden;
}
.ph-tag {
  position: absolute;
  right: 10px;
  bottom: 10px;
  z-index: 2;
  font-family: var(--fw-font-body);
  font-size: 0.62rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  background: rgba(43, 36, 32, 0.72);
  color: #fff;
  padding: 5px 10px;
  border-radius: var(--fw-radius);
}
body.lh-no-tags .ph-tag { display: none; }

.ph-hero {
  min-height: 640px;
  background-image: linear-gradient(155deg, #6d2430 0%, #4a141d 45%, #2c0d13 100%);
}
.ph-vineyard-row {
  min-height: 260px;
  background-image: linear-gradient(160deg, #7a5a37 0%, #5c4527 55%, #3c2f1c 100%);
}
.ph-wine {
  min-height: 380px;
  background-image: linear-gradient(165deg, #8a2f3c 0%, #5c1a24 60%, #341015 100%);
}
.ph-club {
  min-height: 460px;
  background-image: linear-gradient(150deg, #c9a86a 0%, #a1783f 55%, #6b4e26 100%);
}
.ph-portrait {
  min-height: 480px;
  background-image: linear-gradient(160deg, #5c4a3a 0%, #3a2c20 100%);
}
.ph-stone {
  min-height: 420px;
  background-image: linear-gradient(160deg, #cabfa8 0%, #a89a7c 55%, #7d6f56 100%);
}

/* =========================================================
   4. SITE HEADER
========================================================= */
#fw-header {
  position: sticky;
  top: 0;
  z-index: 999;
  background: var(--fw-cream);
  border-bottom: 1px solid rgba(43, 36, 32, 0.08);
  /* No backdrop-filter here (was: saturate(140%) blur(6px)) — per the CSS
     spec, backdrop-filter (like transform/filter/perspective) makes an
     element establish a NEW containing block for position:fixed
     descendants. #c7-cart lives inside this header, and Commerce7 renders
     its .c7-side-cart drawer (position:fixed; top:0; right:0; bottom:0)
     as a descendant of it — with backdrop-filter present, that drawer's
     fixed coordinates resolved relative to this header's own small box
     instead of the viewport, squishing it into a short band instead of a
     full-height panel. The 96%-opacity background still reads as
     frosted/glassy without needing the blur.
     If you want the blur effect back, apply backdrop-filter to a ::before
     pseudo-element positioned behind the header's content instead of on
     this element directly — that keeps #fw-header itself filter-free. */
}

.lh-topbar {
  background: var(--fw-clay-dark);
  color: var(--fw-gold-light);
  max-height: 40px;
  opacity: 1;
  overflow: hidden;
  transition: max-height 0.25s ease, opacity 0.2s ease;
}
.lh-topbar .fw-container {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-top: 8px;
  padding-bottom: 8px;
  font-size: 0.72rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.lh-topbar a { color: var(--fw-gold-light); }
.lh-topbar a:hover { color: #fff; }

.lh-header-main {
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* Longhand top/bottom only — this element is ALSO .fw-container (same
     div, both classes), which sets its own left/right padding via the
     "padding" shorthand. Using the shorthand here too would reset those
     to 0 (it appears later in the file, so it'd win the cascade) — that
     silently stripped the header's side inset site-wide, most visible in
     the mobile nav dropdown where full-width list rows made the missing
     edge padding obvious. */
  padding-top: 18px;
  padding-bottom: 18px;
  transition: padding 0.25s ease;
}

.lh-logo {
  font-family: var(--fw-font-heading);
  font-size: 1.7rem;
  font-weight: 600;
  color: var(--fw-clay-dark);
  letter-spacing: 0.03em;
  display: flex;
  align-items: center;
  gap: 10px;
}
.lh-logo img { max-height: 52px; width: auto; }
.lh-logo span.lh-logo-sub {
  display: block;
  font-family: var(--fw-font-body);
  font-size: 0.6rem;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--fw-olive);
  font-weight: 400;
  /* Prevents wrapping onto a second line if the logo is the flex item
     that gets squeezed when the header row is tight — same fix applied
     to albariza-house-theme's .alb-logo-sub (2026-09-07 report). */
  white-space: nowrap;
}

/* Direct-child combinator on purpose — scopes this to the top-level list
   only, so a nested .sub-menu (added when a menu item has children, e.g.
   "Wines" > Our Wines/Wine Club/Gift Cards) gets its own dropdown
   treatment below instead of inheriting this flex row layout. */
#lh-primary-nav > ul {
  list-style: none;
  display: flex;
  gap: 34px;
  margin: 0;
  padding: 0;
}
#lh-primary-nav a {
  font-size: 0.78rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fw-charcoal);
}
#lh-primary-nav a:hover,
#lh-primary-nav .current-menu-item > a { color: var(--fw-clay); }

/* Submenus (a menu item with children, e.g. Wines > Our Wines/Wine Club/
   Gift Cards, or Visit > Plan Your Visit/Events/Reserve a Tasting) —
   revealed on hover AND :focus-within so tabbing to a submenu link with
   a keyboard opens it too, not just a mouse hover. No custom nav walker/
   ARIA menu roles here — a plain nested <ul> is already announced
   correctly by screen readers, and this covers mouse + keyboard, which
   covers real use; a full ARIA menu widget would be real added
   machinery for marginal benefit over that. */
#lh-primary-nav .menu-item-has-children { position: relative; }
#lh-primary-nav .menu-item-has-children > a::after {
  content: "▾";
  display: inline-block;
  margin-left: 5px;
  font-size: 0.7em;
}
#lh-primary-nav .sub-menu {
  display: none;
  list-style: none;
  position: absolute;
  top: 100%;
  left: 0;
  flex-direction: column;
  min-width: 200px;
  margin: 0;
  padding: var(--fw-space-xs) 0;
  background: var(--fw-cream);
  border: 1px solid rgba(43, 36, 32, 0.08);
  box-shadow: 0 8px 24px rgba(43, 36, 32, 0.12);
  z-index: 20;
}
#lh-primary-nav .menu-item-has-children:hover > .sub-menu,
#lh-primary-nav .menu-item-has-children:focus-within > .sub-menu { display: flex; }
#lh-primary-nav .sub-menu a { display: block; padding: 10px var(--fw-space-sm); white-space: nowrap; }

.lh-header-actions {
  display: flex;
  align-items: center;
  gap: 18px;
}
/* Icon-only by default via the existing button:has(svg) bare-icon
   fallback (section 2) — no color/border rules needed here, just
   sizing/cursor to match the other header icon controls. */
.lh-search-toggle { display: flex; align-items: center; cursor: pointer; padding: 4px; }
/* The dropdown panel toggled by #lh-search-toggle (assets/js/theme.js) —
   [hidden] is all the show/hide logic needs (see the JS comment), this
   just adds the visual chrome once it's visible. */
.lh-header-search {
  border-top: 1px solid rgba(43, 36, 32, 0.08);
  background: var(--fw-cream);
  padding: var(--fw-space-sm) 0;
}
/* Commerce7\Integration::render_cart_trigger()'s fallback (.fw-cart-link)
   moved to forwineries-theme-core's core/assets/css/commerce7-overrides.css. */
/* Commerce7 mounts real widgets into these — we only control spacing
   around them, not their internal markup (that's commerce7.css's job). */
#c7-account { display: flex; align-items: center; font-size: 0.85rem; }
.c7-buy-product, .c7-club-join-button { margin-top: var(--fw-space-xs); }

/* #c7-cart lives in the header now (inc/commerce7.php, [c7_cart_trigger])
   — its intended location per Commerce7's own docs, right in the nav
   actions row. Two earlier attempts to reposition it with CSS
   (display:none, then position:fixed) both broke its internal count-badge
   logic, so this is deliberately hands-off: no positioning, no hiding,
   just normal inline-flex alignment matching its header siblings. */
#c7-cart { display: inline-flex; align-items: center; }

/* An earlier version of this rule reset EVERY descendant of #c7-cart
   (border/background/color, via a `#c7-cart *` wildcard). That assumed
   the drawer panel (.c7-side-cart) was NOT nested inside #c7-cart — it
   is, at least in this rendering — so the wildcard also stripped the
   drawer's own background and legitimately-styled buttons like "Proceed
   to Checkout", making the whole cart panel transparent. Reverted to the
   :has(svg) icon-button rule further down this file, which only targets
   genuinely icon-only buttons (the header toggle, the drawer's close X)
   without touching containers or intentional CTA buttons. */

/* Login — Commerce7 leaves this view visually bare by design; give it a
   card treatment matching the rest of the site. Scoped to .c7-form--login
   specifically (a real modifier class, confirmed in commerce7's own JS)
   rather than the bare .c7-form base class, which Commerce7 reuses for
   every form on the site — including the tiny inline add-to-cart form on
   each product tile. An earlier version of this rule targeted .c7-form
   generically and put the login card's huge padding/background on every
   product card's add-to-cart controls instead. */
#c7-content .c7-form--login,
#c7-content .c7-login-form {
  max-width: 460px;
  margin: var(--fw-space-lg) auto;
  padding: var(--fw-space-lg) var(--fw-space-md);
  background: var(--fw-cream-raised);
  border: 1px solid rgba(43, 36, 32, 0.08);
  border-radius: var(--fw-radius);
}
#c7-content .c7-club,
#c7-content .c7-reservation-type {
  padding: var(--fw-space-md);
  background: var(--fw-cream);
  border: 1px solid rgba(43, 36, 32, 0.08);
  border-radius: var(--fw-radius);
}
/* Confirmed via the widget's own rendered markup: .c7-form__group has no
   align-items set, so the bare submit button (no label sibling like the
   Date/Time/Guests fields have) stretches to the full label+field row
   height and its text centers across that taller box — reading as
   misaligned against the actual input row. Align the row to the fields'
   own baseline instead. */
.c7-reservation__search .c7-form__group {
  align-items: flex-end;
}
@media (max-width: 600px) {
  #c7-content .c7-form--login,
  #c7-content .c7-login-form { padding: var(--fw-space-md) var(--fw-space-sm); margin: var(--fw-space-md) auto; }
}

/* Wine/product cards — restyle Commerce7's default collection grid to
   match the site's editorial look (no underlined serif titles, on-brand
   pricing font). Card background/border is scoped to the "featured"
   variant ONLY (.c7-product-collection__products--featured .c7-product)
   — plain, non-featured grid items keep Commerce7's own bare background
   as-is, matching how Commerce7 itself distinguishes the two.
   Padding is intentionally left untouched on the featured card: Commerce7
   pairs its own 30px/20px/20px padding with a -60px top margin on
   .c7-product__image specifically so the bottle art pokes above the card
   by a calibrated amount — an earlier version of this rule overrode
   padding to a smaller value without adjusting for that, which crowded
   the image into the top of the card. */
#c7-content .c7-product-collection__product-list {
  gap: var(--fw-space-md);
}

/* Commerce7 only caps image height (max-height:300px) — it doesn't fix a
   consistent height or center images within one, so bottle photos with
   different natural proportions (some tall and thin, some shorter/wider
   crops) each render at their own size, making a row of products look
   misaligned. Forcing a fixed-height flex box with object-fit:contain
   gives every product image the same footprint and vertically centers
   the bottle within it, regardless of the source photo's own dimensions.

   !important is required here — the shop-layout-branding-for-commerce7
   plugin's own "Shop Layout" feature injects its own !important rules for
   .c7-product__image / .c7-product__image img at every breakpoint (e.g.
   "max-height: 300px !important; width: auto !important; height: auto
   !important;", confirmed via the live page's actual injected CSS), and
   !important always wins over a normal declaration regardless of
   specificity — an earlier version of this rule had no !important and
   was being silently overridden by the plugin's, which is why the fix
   appeared to do nothing.

   Scoped specifically to .c7-product-collection — NOT a bare #c7-content
   .c7-product__image. .c7-product__image is reused on the single product
   detail page (its own main photo + thumbnail gallery, an entirely
   different layout with no "row of products" to align) and in any
   related-products rail, both of which this fix was also incorrectly
   reaching and distorting. Only the collection/grid listing actually has
   the multiple-different-bottle-photos-in-a-row problem this solves. */
/* Selector matches the plugin's own exact chain (#c7-content
   .c7-product-collection .c7-product .c7-product__image, confirmed via
   the live page's injected CSS) with .c7-product doubled for extra
   specificity — the plugin's rule goes THROUGH .c7-product, which made it
   more specific than an earlier version of this rule that skipped
   straight from .c7-product-collection to .c7-product__image, so the
   plugin's !important won on specificity even before considering load
   order, and none of this was actually applying yet.

   align-self:stretch (overriding the plugin's own flex-start) makes the
   image box stretch to match its row's full height — necessary because a
   2-line product title on one card versus a 1-line title on its neighbor
   makes their rows genuinely different heights, so a fixed height alone
   still lets image boxes start at different Y positions if one row is
   taller than the other. Using min-height rather than height is what
   lets stretch actually take effect: per the flexbox spec, align-self:
   stretch is a no-op once an item has an explicit (non-auto) height —
   min-height doesn't count as "explicit" the same way, so the box can
   still grow to fill the row while keeping a guaranteed floor. Centering
   the bottle within whatever height that resolves to (align-items:
   center) keeps every image on the same visual centerline regardless of
   how tall the text content beside it happens to be. */
/* Two prefixes, not one: #c7-content is present on the dedicated /collection
   page (page-templates/page-c7-content.php manually wraps its mount point
   in <div id="c7-content">), but lh_c7_render_collection() — what powers
   the homepage's [c7_collection] embed — outputs a bare
   <div class="c7-product-collection"> with no #c7-content ancestor at all
   (inc/commerce7.php). An earlier version of this fix only had the
   #c7-content-prefixed selector, so it silently never matched on the
   homepage (0 specificity contest, just a selector that never applies) —
   the fix "worked" on /collection and did nothing on the homepage, which
   is why the bottle image stayed flush-left there specifically. The
   .lh-collection-embed prefix (the wrapper front-page.php puts around the
   homepage's shortcode output) covers that second context the same way. */
#c7-content .c7-product-collection .c7-product.c7-product .c7-product__image,
.lh-collection-embed .c7-product-collection .c7-product.c7-product .c7-product__image {
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  align-self: stretch !important;
  height: auto !important;
  min-height: 340px !important;
}
#c7-content .c7-product-collection .c7-product.c7-product .c7-product__image img,
.lh-collection-embed .c7-product-collection .c7-product.c7-product .c7-product__image img {
  width: 100% !important;
  height: 100% !important;
  max-width: 100% !important;
  max-height: 100% !important;
  object-fit: contain !important;
}
/* Confirmed via live DOM inspection that .c7-product__image wraps its img
   in an <a> (<div class="c7-product__image"><a><img></a></div>) — the <a>,
   not the img, is the actual direct flex item under the display:flex rule
   above. Left unstyled, that <a> has no explicit size, so it shrink-wraps
   to the img's own intrinsic pixel dimensions (confirmed 180x600 for the
   seed Chardonnay photo — a tall, narrow cutout) instead of filling the
   box, which is why justify-content: center above had an undersized item
   to center and bottle photos rendered flush left with dead space beside
   them.

   height is a fixed px value here, NOT 100% — .c7-product__image only sets
   min-height (a floor, kept deliberately so align-self:stretch can still
   equalize row heights per the comment above), never an explicit height,
   so it has no definite height of its own in the common case. height:100%
   on the <a> had nothing real to resolve against and fell back toward the
   img's own intrinsic height (600px for the seed photo), which is what
   blew the card up to nearly full-viewport-tall on mobile the first time
   this shipped. A fixed px height matching the container's own min-height
   floor gives object-fit:contain on the img below a real, bounded box to
   scale into instead. */
#c7-content .c7-product-collection .c7-product.c7-product .c7-product__image a,
.lh-collection-embed .c7-product-collection .c7-product.c7-product .c7-product__image a {
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  width: 100% !important;
  height: 340px !important;
}
#c7-content .c7-product-collection__products--featured .c7-product {
  background: var(--fw-cream);
  border: 1px solid rgba(43, 36, 32, 0.08);
  border-radius: var(--fw-radius);
}
#c7-content .c7-product__title a {
  text-decoration: none;
}
#c7-content .c7-product__title a:hover {
  text-decoration: underline;
}
#c7-content .c7-product__add-to-cart__price {
  font-family: var(--fw-font-body);
}
/* Quantity box + Add to Cart button default to flexbox's own nowrap —
   comfortable at normal widths, but with zero margin for error on the
   narrowest phones (~320px) once a product page adds its own side
   padding on top. Letting this pair wrap is a safe, invisible-until-
   actually-needed safety net rather than a visible layout change. */
#c7-content .c7-product__add-to-cart__form {
  flex-wrap: wrap;
}

/* Homepage embeds the collection widget just below our own "Estate
   Grown / Our Wines" heading — Commerce7 also renders its own collection
   -name heading ("Wines") at the top of the widget itself, duplicating
   ours and, on narrow screens, visually overlapping it. Hidden only in
   this specific homepage wrapper (front-page.php); the dedicated
   /collection page still shows Commerce7's own heading normally, since
   nothing else labels it there. */
.lh-collection-embed .c7-product-collection__content > h1,
.lh-collection-embed .c7-product-collection__content > .c7-h1,
.lh-collection-embed .c7-product-collection__content > h2 {
  display: none;
}

/* Product grid on small phones — two columns of wine cards gets cramped
   under ~480px (image, title, and price all squeeze together); drop to
   a single column so each card keeps readable proportions. Also shrink
   the fixed 260px image box from the alignment fix above — that height
   was sized for a multi-column desktop/tablet grid; once the grid is a
   single column on a narrow phone, 260px of image before any text even
   starts reads as a lot of scrolling for not much content. */
@media (max-width: 480px) {
  #c7-content .c7-product-collection__products--featured .c7-product-collection__product-list,
  #c7-content .c7-product-collection__product-list.c7-product-collection__product-list,
  .lh-collection-embed .c7-product-collection__products--featured .c7-product-collection__product-list,
  .lh-collection-embed .c7-product-collection__product-list.c7-product-collection__product-list {
    grid-template-columns: 1fr !important;
  }
  #c7-content .c7-product-collection .c7-product.c7-product .c7-product__image,
  .lh-collection-embed .c7-product-collection .c7-product.c7-product .c7-product__image {
    min-height: 280px !important;
  }
  #c7-content .c7-product-collection .c7-product.c7-product .c7-product__image a,
  .lh-collection-embed .c7-product-collection .c7-product.c7-product .c7-product__image a {
    height: 280px !important;
  }
}

/* Side-cart drawer line items — confirmed via live DevTools inspection to
   use a different, older set of classes (.c7-order-item__title, .c7-link)
   than the rest of the storefront (.c7-product__title etc), styled by a
   separate stylesheet ("c7-base.css") that hardcodes a pink/rose color
   (#c36) directly — including a solid fill on hover — rather than
   through any --c7-* custom property.

   Rather than hardcoding our own merlot here (which would work, but then
   permanently locks these specific elements out of a Commerce7 branding
   plugin's Brand Kit — it can only ever adjust --c7-* variables, never
   this file's literal color), these rules are pointed at the SAME
   --c7-* variables the rest of the storefront already uses. This theme's
   own bridge (top of this file) sets those variables to the brand colors
   below by default; a branding plugin overriding e.g. --c7-primary-color
   flows through here exactly like it does for every other Commerce7
   button, with no special-casing needed.

   Specificity is deliberately doubled (.c7-link.c7-link, not just
   .c7-link) and !important is still required — c7-base.css is injected
   by Commerce7's JS at runtime (after this stylesheet), so a same-
   specificity rule there wins any tie regardless of !important on either
   side. Unscoped/global on purpose: the drawer is portaled to <body> by
   Commerce7's own JS, so it isn't actually a descendant of #c7-content
   or #c7-cart, and .c7-link/.c7-order-item__title also appear on the
   dedicated /cart page outside any of those wrappers too. */
/* Product title — a plain text link, never a boxed button. */
.c7-order-item__title a,
.c7-order-item .c7-order-item__title a {
  color: var(--c7-link-color) !important;
  border: none !important;
  background-color: transparent !important;
}
.c7-order-item__title a:hover {
  color: var(--c7-primary-color-dark) !important;
}

/* "Remove" etc (.c7-link) — this one IS an actual button control, so it
   keeps a real bordered/outline look that fills on hover, same pattern as
   the generic bare-button fallback above, just routed through Commerce7's
   own --c7-primary-* variables instead of the theme's own charcoal/merlot
   — so a Commerce7 branding plugin's Brand Kit can still control this
   specific element's color, unlike the generic fallback which isn't
   Commerce7-specific and has no reason to defer to it. */
.c7-link.c7-link {
  color: var(--c7-link-color) !important;
  border: 1px solid var(--c7-primary-color) !important;
  background-color: transparent !important;
  padding: 0.45em 0.9em !important;
  line-height: 1.25 !important;
  min-height: 2.35em !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  box-sizing: border-box !important;
}
.c7-link.c7-link:hover {
  color: var(--c7-primary-button-text-color) !important;
  background-color: var(--c7-primary-button-bg-hover) !important;
  border-color: var(--c7-primary-button-bg-hover) !important;
}
.c7-order-item__price.c7-order-item__price,
.c7-order-item__price.c7-order-item__price span,
.c7-order-item__total.c7-order-item__total,
.c7-product__price.c7-product__price,
#c7-content .c7-product__add-to-cart__price {
  font-size: 1rem !important;
  font-weight: 500 !important;
  line-height: 1.3 !important;
}

/* Commerce7 reuses the SAME bare .c7-link class for the login page's
   "Forgot your password?" / "Create one" links (confirmed via user-
   supplied DOM: <a class="c7-link" href="/profile/forgot-password">,
   <a class="c7-link" href="/profile/create-account">) — the boxed-
   button look above is right for "Remove" in the cart, but wrong here:
   two bordered boxes next to the real "Log In" button reads as three
   competing buttons instead of one primary action plus two subtle
   secondary links. Scoped by the exact confirmed href rather than a
   guessed ancestor wrapper (e.g. ".c7-account-login") — the cart's
   "Remove" link isn't a real page link at all, so there's no risk of
   this ever matching it by accident, unlike a class/ancestor guess that
   could go wrong in either direction. */
a.c7-link[href*="/profile/forgot-password"],
a.c7-link[href*="/profile/create-account"] {
  border: none !important;
  background-color: transparent !important;
  color: var(--c7-link-color) !important;
  text-decoration: underline !important;
  padding: 0 !important;
  min-height: 0 !important;
  display: inline !important;
}
a.c7-link[href*="/profile/forgot-password"]:hover,
a.c7-link[href*="/profile/create-account"]:hover {
  background-color: transparent !important;
  color: var(--c7-primary-color-dark) !important;
}

/* "Proceed to Checkout" and other primary CTAs (.c7-btn.c7-btn--primary)
   — confirmed real selector via browser inspection (an <a> styled as a
   filled button, e.g. #c7-side-cart__summary__proceed). The earlier fix
   here guessed at a --c7-primary-button-text-color-hover CSS variable,
   which had no effect — Commerce7's own hover state isn't reading a
   variable for this element at all, so only a direct override works.
   Same specificity-doubling + !important pattern as .c7-link.c7-link
   above, for the same reason: c7-base.css loads after this stylesheet
   via Commerce7's own JS, so an equal-specificity rule there would win
   any tie regardless of !important on either side. */
.c7-btn.c7-btn--primary:hover,
.c7-btn.c7-btn--primary:focus {
  color: var(--c7-primary-button-text-color) !important;
  background-color: var(--c7-primary-button-bg-hover) !important;
  border-color: var(--c7-primary-button-bg-hover) !important;
}

/* Product page image gallery (confirmed real markup via browser
   inspection): Commerce7 already renders a proper main-image +
   clickable-thumbnail-strip structure on its own
   (.c7-product-detail__photo__thumbs wraps one <a><img></a> per extra
   image) — it just needs the thumbnails constrained to thumbnail SIZE.
   Our own global "img { max-width: 100%; display: block; }" rule
   (this file, section 2) was blowing each one up to the full width of
   .c7-product__image instead, which is what made multiple images stack
   as full-width "rows" rather than sit in a compact strip below the
   main photo. No slider/carousel needed — this is that gallery,
   correctly sized. */
/* Main product image — a direct child <img> of .c7-product__image,
   confirmed via inspection (sibling to .c7-product-detail__photo__thumbs,
   not inside it). Different product photos have wildly different
   aspect ratios (a tall bottle shot vs. a wide banner image, seen in
   the same product's own gallery) — with no fixed box, each one renders
   at its own natural height, so the whole layout visibly jumps every
   time a different thumbnail is clicked. A fixed-height box + object-fit
   fixes the jump; object-position: center (contain's own default, set
   explicitly here) keeps differently-shaped images centered in it
   instead of pinned to one corner. */
.c7-product__image > img {
  width: 100% !important;
  height: 460px !important;
  object-fit: contain !important;
  object-position: center !important;
}
@media (max-width: 600px) {
  .c7-product__image > img { height: 320px !important; }
}
.c7-product-detail__photo__thumbs {
  display: flex !important;
  flex-wrap: wrap !important;
  gap: 8px !important;
  margin-top: 8px !important;
}
.c7-product-detail__photo__thumbs a {
  display: block !important;
  width: 64px !important;
  flex: 0 0 64px !important;
}
.c7-product-detail__photo__thumbs img {
  width: 64px !important;
  height: 64px !important;
  object-fit: cover !important;
  border-radius: var(--fw-radius) !important;
  border: 1px solid rgba(43, 36, 32, 0.15) !important;
  cursor: pointer;
}
.lh-wine-view-link {
  display: inline-block;
  margin-top: 8px;
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  text-decoration: underline;
}

/* Cart drawer line items (.c7-order-item) — Commerce7's own CSS never
   gives this a responsive treatment at all (checked directly in
   commerce7.css: zero @media/@container rules reference .c7-order-item
   anywhere). It's a fixed 3-column flex row — 60px image, a flexible
   details column, and a pricing column carrying price + quantity
   dropdown + line total — that Commerce7's own CSS pins to a single row
   with flex-wrap: nowrap !important, regardless of how much space is
   actually available. On a narrow cart panel that overflowed/cramped
   (a forced horizontal scrollbar inside the drawer).

   The fix is just flex-wrap: wrap on .c7-order-item, with !important to
   beat Commerce7's own !important nowrap (confirmed via live DOM
   inspection — same pattern documented elsewhere in this file for
   .c7-product__image etc). Nothing else needs forcing: flex-wrap only
   has an effect once content actually doesn't fit, so this is a no-op
   on any row that already has room, and only drops pricing to its own
   line on the rows that genuinely need it.

   An earlier version of this ALSO forced .c7-order-item__pricing to
   flex: 0 0 100% — meant to make that wrapped line indent nicely under
   the details column — but that forced the full-width line
   UNCONDITIONALLY, on every cart regardless of available space, which
   is exactly the bug this fix exists to prevent: price/quantity kept
   landing on their own row even on cart panels with plenty of room
   beside the details column. Removed; .c7-order-item__pricing keeps
   only flex-wrap + alignment for the genuinely-narrow case, no forced
   basis. */
.c7-order-item {
  display: flex !important;
  flex-wrap: wrap !important;
}
.c7-order-item__pricing {
  display: flex !important;
  /* NOT flex:0 0 100% — an earlier version of this fix forced this onto
     its own full-width line unconditionally, on every cart regardless of
     how much room the row actually had. flex-wrap on the parent above
     already does the real job on its own: with no forced basis here,
     this row sits inline next to the details column whenever it fits
     (which is most of the time, including every wide cart panel — the
     case this was breaking), and only drops to its own line via normal
     flex-wrap once the row genuinely runs out of width. */
  flex-wrap: wrap !important;
  align-items: center !important;
  justify-content: flex-start !important;
  gap: 6px 12px !important;
}
.c7-order-item__price,
.c7-order-item__quantity,
.c7-order-item__total {
  flex: 0 0 auto !important;
}
@media (max-width: 480px) {
  .c7-side-cart__summary-container { padding: 16px 20px; }
}

/* Commerce7-route section padding (.fw-c7-page), the product-page
   "Back to Wines" link (.fw-back-link), and the blank checkout template's
   chrome (.fw-checkout-wrap / body.fw-c7-checkout-body) all moved to
   forwineries-theme-core's core/assets/css/commerce7-overrides.css —
   core/templates/page-c7-content.php and page-c7-checkout.php already
   emit exactly these class names. */

.lh-nav-toggle {
  display: none;
  flex-direction: column;
  gap: 5px;
  background: none;
  /* !important required — the generic bare-button fallback further up
     this file sets border: 1px solid ... !important on every plain
     <button> (including this one, since it matches the bare "button"
     tag selector), and a non-important border:none here loses to that
     regardless of source order, leaving an unwanted border box around
     the hamburger icon. Same category of issue as the pink-button saga
     documented earlier in this file. */
  border: none !important;
  cursor: pointer;
  padding: 6px;
}
.lh-nav-toggle span { width: 24px; height: 2px; background: var(--fw-charcoal); }
/* Defensive: guarantee no background in any interaction state. A pink fill
   was observed here on mobile that doesn't come from any rule in this
   file — likely a browser default tap-highlight or an external stylesheet
   — so this pins it down regardless of source. */
.lh-nav-toggle,
.lh-nav-toggle:hover,
.lh-nav-toggle:focus,
.lh-nav-toggle:active {
  background: none !important;
  background-color: transparent !important;
  -webkit-tap-highlight-color: transparent;
}

@media (max-width: 900px) {
  #lh-primary-nav { display: none; width: 100%; order: 3; }
  #lh-primary-nav.is-open { display: block; }
  #lh-primary-nav > ul { flex-direction: column; gap: 0; padding: var(--fw-space-sm) 0; }
  #lh-primary-nav li { border-top: 1px solid rgba(43,36,32,0.08); }
  #lh-primary-nav a { display: block; padding: 14px 0; }

  /* Submenus on mobile: no hover on touch, and the whole primary nav is
     already tucked behind the hamburger, so there's no real UX cost to
     just always showing children inline (indented) rather than building
     a second expand/collapse tap-toggle on top of the one that already
     opens/closes the whole menu. */
  #lh-primary-nav .menu-item-has-children > a::after { content: ""; }
  #lh-primary-nav .sub-menu {
    display: flex;
    position: static;
    flex-direction: column;
    min-width: 0;
    margin: 0 0 0 var(--fw-space-sm);
    padding: 0;
    background: none;
    border: none;
    border-left: 2px solid rgba(43,36,32,0.12);
    box-shadow: none;
  }
  #lh-primary-nav .sub-menu a { padding: 12px var(--fw-space-sm); font-size: 0.72rem; }
  #lh-primary-nav .sub-menu li { border-top: none; }

  /* Logo stays alone on the left; hamburger + login/cart are grouped as
     one cluster on the right (margin-left:auto on the first of the pair
     pushes that whole trailing group to the edge) instead of the default
     flex space-between spreading all three across the row with an
     awkward gap on each side of the hamburger. */
  .lh-header-main { flex-wrap: wrap; gap: 12px; }
  .lh-nav-toggle { display: flex; order: 1; margin-left: auto; }
  .lh-header-actions { order: 2; }
  #lh-primary-nav { order: 3; }

  .lh-topbar .fw-container { flex-direction: column; gap: 4px; text-align: center; }
  /* The stacked two-line mobile layout above is taller than the 40px
     cap the desktop collapse animation uses — without this the second
     line renders half-clipped. */
  .lh-topbar { max-height: 76px; }
}

@media (max-width: 480px) {
  .lh-logo { font-size: 1.4rem; gap: 6px; }
  .lh-logo span.lh-logo-sub { font-size: 0.52rem; letter-spacing: 0.16em; }
  .lh-header-actions { gap: 10px; }
  #c7-account { font-size: 0.72rem; }
}

/* =========================================================
   5. SECTION LAYOUT PRIMITIVES
========================================================= */
.fw-section { padding: var(--fw-space-xl) 0; }
.fw-section--cream { background: var(--fw-cream-raised); }
.fw-section-head { max-width: 640px; margin: 0 auto var(--fw-space-lg); text-align: center; }

/* Wine/club card grids, the Related Wines slider, Wines Catalog filter
   controls, and the Club Teaser grid all moved to
   forwineries-theme-core's core/assets/css/commerce7-overrides.css —
   Commerce7\Catalog's render functions now emit .fw-wine-*/.fw-catalog-*/
   .fw-club-* markup directly, matching that file's selectors. Nothing
   Larkhaven-specific was left behind; this whole block was already
   byte-identical (modulo prefix) with the other 4 sibling themes. */
/* Team page (page-templates/page-team.php) */
.fw-team-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--fw-space-md);
}
.fw-team-card {
  background: var(--fw-cream);
  border: 1px solid rgba(43, 36, 32, 0.08);
  border-radius: var(--fw-radius);
  overflow: hidden;
}
.fw-team-photo { width: 100%; min-height: 280px; object-fit: cover; }
.fw-team-card-body { padding: var(--fw-space-sm) var(--fw-space-sm) var(--fw-space-md); }
.fw-team-card h2 { margin-bottom: 2px; font-size: 1.3rem; }
.fw-team-role {
  color: var(--fw-olive);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  margin-bottom: var(--fw-space-xs);
}

/* Testimonials & Press (front-page.php) — a pull-quote treatment (thin
   gold rule above, no boxed background/border) instead of a plain
   bordered card, matching the editorial language established by the
   "As Seen In" strip right above this section rather than sitting a
   visible design generation behind it. */
.lh-testimonial-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--fw-space-lg) var(--fw-space-md);
}
.lh-testimonial-card {
  border-top: 2px solid var(--fw-olive);
  padding-top: var(--fw-space-md);
  text-align: left;
}
.lh-testimonial-quote {
  font-family: var(--fw-font-heading);
  font-style: italic;
  font-size: 1.2rem;
  line-height: 1.55;
  color: var(--fw-charcoal);
  margin-bottom: var(--fw-space-sm);
}
.lh-testimonial-quote::before { content: "\201C"; color: var(--fw-olive); }
.lh-testimonial-quote::after { content: "\201D"; color: var(--fw-olive); }
.lh-testimonial-source {
  display: block;
  color: var(--fw-olive);
  font-family: var(--fw-font-body);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* "As Seen In" press strip (front-page.php) — an editorial "masthead
   citation" treatment (thin rule above/below each name, italic serif,
   generous spacing) rather than a cramped row of dashed to-do boxes,
   since most sites run this section before any real logos are on hand.
   Real logo images still get the classic muted/grayscale-until-hover
   treatment once uploaded; the placeholder state below is what should
   look intentional and finished on its own, not like a stand-in. */
.lh-press-section { text-align: center; padding-top: var(--fw-space-xl); padding-bottom: var(--fw-space-xl); }
.lh-press-section .fw-eyebrow { display: block; margin-bottom: var(--fw-space-xs); }
.lh-press-heading { margin-bottom: var(--fw-space-lg); }
/* Continuous sliding "masthead" strip instead of wrapping to a second
   row once there are more publications than fit one line — front-
   page.php renders the item list twice (the second copy aria-hidden,
   tabindex="-1", visual-only) and this animates the combined row exactly
   -50% of its own width, which is precisely one full copy's width, so
   the moment the first copy has scrolled fully off, the (identical)
   second copy is sitting exactly where the first one started — the loop
   restarts with no visible seam. Fade mask softens the hard edges where
   logos enter/exit instead of an abrupt clip. Paused on hover/focus so
   a visitor can actually click a logo; disabled entirely under
   prefers-reduced-motion (vestibular-disorder safety, not just a nicety
   — continuous motion is exactly the kind of thing that spec exists for). */
.lh-press-strip-outer {
  overflow: hidden;
  max-width: 960px;
  margin: 0 auto;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.lh-press-strip {
  display: flex;
  align-items: center;
  gap: var(--fw-space-lg);
  width: max-content;
  animation: lh-press-scroll 32s linear infinite;
}
.lh-press-strip-dup { display: contents; }
.lh-press-strip-outer:hover .lh-press-strip,
.lh-press-strip-outer:focus-within .lh-press-strip { animation-play-state: paused; }
@keyframes lh-press-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  .lh-press-strip { animation: none; }
}
/* Descendant selectors, not direct-child (>) — the duplicated set for
   the seamless loop sits inside .lh-press-strip-dup (display:contents),
   which removes it from the BOX tree for layout but not the DOM tree,
   so a > combinator here would silently miss every duplicated item. */
.lh-press-strip a,
.lh-press-strip .lh-press-logo-placeholder {
  flex: 0 0 auto;
  min-width: 160px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.lh-press-strip img {
  max-height: 38px;
  width: auto;
  margin: 0 auto;
  filter: grayscale(100%);
  opacity: 0.55;
  transition: filter 0.25s ease, opacity 0.25s ease;
}
.lh-press-strip a:hover img,
.lh-press-strip a:focus-visible img { filter: grayscale(0%); opacity: 1; }
/* Real publication logos are trademarked, so an unset row shows this
   labeled placeholder instead of a fabricated logo image — same honesty-
   over-lorem-ipsum approach as every other ph-img placeholder. Thin
   rules above/below (not a box outline all the way round) read as a
   citation/masthead credit rather than an unfinished to-do item — the
   .ph-img default box/min-height/dashed-border look is overridden
   entirely rather than adapted, since none of it fits this treatment. */
.lh-press-logo-placeholder {
  width: auto !important;
  min-height: 0 !important;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--fw-space-sm) var(--fw-space-xs);
  border: none;
  border-top: 1px solid rgba(43, 36, 32, 0.16);
  border-bottom: 1px solid rgba(43, 36, 32, 0.16);
  border-radius: 0;
  background: none;
}
.lh-press-logo-placeholder .ph-tag {
  position: static;
  background: none;
  color: var(--fw-charcoal-soft);
  padding: 0;
  font-family: var(--fw-font-heading);
  font-size: 1.05rem;
  font-style: italic;
  letter-spacing: 0.02em;
  text-transform: none;
  white-space: nowrap;
}

/* Wine Club tier comparison (.fw-club-tier-*) moved to
   forwineries-theme-core's core/assets/css/commerce7-overrides.css. */
/* Social feed photo grid (front-page.php) — a hand-curated grid, not a
   live Instagram API embed: the Graph API requires an app review and an
   access token that expires and needs periodic renewal, which is a poor
   fit for a theme meant to be handed off to a non-technical client with
   no ongoing developer support. A client swaps photo URLs here the same
   way they already do for Team photos. */
.lh-social-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: var(--fw-space-xs);
}
.lh-social-grid a { display: block; position: relative; aspect-ratio: 1 / 1; overflow: hidden; border-radius: var(--fw-radius); }
.lh-social-grid img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 0.3s ease; }
.lh-social-grid a:hover img { transform: scale(1.05); }

/* Homepage email capture (front-page.php) — the same real [c7_subscribe]
   widget as the footer's "Stay in the Loop", but this section sits on a
   light background so it needs its own light-palette version rather than
   the footer's off-white-on-merlot styling. Structural fixes (column
   .c7-form__group, full-width .c7-form__field) match the footer's for
   the same confirmed-via-DevTools reasons — see style.css's "FOOTER"
   section for the full explanation. The submit button is left
   unstyled here on purpose: the global bare-button fallback (section 2)
   already renders charcoal-on-transparent, which is already correct
   against this light background, unlike the footer's dark one. */
.lh-email-capture { max-width: 480px; margin: 0 auto; text-align: center; }
.lh-email-capture .c7-form__group {
  display: flex !important;
  flex-direction: column !important;
  align-items: center !important;
  width: 100% !important;
  gap: var(--fw-space-sm) !important;
  margin-top: var(--fw-space-md);
}
.lh-email-capture .c7-form__field { width: 100% !important; margin: 0 !important; padding: 0 !important; }
.lh-email-capture label {
  display: block !important;
  width: 100%;
  margin: 0 0 6px !important;
  color: var(--fw-charcoal-soft);
  font-size: 0.78rem;
  text-align: left;
}
.lh-email-capture input[type="email"] {
  width: 100% !important;
  height: auto !important;
  padding: 6px 0 !important;
  border: none !important;
  border-bottom: 1px solid rgba(43, 36, 32, 0.3) !important;
  background: transparent !important;
  color: var(--fw-charcoal) !important;
  border-radius: 0 !important;
  margin: 0 !important;
  box-sizing: border-box !important;
}
.lh-email-capture input[type="email"]:focus { border-bottom-color: var(--fw-clay) !important; outline: none; }
.lh-email-capture button,
.lh-email-capture [type="submit"] {
  width: auto !important;
  padding: 10px 24px !important;
}

/* Site search (searchform.php) — reused as-is by the header's search
   toggle panel, 404.php, and search.php, so it's defined once, generic,
   not scoped to any one of those. All three sit on the theme's normal
   off-white/light backgrounds, so unlike the newsletter form this needs
   no separate light/dark variant.

   The icon sits INSIDE the input as an absolutely-positioned overlay
   button (same idea as the Wines Catalog's own search — now
   .fw-catalog-search-wrap, forwineries-theme-core's commerce7-
   overrides.css) rather than as a second element next to it —
   a bordered icon button beside a bordered input reads as two
   disconnected boxes rather than one search bar, especially once the
   input's own focus-visible outline (section 2 — WCAG 2.4.7, kept
   deliberately rather than suppressed) adds a second, differently-
   colored ring around just the input on open (the panel auto-focuses
   it, see assets/js/theme.js). One box, one border, is the fix — not
   fighting the accessibility outline. */
.lh-search-form-wrap { margin-bottom: var(--fw-space-md); }
.lh-search-form-field { position: relative; max-width: 480px; }
.lh-search-input {
  width: 100%;
  padding: 11px 46px 11px 16px;
  border: 1px solid rgba(43, 36, 32, 0.25);
  border-radius: var(--fw-radius);
  font-family: var(--fw-font-body);
  font-size: 0.95rem;
  color: var(--fw-charcoal);
  background: var(--fw-cream);
  box-sizing: border-box;
}
.lh-search-submit {
  position: absolute;
  top: 50%;
  right: 4px;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  background: transparent !important;
  border: none !important;
  /* !important: the global button:has(svg) icon-only fallback (section 2)
     already sets color:inherit !important, which would otherwise win
     over a plain (non-important) color here regardless of this rule's
     own specificity. */
  color: var(--fw-charcoal-soft) !important;
}
.lh-search-submit:hover { color: var(--fw-clay) !important; background: transparent !important; }

/* Contact form (page-templates/page-contact.php) */
.fw-contact-form label {
  display: block;
  font-family: var(--fw-font-body);
  font-size: 0.78rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-bottom: 6px;
}
.fw-contact-form input[type="text"],
.fw-contact-form input[type="email"],
.fw-contact-form textarea {
  width: 100%;
  padding: 12px 14px;
  border: 1px solid rgba(43, 36, 32, 0.2);
  border-radius: var(--fw-radius);
  background: var(--fw-cream);
  color: var(--fw-charcoal);
  font-family: var(--fw-font-body);
  font-size: 1rem;
}
.fw-contact-form input:focus-visible,
.fw-contact-form textarea:focus-visible {
  outline: 2px solid var(--fw-clay);
  outline-offset: 1px;
}
.fw-contact-form button[type="submit"] { margin-top: var(--fw-space-xs); }
/* Honeypot — off-screen (not display:none) so unsophisticated bots that
   check for that specific property still fill it in, while aria-hidden
   plus tabindex="-1" (on the input, in page-contact.php) keeps it fully
   out of the way for screen reader and keyboard users. */
.fw-hp-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
.fw-form-notice {
  padding: var(--fw-space-sm) var(--fw-space-md);
  border-radius: var(--fw-radius);
  margin-bottom: var(--fw-space-md);
  font-size: 0.95rem;
}
.fw-form-notice--success { background: var(--fw-cream-raised); border: 1px solid var(--fw-olive); color: var(--fw-charcoal); }
.fw-form-notice--error { background: #fbeaea; border: 1px solid #c0392b; color: #7a2418; }

/* Blog archive (archive.php) */
.lh-blog-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: var(--fw-space-md);
}
.lh-blog-card {
  background: var(--fw-cream);
  border: 1px solid rgba(43, 36, 32, 0.08);
  border-radius: var(--fw-radius);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.lh-blog-card-media { display: block; }
.lh-blog-card-media img { display: block; width: 100%; height: 220px; object-fit: cover; }
.lh-blog-card-media .ph-img { min-height: 220px; }
.lh-blog-card-body { padding: var(--fw-space-sm) var(--fw-space-sm) var(--fw-space-md); }
.lh-blog-meta {
  display: block;
  color: var(--fw-olive);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  margin-bottom: var(--fw-space-xs);
}
.lh-blog-card h2 { font-size: 1.4rem; margin-bottom: var(--fw-space-xs); }
.lh-blog-card h2 a { color: inherit; text-decoration: none; }

/* Events archive card — reuses .lh-blog-card wholesale, this is just the
   date badge overlaid on the card image (/events, archive-lh_event.php).
   Scoped to .lh-event-card specifically rather than changing the shared
   .lh-blog-card-media rule, so real blog post cards are unaffected. */
.lh-event-card .lh-blog-card-media { position: relative; }
.lh-event-date-badge {
  position: absolute;
  top: var(--fw-space-xs);
  left: var(--fw-space-xs);
  background: var(--fw-clay);
  color: var(--fw-cream);
  font-family: var(--fw-font-body);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.04em;
  padding: 6px 12px;
  border-radius: var(--fw-radius);
}
.lh-blog-card h2 a:hover { color: var(--fw-clay); }

.lh-pagination {
  display: flex;
  justify-content: center;
  gap: var(--fw-space-xs);
  margin-top: var(--fw-space-lg);
  flex-wrap: wrap;
}
.lh-pagination .page-numbers {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 40px;
  height: 40px;
  padding: 0 10px;
  border: 1px solid rgba(43, 36, 32, 0.15);
  border-radius: var(--fw-radius);
  color: var(--fw-charcoal);
  text-decoration: none;
}
.lh-pagination .page-numbers.current { background: var(--fw-clay); border-color: var(--fw-clay); color: var(--fw-cream); }
.lh-pagination .page-numbers:hover:not(.current) { border-color: var(--fw-clay); }

/* Single post (single.php) */
.lh-post-hero img { display: block; width: 100%; max-height: 480px; object-fit: cover; }
.lh-post-container { max-width: 760px; }
.lh-post-header { text-align: center; margin-bottom: var(--fw-space-lg); }
.lh-post-meta { color: var(--fw-charcoal-soft); font-size: 0.9rem; }
.lh-post-content { font-size: 1.05rem; line-height: 1.75; }
.lh-post-content > * + * { margin-top: var(--fw-space-sm); }
.lh-post-content img { max-width: 100%; height: auto; border-radius: var(--fw-radius); }
.lh-post-footer { margin-top: var(--fw-space-xl); padding-top: var(--fw-space-md); border-top: 1px solid rgba(43, 36, 32, 0.1); }
.lh-post-terms { color: var(--fw-charcoal-soft); font-size: 0.9rem; }
.lh-post-nav {
  display: flex;
  justify-content: space-between;
  gap: var(--fw-space-sm);
  margin: var(--fw-space-md) 0;
  flex-wrap: wrap;
}
.lh-post-nav a { text-decoration: none; color: var(--fw-clay); font-weight: 500; }
.lh-post-nav a:hover { text-decoration: underline; }
.lh-post-back { text-align: center; margin-top: var(--fw-space-md); }
@media (max-width: 600px) {
  .lh-post-nav { flex-direction: column; text-align: center; }
}

/* .c7-buy-product (Commerce7's own quantity + Add to Cart mount point —
   used both by our own wine cards and inside Commerce7's official
   [c7_collection] widget on the homepage) renders its qty input/button
   as its own internal flex/block row, which text-align:center on a
   surrounding wrapper never reaches (that only affects inline content,
   not how a block/flex child arranges ITS OWN children). Once card
   layouts stack to a centered single column on mobile, that left this
   row visibly left-aligned while everything else around it centered.
   Forcing display:flex + justify-content:center here takes control of
   that arrangement directly instead of relying on inherited text-align. */
@media (max-width: 600px) {
  .c7-buy-product { display: flex !important; justify-content: center !important; }
}

/* =========================================================
   6. REUSABLE PAGE-BUILDING BLOCKS
   Apply these as "CSS Classes" (Advanced tab) on Elementor
   Section/Container + Column widgets so freehand pages still
   match the site system. See readme.txt for usage per block.
========================================================= */

/* Sticky header gets a touch shorter once you've scrolled — keeps
   more screen real-estate on phones. */
#fw-header.is-scrolled .lh-header-main { padding-top: 10px; padding-bottom: 10px; }
#fw-header.is-scrolled .lh-topbar { max-height: 0; opacity: 0; }

/* Header is NOT sticky on mobile. Commerce7 renders its own fixed/sticky
   elements on small screens (mobile checkout/cart action bars — see e.g.
   .c7-account-club-shipment__mobile-actions in commerce7.css, position:
   fixed), and two independent fixed/sticky layers both anchored to the
   viewport edge can end up overlapping each other, which is what caused
   cart/checkout content to render underneath the header instead of below
   it. Trading the always-visible nav for guaranteed no-collision is the
   right call on the limited vertical space of a phone screen anyway. */
@media (max-width: 900px) {
  #fw-header { position: static; }
}

/* Floating cart button — the mobile answer to "no sticky header" above:
   one small fixed element instead of a whole fixed header bar, so it
   can't collide with Commerce7's own fixed cart-drawer/checkout
   elements the way a sticky header did. Toggled by assets/js/theme.js
   once scrolled well past the header. Deliberately does NOT use
   transform/filter/backdrop-filter/contain — any of those would make
   THIS element a new containing block for Commerce7's .c7-side-cart
   drawer (rendered as ITS descendant), breaking its own position:fixed
   coordinates exactly like the backdrop-filter bug documented on
   #fw-header above. position:fixed alone doesn't have that effect, so
   plain positioning + a couple of harmless visual properties is safe. */
#c7-cart.lh-cart-float {
  position: fixed;
  bottom: 20px;
  right: 20px;
  z-index: 998;
  width: 56px;
  height: 56px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--fw-cream);
  border: 1px solid var(--fw-clay);
  border-radius: 50%;
  box-shadow: 0 4px 14px rgba(43, 36, 32, 0.25);
}
@media (min-width: 901px) {
  /* Never float on desktop — the sticky header already keeps the cart
     visible at all times there. */
  #c7-cart.lh-cart-float { position: static; width: auto; height: auto; background: none; border: none; box-shadow: none; }
}

/* Full-bleed hero with centered overlay content (home, wines, visit). */
.fw-hero {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  color: var(--fw-cream);
  padding: var(--fw-space-xl) var(--fw-space-md);
}
/* Every hero gets the same proper hero height regardless of which
   .ph-* gradient-fallback modifier it happens to be paired with for
   its placeholder color — ph-portrait/ph-stone/ph-vineyard-row (480px/
   420px/260px) were built for small split-section images, not
   full-bleed heroes, and background-size:cover still centers correctly
   in a too-short box, but crops down to a narrow sliver instead of a
   proper hero-height crop. Desktop-only (min-width matches the 600px
   mobile breakpoint below): .fw-hero.ph-img (2 classes) would otherwise
   outrank the mobile media query's plain .fw-hero rule on specificity
   alone regardless of viewport, undoing that deliberately shorter
   mobile height. */
@media (min-width: 601px) {
  /* 680px (was 560px) — a taller, more cinematic full-bleed crop reads
     more editorial/luxury than the previous "banner" proportions;
     applies sitewide (every ph-img hero, not just the homepage) for
     consistency rather than special-casing the homepage alone. */
  .fw-hero.ph-img { min-height: 680px; }
}
.fw-hero::before {
  content: "";
  position: absolute;
  inset: 0;
  /* Deep enough that text stays WCAG AA-legible (verified against the
     brightest plausible photo regions — sky, sunlit vines) even before
     the text-shadow below adds its own margin. A lighter overlay reads
     nicely against a mid-tone photo but silently fails contrast the
     moment a client uploads something brighter, so this errs dark. */
  background: linear-gradient(180deg, rgba(20, 8, 11, 0.55) 0%, rgba(20, 8, 11, 0.72) 100%);
}
/* min-width:0 — flex items default to min-width:auto (not 0), refusing
   to shrink below their content's own preferred width. Commerce7's
   reservation-form row (date input + calendar icon + two dropdowns)
   doesn't wrap, so on a narrow phone viewport this flex item (and the
   hero card along with it) could be forced wider than the available
   space instead of shrinking to fit, spilling the CTA band past its own
   rounded-card bounds. min-width:0 is the standard fix for this
   flexbox gotcha. */
.fw-hero-content { position: relative; z-index: 1; max-width: 760px; min-width: 0; }
.fw-hero-content h1,
.fw-hero-content h2,
.fw-hero-content p,
.fw-hero-content .fw-eyebrow { text-shadow: 0 1px 4px rgba(0, 0, 0, 0.55); }
.fw-hero-content h1 { color: var(--fw-cream); }
.fw-hero-content h2 { color: var(--fw-cream); }
.fw-hero-content .fw-eyebrow { color: var(--fw-gold-light); }
/* A short, punchy "why us" line — deliberately smaller and gold rather
   than styled like the main subtext above it, so it reads as a distinct
   supporting hook, not a continuation of the same sentence. */
.lh-hero-differentiator {
  color: var(--fw-gold-light);
  font-size: 0.85rem;
  font-style: italic;
  margin-top: -8px;
}
@media (max-width: 600px) {
  .fw-hero { padding: var(--fw-space-lg) var(--fw-space-sm); min-height: 340px; }
}

/* The reservation-availability widget embed (.fw-reservation-widget-embed
   and its --page variant) plus the calendar-dropdown mobile fix all
   moved to forwineries-theme-core's core/assets/css/
   commerce7-overrides.css — this is the exact bug this entire shared-
   core rebuild started from; see that file's own comments for the full
   3-part story. Commerce7\ReservationWidget's render() output already
   uses this markup unchanged. */

/* Shorter variant for mid-page promo bands (e.g. wine club CTA) that reuse
   the hero's full-bleed overlay treatment without the full hero height.
   The overflow:visible this band needs for the reservation widget's
   calendar dropdown (previously here) now lives in forwineries-theme-
   core's commerce7-overrides.css alongside that widget's own CSS — this
   rule only owns the band's own height sizing now. */
.fw-hero.fw-hero--band { min-height: 420px; }
@media (max-width: 600px) {
  .fw-hero.fw-hero--band { min-height: 340px; }
}
/* The homepage stacks two of these back to back (Wine Club CTA, then
   Reservation CTA) — different photos with no gap between them read as
   a jarring, almost broken-looking hard seam rather than two deliberate
   sections. A thin line at the boundary is enough to read as an
   intentional division instead. */
.fw-hero.fw-hero--band + .fw-hero.fw-hero--band { border-top: 1px solid rgba(250, 247, 242, 0.25); }

/* Horizontal CTA button groups (hero, promo bands, visit section). */
.fw-btn-row {
  display: flex;
  gap: 16px;
  justify-content: center;
  flex-wrap: wrap;
  margin-top: var(--fw-space-sm);
}
@media (max-width: 480px) {
  .fw-btn-row { flex-direction: column; align-items: stretch; }
}

/* Centered CTA under a section (e.g. "View Full Collection"). */
.fw-section-cta { text-align: center; margin-top: var(--fw-space-lg); }

/* Two-up split (image / text) — reorders to image-on-top on mobile. */
.fw-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--fw-space-lg);
  align-items: center;
}
.fw-split.fw-split--reverse .fw-split-media { order: 2; }
.fw-split.fw-split--reverse .fw-split-text { order: 1; }
/* The Flagship Wine section links its heading to the product page, which
   would otherwise pick up the global anchor color. .fw-wine-card h3 a
   (core/assets/css/commerce7-overrides.css) and .lh-blog-card h2 a
   already override back to inherit for every other wine/post title on
   the site, so this section's title should match. */
.fw-split-text h2 a { color: inherit; text-decoration: none; }
/* Commerce7's own product photo is a bottle cutout on plain background,
   not the wide still-life shot .ph-img's background-size:cover otherwise
   assumes — cover crops a bottle photo into an unrecognizable close-up,
   so it gets shown whole on a neutral card instead. */
.fw-split-media.fw-split-media--product-photo {
  background-size: contain;
  background-repeat: no-repeat;
  background-color: var(--fw-cream);
}
@media (max-width: 780px) {
  .fw-split { grid-template-columns: 1fr; gap: var(--fw-space-md); }
  .fw-split .fw-split-media,
  .fw-split.fw-split--reverse .fw-split-media { order: 1 !important; }
  .fw-split .fw-split-text,
  .fw-split.fw-split--reverse .fw-split-text { order: 2 !important; }
}

/* Homepage in-page "chapter" nav (front-page.php) — desktop only. Active
   dot + smooth scroll are handled in assets/js/theme.js. */
.lh-section-nav {
  position: fixed;
  right: 24px;
  top: 50%;
  transform: translateY(-50%);
  z-index: 500;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.lh-section-nav a {
  position: relative;
  display: block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: rgba(43, 36, 32, 0.25);
  transition: background 0.2s ease, transform 0.2s ease;
}
.lh-section-nav a:hover,
.lh-section-nav a:focus-visible,
.lh-section-nav a.is-active {
  background: var(--fw-clay);
  transform: scale(1.35);
}
/* Label stays invisible until hover/focus — the dots alone are enough of
   a landmark once you know what they do, so there's no need for
   permanently-visible text competing with the actual page content. */
.lh-section-nav-label {
  position: absolute;
  right: 20px;
  top: 50%;
  transform: translateY(-50%);
  white-space: nowrap;
  background: var(--fw-charcoal);
  color: var(--fw-cream);
  font-family: var(--fw-font-body);
  font-size: 0.7rem;
  letter-spacing: 0.04em;
  padding: 5px 10px;
  border-radius: var(--fw-radius);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
}
.lh-section-nav a:hover .lh-section-nav-label,
.lh-section-nav a:focus-visible .lh-section-nav-label { opacity: 1; }
@media (max-width: 900px) {
  .lh-section-nav { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .lh-section-nav a { transition: none; }
  .lh-section-nav-label { transition: none; }
}

/* Homepage photo gallery (front-page.php) — full-bleed edge-to-edge
   (deliberately outside .fw-container, unlike every other homepage
   section), asymmetric mosaic: one large tile (a) plus four smaller
   ones (b-e), matching a magazine spread rather than a boxed gallery
   widget. Named grid-template-areas rather than nth-child/auto-flow so
   each tile's exact position is explicit and easy to reason about. */
.lh-gallery-mosaic {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(2, 260px);
  grid-template-areas:
    "a a b c"
    "a a d e";
  gap: 4px;
}
/* overflow:hidden + a scaling <img> inside (rather than background-size
   growing on the tile itself, the earlier version's approach) — needed
   now that each tile holds a real <img loading="lazy"> instead of a CSS
   background-image, which is what actually makes lazy-loading possible. */
.lh-gallery-tile { overflow: hidden; }
.lh-gallery-tile img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
  transition: transform 0.6s ease;
}
.lh-gallery-tile:hover img { transform: scale(1.08); }
.lh-gallery-tile--a { grid-area: a; }
.lh-gallery-tile--b { grid-area: b; }
.lh-gallery-tile--c { grid-area: c; }
.lh-gallery-tile--d { grid-area: d; }
.lh-gallery-tile--e { grid-area: e; }
@media (max-width: 900px) {
  .lh-gallery-mosaic {
    grid-template-columns: repeat(2, 1fr);
    grid-template-rows: repeat(3, 200px);
    grid-template-areas:
      "a a"
      "b c"
      "d e";
  }
}
@media (max-width: 480px) {
  .lh-gallery-mosaic {
    grid-template-columns: 1fr;
    grid-template-rows: repeat(5, 220px);
    grid-template-areas:
      "a"
      "b"
      "c"
      "d"
      "e";
  }
}
/* Respect the same motion-sensitivity concern as the press strip's
   marquee — the hover-zoom is decorative, not load-bearing. */
@media (prefers-reduced-motion: reduce) {
  .lh-gallery-tile { transition: none; }
}

/* Three-up stat row (est. year / acres / cases produced, etc) — thin
   vertical rules between figures instead of plain grid gaps, and an
   italic serif treatment on the numbers, matching the same editorial-
   citation language as the "As Seen In" strip and Testimonials pull-
   quotes rather than reading as a plainer, older part of the page. */
.fw-stats-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--fw-space-md);
  text-align: center;
}
.fw-stats-row > div { position: relative; padding: 0 var(--fw-space-sm); }
.fw-stats-row > div + div::before {
  content: "";
  position: absolute;
  left: 0;
  top: 6px;
  bottom: 6px;
  width: 1px;
  background: rgba(43, 36, 32, 0.15);
}
.fw-stats-row .fw-stat-num {
  font-family: var(--fw-font-heading);
  font-style: italic;
  font-size: clamp(2rem, 4vw, 3rem);
  color: var(--fw-clay);
  display: block;
}
.fw-stats-row .fw-stat-label {
  font-size: 0.72rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--fw-charcoal-soft);
}
@media (max-width: 600px) {
  .fw-stats-row { grid-template-columns: 1fr; gap: var(--fw-space-md); }
  .fw-stats-row > div + div::before { display: none; }
}

/* Generic responsive gap/padding helpers for Elementor sections. */
@media (max-width: 600px) {
  .fw-section { padding: var(--fw-space-md) 0; }
  .fw-section-head { margin-bottom: var(--fw-space-sm); }
}

/* =========================================================
   7. FOOTER
========================================================= */
#lh-footer {
  background: var(--fw-clay-dark);
  color: var(--fw-gold-light);
  padding-top: var(--fw-space-xl);
}
#lh-footer a { color: var(--fw-cream); }
#lh-footer a:hover { color: var(--fw-olive); }
#lh-footer h4 {
  color: var(--fw-cream);
  font-family: var(--fw-font-body);
  font-size: 0.78rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  margin-bottom: var(--fw-space-sm);
}
.lh-footer-grid {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr 1.2fr;
  gap: var(--fw-space-lg);
  padding-bottom: var(--fw-space-lg);
  border-bottom: 1px solid rgba(250,247,242,0.12);
}
.lh-footer-grid ul { list-style: none; margin: 0; padding: 0; }
.lh-footer-grid li { margin-bottom: 10px; font-size: 0.92rem; }
/* [c7_subscribe] — email-only (inc/commerce7.php dropped
   data-has-name-field), matching the minimal single-field pattern real
   winery footers use (e.g. Joseph Phelps: underline input, small label,
   compact outline button) instead of a boxed multi-field form. Actual
   rendered markup confirmed via live DevTools inspection:
     .c7-subscribe > form.c7-form > div.c7-form__group >
       div.c7-form__field (label+input) + button.c7-btn
   !important throughout because Commerce7's own base CSS is injected by
   its JS after this stylesheet loads, so an equal-specificity rule there
   would otherwise win the cascade tie regardless of source order (same
   reasoning as the .c7-link/.c7-btn overrides further down this file). */
/* Generic fallback: keeps the Subscribe button bottom-aligned with the
   email input wherever [c7_subscribe] is placed, not just inside the
   two wrapper contexts below (.lh-footer-newsletter / .lh-email-capture). */
.c7-subscribe .c7-form__group { align-items: flex-end !important; }

.lh-footer-newsletter .c7-form__group {
  display: flex !important;
  flex-direction: column !important;
  align-items: flex-start !important;
  width: 100% !important;
  gap: var(--fw-space-sm) !important;
}
/* Commerce7's own CSS gives .c7-form__field its own margin/padding,
   designed for a wide multi-column layout — zeroed out so the flex gap
   above is the only source of spacing between the field and the button. */
.lh-footer-newsletter .c7-form__field { width: 100% !important; margin: 0 !important; padding: 0 !important; }
.lh-footer-newsletter label {
  display: block !important;
  width: 100% !important;
  margin: 0 0 6px !important;
  color: var(--fw-gold-light);
  font-size: 0.78rem;
}
/* Underline instead of a boxed input — same minimal treatment as the
   Joseph Phelps reference this was matched to. */
.lh-footer-newsletter input[type="email"] {
  width: 100% !important;
  height: auto !important;
  padding: 6px 0 !important;
  border: none !important;
  border-bottom: 1px solid rgba(250,247,242,0.35) !important;
  background: transparent !important;
  color: var(--fw-cream) !important;
  border-radius: 0 !important;
  margin: 0 !important;
  box-sizing: border-box !important;
}
.lh-footer-newsletter input[type="email"]:focus { border-bottom-color: var(--fw-olive) !important; outline: none; }
/* The widget's own submit button (.c7-btn.c7-btn--primary, confirmed via
   live DevTools) still falls back to this file's global bare-button
   treatment (section 2) for its border/text color — which uses
   --fw-charcoal, nearly invisible against this footer's dark merlot-dark
   background. Same off-white/gold treatment as the footer's legal links
   (verified 9.17:1 contrast) instead, kept compact/left-aligned (not
   full width) to match the reference's small "SIGN UP" button rather
   than a large full-width box. */
.lh-footer-newsletter button,
.lh-footer-newsletter [type="submit"] {
  width: auto !important;
  align-self: flex-start !important;
  padding: 10px 24px !important;
  border-color: var(--fw-cream) !important;
  color: var(--fw-cream) !important;
}
.lh-footer-newsletter button:hover, .lh-footer-newsletter button:focus,
.lh-footer-newsletter [type="submit"]:hover, .lh-footer-newsletter [type="submit"]:focus {
  background-color: var(--fw-olive) !important;
  border-color: var(--fw-olive) !important;
  color: var(--fw-clay-dark) !important;
}
.lh-social { display: flex; gap: 14px; margin-top: var(--fw-space-sm); }
.lh-bottom-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--fw-space-sm);
  padding: var(--fw-space-sm) 0;
  font-size: 0.75rem;
  color: rgba(244,237,225,0.6);
}
.lh-legal-links { display: flex; gap: 16px; flex-wrap: wrap; }
.fw-credit { text-align: center; font-size: 0.68rem; opacity: 0.5; padding-bottom: var(--fw-space-sm); }
.fw-credit a { color: inherit; text-decoration: none; }
.fw-credit a:hover { opacity: 1; text-decoration: underline; }
/* CC BY/BY-SA attribution for the 4 Wikimedia-sourced homepage photos —
   see the comment above this markup in footer.php. Deliberately smaller/
   quieter than .lh-bottom-bar itself (this is compliance text, not
   something a visitor needs to notice), but still real, legible, and
   linked, not hidden. */
.lh-photo-credits {
  padding-bottom: var(--fw-space-sm);
  font-size: 0.68rem;
  color: rgba(244,237,225,0.4);
  text-align: center;
}
.lh-photo-credits a { color: rgba(244,237,225,0.55); }
.lh-photo-credits a:hover { color: var(--fw-gold-light); }
.lh-legal-links a { color: var(--fw-gold-light); text-decoration: none; }
.lh-legal-links a:hover { text-decoration: underline; }

@media (max-width: 900px) {
  .lh-footer-grid { grid-template-columns: 1fr 1fr; }
  .lh-bottom-bar { flex-direction: column; gap: 10px; text-align: center; }
  .lh-legal-links { justify-content: center; }
}
@media (max-width: 560px) {
  .lh-footer-grid { grid-template-columns: 1fr; }
}

/* =========================================================
   MOTION PACING (Larkhaven-only)
   Reveals here read as faster than the four sibling themes on the
   byte-identical shared core/assets/css/motion.css, so this theme runs
   every shared duration at 1.2x. --fw-motion-base is the theme-level
   multiplier motion.css folds into all of its timings, alongside the
   client-facing --fw-motion-speed from the Motion settings tab.
========================================================= */
:root { --fw-motion-base: 1.2; }

/* =========================================================
   AGE GATE + DEMO BAR
   Both moved to forwineries-theme-core: core/assets/css/age-gate.css
   (AgeGate::render() already emits unprefixed .fw-age-gate* markup) and
   core/assets/css/demo-bar.css (DemoBar::render() likewise). Nothing
   Larkhaven-specific was left behind -- both were already byte-
   identical (modulo prefix) with the other 4 sibling themes before
   this migration.
========================================================= */
