/*
Theme Name: El-Za Divi Child
Template: Divi
Version: 1.0.0
*/

:root {
  --el-bg: #F8F5EF;
  --el-bg-alt: #FBF8F2;
  --el-fg: #25271f;
  --el-primary: #292d24;
  --el-primary-alt: #20231d;
  --el-secondary: #F3DFC6;
  --el-accent: #DCB57E;
  --el-olive: #999572;
  --el-olive-dark: #8b8967;
  --el-terracotta: #9a725d;
  --el-taupe: #D9C8B7;
  --el-taupe-dark: #6f6c52;
  --el-product-bg: #E9DDCA;
  --el-destructive: #a4433e;
  --el-muted-fg: #6d6b62;
  --el-ease: cubic-bezier(0.23, 1, 0.32, 1);
}

/* Task 16 fix: this project's real footer is a custom Divi section built by
   class-footer-content.php and appended directly into every page's own
   post_content (per this project's CLAUDE.md rule against the Divi 5
   Theme Builder for global footers -- see that file's docblock). Divi's
   own theme-level footer.php ("#main-footer", containing "#footer-widgets"
   and "#footer-bottom") is never actually replaced by that approach, only
   supplemented -- it keeps rendering unconditionally below the real
   footer on every single page, showing generic leftover content (default
   Archives/Categories widgets, placeholder "#"-linked social icons, and a
   "Designed by Elegant Themes | Powered by WordPress" credit line) with
   no equivalent anywhere in the source Node app. Never caught by any
   earlier task's verification because those all rendered saved
   post_content directly (file:// or raw shortcode output), which never
   executes footer.php at all -- only surfaced once Task 16 walked the
   pages through a real HTTP request in a real browser. `display: none`
   here purely hides the markup; `wp_footer()` (tracking hooks, WooCommerce
   cart-fragments script, etc.) fires from a separate `<?php wp_footer(); ?>`
   call outside `#main-footer` in Divi/footer.php, so this has zero effect
   on any script/hook execution. */
#main-footer { display: none !important; }

/* Task 16 fix (sitewide, discovered via real-browser measurement, not just
   the 4 rows the plan named): every two-column flex row in this theme
   resets `.et_pb_column { padding: 0; }` but never reset `margin` too.
   Divi's own forced-enqueued style-static.min.css carries
   `@media(min-width:981px){.et_pb_gutters3 .et_block_row .et_pb_column,
   .et_pb_gutters3.et_block_row.et_pb_row>.et_pb_column{margin-right:5.5%}}`
   -- (0,3,0) specificity, only active at real desktop widths (981px+, ONE
   pixel above this project's own 980px breakpoint, which is why it was
   invisible at exactly 980px in every prior task's verification and only
   surfaced now via real getBoundingClientRect() measurement at 1024/1440).
   It beats every row-scoped `.my-row .et_pb_column{padding:0}` reset here
   ((0,2,0), lower specificity) on the row's non-last column (Divi exempts
   `.et-last-child` from its own gutter rule already, which is why only
   ONE column in each pair ever showed the extra space). Net effect: an
   unaccounted-for ~5.5%-of-row-width margin stacked on top of this
   project's own explicit flex `gap`, pushing the last column's right edge
   past the row's own right edge by exactly that amount at every desktop
   width above 980px -- silently absorbed by section padding on some rows
   (no visible defect) but a real, measurable overflow on others (see
   task-16-report.md for the specific rows/pixel amounts). Divi's
   margin-based gutter model is legacy cruft this project's flex+gap rows
   never wanted in the first place; `!important` matches this project's
   established pattern (divi5-syntax-reference.md's Task 8 addendum) for
   beating specificity from the forced-enqueued static CSS. Every one of
   this file's 14 row-scoped `.my-row .et_pb_column { padding: 0; }` rules
   below now reads `{ padding: 0; margin: 0 !important; }` -- harmless on
   the handful of single-column rows among them (their one child is
   already both first and last, so Divi's own rule already exempts it;
   the addition is a no-op there, not a behaviour change). Deliberately
   NOT hoisted into one unscoped `.et_pb_column{...}` rule -- keeping the
   fix scoped per-row matches this file's established convention and
   avoids touching any column this task didn't actually verify. */

.et_pb_row { width: 80%; margin: auto; }

/* ==========================================================================
   Task 18 -- GLOBAL RESET LAYER (2026-09-24)

   This block exists because of the load-order change documented in
   functions.php's elza_enqueue_parent_style() docblock: this stylesheet is
   now printed from wp_head at priority 200, i.e. AFTER Divi's
   force-enqueued style-static.min.css AND after Divi's per-page
   `et-core-unified-*` global inline block. Both of those carry bare
   single-class Divi defaults at the SAME specificity as this theme's own
   rules, and used to win purely on source order.

   Consequence for anything written below this line: a plain, single-class
   `.elza-*` rule now beats Divi's matching default WITHOUT needing
   `!important`. New rules should follow that pattern -- do NOT add fresh
   one-off `!important` overrides for Divi defaults; they are no longer
   required, and they only make the cascade harder to reason about.

   `!important` is still genuinely required in exactly two situations, both
   already used below and both deliberately left alone:
     1. Beating Divi's `<style class="et-vb-global-data et-vb-global-fonts">`
        block, which Divi prints AFTER everything else (it carries
        `body{line-height:var(--et_global_body_font_height);
        font-size:var(--et_global_body_font_size)}`, with those variables
        resolving to Divi's own 1.7em / 14px defaults). Nothing printed in
        <head> can beat it on source order.
     2. Beating a rule that already carries `!important`, where specificity
        is compared first and source order is only the tie-breaker.

   THE RESET ITSELF -- Divi ships `.et_pb_section { padding: 4% 0 }`
   (specificity 0,1,0). Measured before the load-order fix: every single
   `.et_pb_section` on this site computed `padding: 54px 0px`, so not one of
   this file's ~25 section-padding rules was actually in effect. Six of this
   build's sections legitimately want NO section padding at all (they are
   full-bleed: the Home/Shop/Story heroes, the dark split banner, Story's
   founder + philosophy splits, Contact's form split) and therefore never
   declared `padding` -- for those, source order alone can't help, because
   there is no competing declaration to win with. One neutral reset rule
   here gives them the `padding: 0` the source app has, while every
   `.elza-*` section rule further down this file (all later in source order,
   all equal specificity) still overrides it with its own real padding.
   ========================================================================== */
.et_pb_section { padding: 0; }
/* Divi also ships `.et_pb_row { padding: 2% 0 }` -- measured 27px top and
   bottom on every row on the site. The source app puts ALL vertical rhythm on
   its sections (`py-*` utilities) and none on the inner containers, so this
   27px was pure additive drift on every single row. Same reset treatment;
   the handful of rows here that genuinely want their own padding
   (.elza-hero-content-row, .elza-shop-hero-content-row) declare it later in
   this file and still win on source order. */
.et_pb_row { padding: 0; }

/* Divi stamps `et_pb_text_align_left` onto EVERY text module that doesn't
   explicitly ask for another alignment, and style-static.min.css backs it
   with `.et_pb_module.et_pb_text_align_left { text-align: left }` --
   specificity (0,2,0), and, crucially, a DIRECT match on the module element
   itself. A `text-align: center` declared on the section (0,1,0) can never
   reach through it, because an inherited value always loses to a direct
   match on the element regardless of the ancestor selector's specificity.

   Measured consequence before this fix: every deliberately centred block on
   the site was rendering LEFT-aligned -- Home's closing CTA, Shop's closing
   band, Our Story's "Confident." statement and its roles intro, and the
   whole Contact hero. Five sections, on four of the five pages. Invisible to
   any check that compares element bounding boxes (a block-level h2 fills its
   container either way); caught by comparing the per-line client rects of an
   inline accent span against the live app, which showed the last line
   flush-left here and centred there.

   Each override below is (0,2,0) -- equal to Divi's rule, and this
   stylesheet now loads later, so it wins on source order with no
   `!important` needed (see the Task 18 reset-layer note above). Scoped to
   exactly the blocks the source centres; Our Story's roles GRID is
   deliberately excluded, since Story.tsx centres only the intro Reveal
   (`mx-auto max-w-5xl text-center`) and leaves the six role cards
   left-aligned. */
.elza-closing-cta-section .et_pb_module,
.elza-shop-closing-section .et_pb_module,
.elza-story-confident-section .et_pb_module,
.et_pb_module.elza-story-roles-intro,
.elza-contact-hero .et_pb_module { text-align: center; }

/* `font-size` / `line-height` carry `!important` for reason (1) above -- the
   et-vb-global-fonts block is printed after this stylesheet and forces
   Divi's 14px / 1.7em onto `body`, and Divi's static sheet separately sets
   `.et_pb_text{line-height:var(--et_global_body_font_height,1.7em)}`.
   Measured before this fix: `.et_pb_text` computed 28.9px (1.7) against the
   source app's 27.54px (1.62) -- the ~5% body line-height drift seen
   sitewide. Everything else in this rule now wins on source order alone.
   `font-weight: 400` is new (Task 18): Divi's static sheet sets
   `body{font-weight:500}` and this rule previously declared no font-weight
   at all, so there was nothing to win the cascade with -- measured, `body`
   computed weight 500 against the source app's 400, subtly bolding every
   paragraph, marquee item and product-card description on the site.
   Source of truth: elza-website/client/src/index.css's
   `body { font-size: 17px; line-height: 1.62 }`, which sets no font-weight
   (i.e. the initial value, 400). */
body, .et_pb_text, .et-l { font-family: 'Raleway', sans-serif; font-size: 17px !important; line-height: 1.62 !important; font-weight: 400; color: var(--el-fg); }
/* Task 18: `.et_pb_button` removed from this Jost/500 list. The source app's
   Button component (elza-website/client/src/components/ui/button.tsx) sets
   `text-[14px] font-semibold uppercase tracking-[0.14em]` and NO font-family
   class at all -- so buttons inherit the body font, which index.css defines
   as `--font-sans: "Bodoni Moda", serif`. Measured on the live app: every
   button renders Bodoni Moda 14px/600. This theme was rendering them Jost
   500, i.e. the wrong family AND the wrong weight. See `.et_pb_button`
   below for the replacement rule. */
.font-display, h1, h2, h3, h4, h5, h6 { font-family: 'Jost', sans-serif; font-weight: 500; }
/* Phase 3 fix (Table A #1) -- final version after two rounds of real-browser
   CDP verification found this needs THREE things together, not one:

   1. Divi 5 generates its own per-page "dynamic CSS" <style> block with the
      LITERAL SAME selector text as a base rule this theme already had --
      `h1, h2, h3, h4, h5, h6` -- setting color:#333. Confirmed via CDP
      (document.styleSheets walk): both rules exist, identical selector,
      identical specificity (0,0,1), neither !important. At equal
      specificity the LATER rule in document order wins, and Divi's inline
      block lands after this linked stylesheet in <head> -- so without
      !important, Divi's #333 always won regardless of what this rule said.
      This is the exact same "Divi's own late-loading CSS beats child-theme
      rules at equal specificity" class of gotcha this project has already
      hit and fixed with !important elsewhere (see divi5-syntax-reference.md);
      apply the same fix here.

   2. Headings have their OWN direct color rule (the one right below), so
      simply fixing inheritance further up the tree (item 3) can never reach
      them -- a direct match on the element always wins over any inherited
      value, no matter what that inherited value resolves to. Headings
      inside dark sections need their own more-specific, equally-!important
      override back to `inherit`.

   3. Separately, the pre-existing `body, .et_pb_text, .et-l {...color:
      var(--el-fg)}` rule at the top of this file unconditionally forces
      --el-fg onto every .et_pb_text MODULE WRAPPER regardless of light/dark
      section context. This doesn't affect headings directly (see #2) but
      DOES affect any non-heading text (paragraphs, spans) inside a dark
      section's text module, which has no direct rule of its own and so
      really does inherit from .et_pb_text. Needs the same inherit-with-
      !important treatment, scoped to dark sections, so paragraph text in
      those sections is correct too -- not just headings. */
h1, h2, h3, h4, h5, h6 { color: var(--el-fg) !important; }
.elza-home-hero h1, .elza-home-hero h2, .elza-home-hero h3, .elza-home-hero h4, .elza-home-hero h5, .elza-home-hero h6,
.elza-dark-banner-section h1, .elza-dark-banner-section h2, .elza-dark-banner-section h3, .elza-dark-banner-section h4, .elza-dark-banner-section h5, .elza-dark-banner-section h6,
.elza-shop-hero h1, .elza-shop-hero h2, .elza-shop-hero h3, .elza-shop-hero h4, .elza-shop-hero h5, .elza-shop-hero h6,
.elza-story-hero h1, .elza-story-hero h2, .elza-story-hero h3, .elza-story-hero h4, .elza-story-hero h5, .elza-story-hero h6,
.elza-story-roles-section h1, .elza-story-roles-section h2, .elza-story-roles-section h3, .elza-story-roles-section h4, .elza-story-roles-section h5, .elza-story-roles-section h6,
.elza-story-promise-section h1, .elza-story-promise-section h2, .elza-story-promise-section h3, .elza-story-promise-section h4, .elza-story-promise-section h5, .elza-story-promise-section h6,
.elza-footer-section h1, .elza-footer-section h2, .elza-footer-section h3, .elza-footer-section h4, .elza-footer-section h5, .elza-footer-section h6
{ color: inherit !important; }
.elza-home-hero .et_pb_text,
.elza-dark-banner-section .et_pb_text,
.elza-shop-hero .et_pb_text,
.elza-story-hero .et_pb_text,
.elza-story-roles-section .et_pb_text,
.elza-story-promise-section .et_pb_text,
.elza-footer-section .et_pb_text
{ color: inherit !important; }
.font-editorial { font-family: 'Raleway', sans-serif; font-style: italic; font-weight: 400; }

.et_pb_button, .et_pb_module, input, textarea, select, img {
  border-radius: 0 !important;
}

/* Task 18: real button typography + box, transcribed from the source app's
   Button component (elza-website/client/src/components/ui/button.tsx).
   Its base class list is:
     inline-flex shrink-0 items-center justify-center gap-3 whitespace-nowrap
     rounded-none border text-[14px] font-semibold uppercase
     tracking-[0.14em] transition-... duration-200
   with NO font-family class, so buttons inherit index.css's
   `--font-sans: "Bodoni Moda", serif` -- NOT the display font. Measured on
   the live app at :8600, every button computes Bodoni Moda / 14px / 600 /
   uppercase / 1.96px tracking. This theme previously listed `.et_pb_button`
   alongside `h1-h6` in the Jost/500 rule near the top of this file and
   declared no size of its own, so Divi's `.et_pb_button{font-size:20px;
   padding:.3em 1em}` supplied the box -- measured result was Jost / 20px /
   500 / no uppercase / normal tracking, i.e. wrong on five properties at
   once, on every CTA on the site.
   Sizes come from the component's `size` variants: default `h-12 px-6`
   (48px tall, 24px side padding), `lg` `h-14 px-8` (56px / 32px). `lg` is
   opt-in here via `.elza-btn-lg` (applied by class-page-home.php only on
   the three buttons the source renders with size="lg"). `gap-3` = .75rem
   is the space between label and the `.elza-btn-arrow` ::after glyph.
   No `!important` needed on any of this: per the Task 18 reset-layer note
   above, this stylesheet now loads after Divi's own sheets. */
.et_pb_button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .75rem;
  white-space: nowrap;
  box-sizing: border-box;
  height: 48px;
  padding: 0 1.5rem;
  border: 1px solid transparent;
  font-family: 'Raleway', sans-serif;
  font-size: 14px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: .14em;
  text-transform: uppercase;
  text-decoration: none;
  /* Divi's static sheet declares `.et_pb_button{line-height:1.7em!important}`
     -- the one property on this element that source order cannot beat, so it
     needs `!important` here. Source buttons set no line-height at all and so
     inherit index.css's body 1.62. */
  line-height: 1.62 !important;
  transition: transform 200ms, background-color 200ms, color 200ms, border-color 200ms;
}
.elza-btn-lg { height: 56px; padding: 0 2rem; }

/* `--primary-foreground` in index.css is #fbf8f2, a warm off-white -- not
   pure #fff (Task 18 correction; the two are visibly different against this
   palette's dark greens). */
.elza-btn-primary {
  background: var(--el-primary) !important;
  color: var(--el-bg-alt) !important;
  border-color: var(--el-primary) !important;
}
.elza-btn-primary:hover { background: var(--el-olive) !important; border-color: var(--el-olive) !important; }
/* Source: `border-foreground/25 bg-transparent text-foreground`. The border
   was previously `currentColor`, i.e. FULL opacity -- measurably heavier
   than the source's 25% on light sections, and pure white rather than the
   source's 55%/40% white on the two dark sections that override it (see the
   scoped rules next to `.elza-home-hero` / `.elza-dark-banner-section`
   below). `color: inherit` is kept: on a light section it resolves to the
   inherited body colour (#25271f = the source's `text-foreground`) and on a
   dark section to that section's own white, which is exactly what the two
   source call-sites ask for. */
.elza-btn-outline {
  background: transparent !important;
  border: 1px solid rgba(37,39,31,.25) !important;
  color: inherit !important;
}
.elza-btn-outline:hover { background: var(--el-fg) !important; border-color: var(--el-fg) !important; color: var(--el-bg) !important; }
.elza-cta-text, .elza-cta-text * {
  color: #fff !important;
}
.elza-eyebrow {
  font-family: 'Jost', sans-serif;
  font-size: 14px;
  font-weight: 500;
  letter-spacing: .22em;
  text-transform: uppercase;
}

/* Final-review fix (Important, 2026-09-23 -- client's explicit top
   priority, "make sure it looks exactly the same"): scroll-reveal motion
   per the design spec's §4 "Motion" (fade-in + slide-up from 22px, 0.55s,
   the same `--el-ease` cubic-bezier already defined above, triggers once at
   18% visible) -- specified but never implemented anywhere on this branch.
   `.is-visible` is toggled by js/scroll-reveal.js (IntersectionObserver,
   fires once, stagger via inline `transition-delay`). Reuses `--el-ease`
   (defined in :root above) rather than a second easing token, since it's
   already the exact cubic-bezier(0.23, 1, 0.32, 1) the spec calls for.

   Third-review fix (Important, 2026-09-23): the hidden state used to be a
   bare, unconditional `.elza-reveal { opacity: 0 }` -- meaning content
   stayed invisible forever unless js/scroll-reveal.js specifically
   succeeded (a <noscript> fallback covered "JS entirely off" but not "JS
   is on, this one script 404s/fails"). Now class-gated: the hidden state
   only applies once `html.elza-reveal-js` is present, a class the script
   adds as its own very first, unthrowable action -- so elements are
   VISIBLE BY DEFAULT and only become hidden once the script has proven
   it's actually running. `.is-visible` is scoped to the same
   `html.elza-reveal-js` ancestor and carries one more class than the
   hidden-state rule (0,3,1 vs 0,2,1) specifically so it always wins on
   specificity, not just on source order -- guarantees the reveal-complete
   state beats the hidden state even if this file's rule order ever
   changes. */
.elza-reveal { transition: opacity .55s var(--el-ease), transform .55s var(--el-ease); }
html.elza-reveal-js .elza-reveal { opacity: 0; transform: translateY(22px); }
html.elza-reveal-js .elza-reveal.is-visible { opacity: 1; transform: none; }

/* Second-review fix (Important, 2026-09-23): respect the OS-level "reduce
   motion" preference -- users who have JS enabled (so the <noscript>
   fallback in header.php doesn't apply) but have explicitly turned off
   animations at the system level should see content immediately, not a
   0.55s slide/fade. Neutralizes both the hidden starting state and the
   transition itself, so `.elza-reveal` elements render exactly as if
   `.is-visible` were already present, with no animation at any point.
   `!important` (third-review fix, 2026-09-23): needed now that the
   hidden-state rule above is scoped to `html.elza-reveal-js` -- that
   selector's specificity (0,2,1) otherwise beats this bare `.elza-reveal`
   rule (0,1,0), which would let JS re-hide a reduced-motion visitor's
   content the instant `elza-reveal-js` gets added to <html>. */
@media (prefers-reduced-motion: reduce) {
  .elza-reveal { opacity: 1 !important; transform: none !important; transition: none !important; }
}

/* Fourth-review fix (CRITICAL, 2026-09-23): neutralise Divi's own legacy
   waypoint/reveal mechanism sitewide. Round 3 put this exact declaration in
   header.php's <noscript> block, believing the only broken case was "JS
   disabled"; that was wrong. It is broken for EVERY visitor, including (in
   fact, especially) visitors with JS fully enabled and working. Proven with
   real headless Chromium against a real HTTP render, with the real
   photographs actually loaded (naturalWidth/naturalHeight both non-zero, not
   a 404 placeholder): 7 et_pb_image modules across 3 pages computed
   `opacity: 0` forever -- elza-hero-bg-image / elza-intro-image /
   elza-banner-image (Home), elza-shop-hero-bg-image (Shop),
   elza-story-hero-bg-image / elza-story-founder-image /
   elza-story-philosophy-image (Our Story). Home's hero photograph, the
   single biggest thing on the site, was genuinely invisible in production.

   Root cause (NOT a JS failure -- Divi's JS works fine here): gotcha #2 makes
   this child theme force-enqueue Divi's legacy `style-static.min.css` (see
   elza_force_static_css() in functions.php) to restore the Divi 5 column
   grid. That stylesheet hides every waypoint element with
   `.et-waypoint:not(.et_pb_counters){opacity:0}`, and EVERY rule that ever
   puts it back to `opacity:1` needs an `et_pb_animation_*` direction class
   as well as `et-waypoint`:
       .et-waypoint.et_pb_animation_left.et-animated   {opacity:1; animation:fadeLeft ...}
       .et-waypoint.et_pb_animation_fade_in.et-animated {opacity:1; animation:fadeIn ...}
       .et-waypoint.et_pb_animation_off                 {opacity:1}
       ... (left/right/top/bottom/fade_in x desktop/_tablet/_phone, plus _off)
   There is no `.et-waypoint.et-animated{opacity:1}` rule -- the animation
   class is load-bearing, not decorative. Our image modules render as
   `et_pb_module et_d4_element et_pb_image et_pb_image_N <our-class>
   et-waypoint et-animated` with NO `et_pb_animation_*` class at all, so the
   combination never matches anything and the element stays at opacity 0
   permanently. Divi's own frontend JS does its half correctly (measured:
   3/3 waypoints on Home, 1/1 on Shop, 3/3 on Our Story all receive
   `et-animated` on scroll) -- it is the CSS side that can never resolve.

   Why an unconditional override rather than emitting a real animation class
   on the modules: `et_pb_animation_off` (the one class that resolves without
   `et-animated`) appears in ZERO Divi PHP files and ZERO Divi JS files --
   it survives only as a selector inside style-static.min.css, a D3/D4-era
   leftover Divi itself never emits, so depending on it means depending on an
   undocumented internal that any Divi update can drop. It would also mean
   rewriting every image shortcode in page post_content, i.e. a full
   elza_setup_run_all() re-run, which this branch has already had bite it
   once (the Round-1 nav-menu duplication). A stylesheet rule needs neither.

   Neutralising Divi's waypoint reveal outright costs this build nothing:
   all reveal motion here is owned by `.elza-reveal` + js/scroll-reveal.js
   above, which is the design spec's actual motion (22px slide-up, 0.55s,
   --el-ease, staggered), and none of these modules asked for a Divi
   animation in the first place. Measured on this branch: 0 elements
   sitewide carry an `et_pb_animation_*` class, so no working Divi animation
   exists for this rule to flatten.

   `!important` is required, not defensive: elza_force_static_css() prints
   style-static.min.css from `wp_head` at priority 99, i.e. AFTER this
   stylesheet's own <link>, so Divi's `.et-waypoint:not(.et_pb_counters)`
   (specificity 0,2,0) would otherwise beat an identical-specificity rule
   here purely on source order. The `:not(.et_pb_counters)` is carried over
   verbatim from Divi's own selector so bar-counter modules keep Divi's
   intended behaviour untouched.

   This rule is unconditional ON PURPOSE. Round 3's <noscript>-scoped copy
   could only ever fire when JS was off, which is the rare case; the common
   case is a normal visitor with working JS, and they saw nothing. The
   <noscript> copy has been removed (see header.php) so there is exactly one
   place this behaviour is defined. */
.et-waypoint:not(.et_pb_counters) { opacity: 1 !important; }

/* Task 8: header (marquee + nav + order bag) */
.elza-marquee { overflow: hidden; white-space: nowrap; background: #252820; color: #fff; border-bottom: 1px solid rgba(255,255,255,.1); padding: 8px 0; }
.elza-marquee--overlay { background: rgba(0,0,0,.55); border-bottom-color: rgba(255,255,255,.2); }
.elza-marquee-track { display: inline-flex; animation: elza-marquee 34s linear infinite; }
/* Task 18: transcribed verbatim from elza-website/client/src/index.css's
   `.brand-marquee-item` + `.brand-marquee-item::after`. The ::after ellipse
   (the little "crochet ring" separator between marquee phrases) was missing
   entirely -- measured, computed `content` was `none` -- so every item also
   rendered ~44px narrower than the source's. Deliberately NO font-weight:
   `.brand-marquee-item` is the one Jost rule in the source that declares
   none, so it correctly inherits the body's 400. */
.elza-marquee-item { display: flex; align-items: center; gap: 1.6rem; font-family: 'Jost', sans-serif; font-size: 11px; letter-spacing: .22em; text-transform: uppercase; padding-right: 1.6rem; }
.elza-marquee-item::after { width: 18px; height: 8px; content: ""; border: 1px solid currentColor; border-radius: 50%; opacity: .65; transform: rotate(-18deg); flex-shrink: 0; }
@keyframes elza-marquee { to { transform: translateX(-50%); } }

/* Final-review fix (Critical, 2026-09-23): explicit `grid-column` on every
   one of the header's 4 real children (menu trigger / logo / nav /
   order-bag) -- see header.php's own docblock for the full root-cause
   writeup (3-track grid for 4 children, zero responsive behaviour, a dead
   `.elza-menu-trigger` with no CSS/JS at all). Deliberately explicit
   per-child `grid-column` rather than relying on grid auto-placement: with
   `.elza-nav` (mobile) or `.elza-menu-trigger` (desktop) `display:none` at
   any given width, auto-placement would silently reflow every remaining
   item leftward into the vacated slot instead of leaving it empty, which
   would misplace the order-bag icon at exactly the breakpoint boundary. */
.elza-header { position: sticky; top: 0; z-index: 50; display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; height: 96px; padding: 0 20px; }
.elza-header--solid { background: rgba(248,245,239,.95); border-bottom: 1px solid rgba(37,39,31,.12); }
.elza-header--transparent { position: absolute; inset-inline: 0; background: linear-gradient(to bottom, rgba(0,0,0,.25), transparent); color: #fff; }
.elza-menu-trigger { grid-column: 1; grid-row: 1; justify-self: start; display: grid; place-items: center; width: 44px; height: 44px; border: 1px solid currentColor; background: none; color: inherit; font-size: 1.15rem; line-height: 1; cursor: pointer; }
.elza-logo { grid-column: 2; grid-row: 1; }
.elza-logo img { width: 158px; height: auto; }
.elza-nav { grid-column: 2; grid-row: 1; display: none; gap: 36px; justify-content: center; list-style: none; margin: 0; padding: 0; }
.elza-nav li { list-style: none; }
/* Task 18: SiteShell.tsx wraps the label + cart button in
   `<div className="col-start-3 flex items-center justify-end gap-5">`, with
   the label itself `hidden ... xl:inline` (Tailwind xl = 1280px). That label
   was missing from this header entirely; `.elza-header-actions` is the new
   wrapper that owns grid column 3 so the two sit side by side with the
   source's 20px gap. */
.elza-header-actions { grid-column: 3; grid-row: 1; display: flex; align-items: center; justify-content: flex-end; gap: 1.25rem; }
.elza-order-bag-label { display: none; font-family: 'Jost', sans-serif; font-size: 13px; font-weight: 500; letter-spacing: .14em; text-transform: uppercase; }
@media (min-width: 1280px) { .elza-order-bag-label { display: inline; } }
.elza-order-bag { position: relative; display: grid; place-items: center; width: 44px; height: 44px; border: 1px solid currentColor; flex-shrink: 0; }
.elza-order-bag-count { position: absolute; top: -4px; right: -4px; display: grid; place-items: center; width: 20px; height: 20px; border-radius: 50%; background: var(--el-olive); color: #fff; font-size: 11px; }

/* Responsive show/hide, matching the source app's `lg:` (1024px) breakpoint
   (elza-website/client/src/components/SiteShell.tsx: `lg:hidden` on the
   mobile trigger, `hidden ... lg:flex` on the desktop nav). Below 1024px:
   trigger (col 1) + logo (col 2, centered between two `1fr` tracks) +
   order-bag (col 3, `justify-self:end`) -- `.elza-nav` is `display:none`
   so it never participates in the grid. At/above 1024px the trigger is
   hidden and the grid switches to `auto 1fr auto` (logo / centered nav /
   order-bag), the same shape the source swaps to at its own `lg:` variant. */
@media (min-width: 1024px) {
  .elza-menu-trigger { display: none; }
  .elza-header { grid-template-columns: auto 1fr auto; padding-left: 40px; padding-right: 40px; }
  .elza-logo { grid-column: 1; }
  .elza-nav { grid-column: 2; display: flex; }
  .elza-header-actions { grid-column: 3; }
}

/* Mobile slide-in nav panel (below 1024px only) -- `.elza-menu-trigger`
   above toggles this via js/mobile-nav.js, reusing the exact same drawer
   pattern already shipped for the order-bag drawer (`.is-open` class,
   translateX transition, js/order-bag-drawer.js) rather than inventing a
   new one. */
.elza-mobile-nav {
  position: fixed; top: 0; left: 0; bottom: 0; width: 100%; max-width: 22rem;
  background: var(--el-bg-alt); padding: 2rem 1.75rem; overflow-y: auto;
  transform: translateX(-100%); transition: transform 320ms var(--el-ease);
  z-index: 100;
}
.elza-mobile-nav.is-open { transform: translateX(0); }
@media (min-width: 1024px) { .elza-mobile-nav { display: none; } }
.elza-mobile-nav-close { position: absolute; top: 1.5rem; right: 1.5rem; width: 2.5rem; height: 2.5rem; display: grid; place-items: center; font-size: 1.5rem; line-height: 1; background: none; border: 1px solid rgba(37,39,31,.18); cursor: pointer; }
.elza-mobile-nav-logo { display: inline-flex; background: var(--el-secondary); padding: .6rem; margin-bottom: 3.5rem; }
.elza-mobile-nav-logo img { width: 130px; height: auto; display: block; }
.elza-mobile-nav-list { display: flex; flex-direction: column; gap: 1.75rem; list-style: none; margin: 0; padding: 0; }
.elza-mobile-nav-list li { list-style: none; }
.elza-mobile-nav-list .elza-nav-link { font-size: 2rem; letter-spacing: normal; text-transform: none; }

/* Phase 3 fix (Table A #2): source's own .nav-link never sets color either
   -- it deliberately inherits the header's current text color (white on
   the transparent home hero, dark ink on the solid sticky header), which
   is the correct behaviour. Divi's default link blue was winning only
   because this rule never stated an explicit `color: inherit`. */
.elza-nav-link { font-family: 'Jost', sans-serif; font-size: 14px; letter-spacing: .14em; text-transform: uppercase; color: inherit; font-weight: 500; }

/* Task 8: footer content (Elza_Setup_Footer::get_shortcode()) */
/* Task 16 fix: found via Step 6's real side-by-side visual diff against the
   live Node app -- the whole footer (all 3 bands, every page site-wide)
   was rendering with a WHITE background instead of this dark one, making
   the light-coloured "Modern made by hand. Made for you." text (and the
   rest of the footer's light text) nearly illegible. Root cause: Divi's
   own forced-enqueued style-static.min.css carries a bare
   `.et_pb_section{background-color:rgb(255,255,255);...}` rule -- equal
   (0,1,0) specificity to this single-class selector, but loaded LATER
   (force-enqueued at wp_head priority 99, per this theme's Phase-1 rule,
   vs this stylesheet's default priority-10 enqueue), so it won on source
   order. Same documented mechanism as CLAUDE.md's Divi 5 gotcha #4 and
   this file's own `.elza-cta-text` rule (Task 3) -- `!important` is
   required on any single-class override of Divi's own per-module default
   styling once static.min.css is force-enqueued. This rule was the one
   place in the file where that established pattern was missed. */
.elza-footer-section { background-color: var(--el-primary-alt) !important; }
.elza-footer-section .et_pb_text,
.elza-footer-section .et_pb_text * { color: var(--el-bg); }

/* Task 18 -- footer row widths + responsive padding.
   All three footer rows were the only rows on the site carrying NO
   module_class (now fixed in class-footer-content.php), so each inherited
   Divi's `.et_pb_row:not([class*=et_flex_column]){width:80%;max-width:1080px}`
   and measured 1080px wide, centred, against the source app's full-bleed
   1425px. Same `width/max-width !important` pattern every other row on this
   site already uses (see .elza-trust-row, .elza-closing-row, etc. -- the
   !important is required because Divi's `:not()` selector is (0,2,0), which
   beats a single-class rule on specificity regardless of load order).
   Padding steps transcribed from SiteShell.tsx's Footer():
     band 1: px-6 py-16  md:px-12  lg:px-16 lg:py-20
     band 2: px-6 py-14  md:px-12  lg:px-16 lg:py-18   (gap-12)
     band 3: px-6 py-5   md:px-12  lg:px-16
   -- md = 768px and lg = 1024px, Tailwind's real defaults (Task 18 item 2). */
.elza-footer-band1-row,
.elza-footer-band2-row,
.elza-footer-band3-row { width: 100% !important; max-width: none !important; margin: 0; }

.elza-footer-band1 { border-bottom: 1px solid rgba(255,255,255,.12); padding: 48px 24px; }
@media (min-width: 768px) { .elza-footer-band1 { padding-left: 48px; padding-right: 48px; } }
@media (min-width: 1024px) { .elza-footer-band1 { padding: 64px 64px; } }
.elza-footer-eyebrow { color: var(--el-accent) !important; }
.elza-footer-heading { margin-top: 20px; }
.elza-footer-heading h2 { font-size: clamp(3rem, 6vw, 6.8rem); line-height: .92; margin: 0; max-width: 64rem; }
.elza-footer-heading .font-editorial { color: var(--el-secondary) !important; }

.elza-footer-band2 { padding: 44px 24px; }
@media (min-width: 768px) { .elza-footer-band2 { padding-left: 48px; padding-right: 48px; } }
@media (min-width: 1024px) { .elza-footer-band2 { padding: 56px 64px; } }
/* Real `gap: 3rem` (source's `gap-12`) instead of the previous
   `padding: 0 16px` + `margin-bottom: 32px` gutter approximation, which
   produced 32px between columns instead of 48px and also inset the first and
   last columns by 16px against the section padding. */
.elza-footer-band2 .et_pb_row { display: flex; flex-wrap: wrap; gap: 3rem; }
.elza-footer-band2 .et_pb_column { padding: 0; margin: 0 !important; box-sizing: border-box; }
/* Asymmetric 4-column widths matching SiteShell.tsx's
   grid-cols-[1.35fr_.65fr_.75fr_.75fr] (col 1 ~double col 2/3/4), normalized
   to percentages of the 3.5fr total (1.35+.65+.75+.75). Set directly here
   rather than via Divi's own type="X_Y" column-width CSS: confirmed via
   wp eval that classic-shortcode-rendered rows/columns only ever get the
   generic et_block_row / et_pb_column_1_4 classes, never the
   et_pb_gutters{N} or VB-only et_block_row_{structure} classes that Divi's
   static CSS actually scopes its width percentages to -- so none of Divi's
   built-in fraction widths (equal or asymmetric) are reliably wired up for
   this backward-compat shortcode path without a real page load to confirm
   the per-page dynamic CSS. !important guarantees this wins regardless. */
/* Column widths now subtract the row's own 3rem gap, the same precise
   calc() pattern every other multi-column row in this file uses. fr shares
   are SiteShell.tsx's `lg:grid-cols-[1.35fr_.65fr_.75fr_.75fr]` normalised
   over the 3.5fr total: .385714 / .185714 / .214286 / .214286, applied to
   the space left after three 3rem gaps. Breakpoints are Tailwind's real
   md=768 / lg=1024 (previously 767/980, Divi's legacy values). */
.elza-footer-band2 .et_pb_row > .et_pb_column { flex: 0 0 100% !important; max-width: 100% !important; }
@media (min-width: 768px) {
  .elza-footer-band2 .et_pb_row > .et_pb_column {
    flex: 0 0 calc((100% - 3rem) / 2) !important; max-width: calc((100% - 3rem) / 2) !important;
  }
}
@media (min-width: 1024px) {
  .elza-footer-band2 .et_pb_row > .et_pb_column:nth-child(1) { flex: 0 0 calc((100% - 9rem) * .385714) !important; max-width: calc((100% - 9rem) * .385714) !important; }
  .elza-footer-band2 .et_pb_row > .et_pb_column:nth-child(2) { flex: 0 0 calc((100% - 9rem) * .185714) !important; max-width: calc((100% - 9rem) * .185714) !important; }
  .elza-footer-band2 .et_pb_row > .et_pb_column:nth-child(3),
  .elza-footer-band2 .et_pb_row > .et_pb_column:nth-child(4) { flex: 0 0 calc((100% - 9rem) * .214286) !important; max-width: calc((100% - 9rem) * .214286) !important; }
}
/* Chip removal (2026-09-25, explicit client request -- "replace this [logo
   on a peach chip] with this [plain logo, no background]"): the peach
   `--el-secondary` background box made sense as a light backdrop for
   whatever the OLD logo asset needed, but the new gold/tan logo already
   reads cleanly directly against a dark background on its own -- confirmed
   by `.elza-logo` (header.php's desktop logo), which never had a chip
   background at all and was never flagged. Matches that same bare
   treatment here instead of inventing a new one. */
.elza-footer-logo-chip { display: inline-flex; }
.elza-footer-logo-chip img { width: 224px; height: auto; display: block; }
.elza-footer-col-text { margin-top: 24px; max-width: 24rem; color: rgba(248,245,239,.68) !important; }
.elza-footer-text { margin-top: 20px; color: rgba(248,245,239,.75) !important; }
.elza-footer-link-list { display: flex; flex-direction: column; gap: 12px; margin-top: 20px; }
/* `w-fit` in the source -- these were full-column-width block links here
   (measured 247px vs the source's 93px/78px), which made the whole hover
   target span the column. */
.elza-footer-link-list a { color: rgba(248,245,239,.75) !important; text-decoration: none; width: fit-content; }
.elza-footer-link-list a:hover { color: #fff !important; }

/* Social pass (2026-09-25): replaced the single text-labelled Instagram
   link with a horizontal row of 3 icon-only links (WhatsApp, Facebook,
   Instagram) -- see class-footer-content.php's docblock for the full
   context. Each link is its own small bordered square (matching this
   project's established icon-button treatment elsewhere, e.g.
   .elza-order-bag/.elza-menu-trigger in the header) rather than a bare
   icon, so the "#" placeholder hrefs still read as real, tappable social
   links even with no visible text. */
.elza-footer-social-icons { display: flex; gap: .75rem; margin-top: 20px; }
.elza-footer-social-link { display: grid; place-items: center; width: 40px; height: 40px; border: 1px solid rgba(248,245,239,.3); color: rgba(248,245,239,.75) !important; text-decoration: none; transition: border-color 200ms, color 200ms; }
.elza-footer-social-link:hover { border-color: #fff; color: #fff !important; }
.elza-footer-social-icon { width: 18px; height: 18px; flex-shrink: 0; }

.elza-footer-copyright { border-top: 1px solid rgba(255,255,255,.1); padding: 20px 24px; }
@media (min-width: 768px) { .elza-footer-copyright { padding-left: 48px; padding-right: 48px; } }
@media (min-width: 1024px) { .elza-footer-copyright { padding-left: 64px; padding-right: 64px; } }
.elza-footer-copyright .et_pb_text, .elza-footer-copyright .et_pb_text * { color: rgba(248,245,239,.48) !important; }
.elza-footer-copyright-inner { display: flex; flex-direction: column; gap: 8px; font-family: 'Jost', sans-serif; font-size: 12px; text-transform: uppercase; letter-spacing: .14em; font-weight: 500; }
@media (min-width: 768px) {
  .elza-footer-copyright-inner { flex-direction: row; align-items: center; justify-content: space-between; }
}

/* ==========================================================================
   Task 10: Home page (class-page-home.php)
   ========================================================================== */

/* --- Signature motifs (project-wide reusable, per design spec §4) ---
   Pulled verbatim from elza-website/client/src/index.css. */
.crochet-ring { width: 56px; height: 23px; border: 2px solid var(--el-accent); border-radius: 50%; transform: rotate(-16deg); box-shadow: 14px 4px 0 -9px transparent, 14px 4px 0 -7px var(--el-accent); }
.stitch-frame { position: relative; }
.stitch-frame::after { position: absolute; right: -1px; bottom: 22px; width: 92px; height: 28px; content: ""; background: repeating-radial-gradient(ellipse at center, transparent 0 7px, var(--el-olive) 8px 9px, transparent 10px 15px); opacity: .72; pointer-events: none; }
.editorial-image { position: relative; overflow: hidden; background: var(--el-product-bg); }
.editorial-image img { transition: transform 900ms var(--el-ease); }
.elza-card:hover .editorial-image img { transform: scale(1.025); }
.elza-card { position: relative; }
.elza-card::before { position: absolute; z-index: 2; top: 12px; right: -1px; bottom: 12px; width: 4px; content: ""; background: repeating-linear-gradient(to bottom, var(--el-olive) 0 7px, transparent 7px 13px); opacity: 0; transition: opacity 220ms var(--el-ease); pointer-events: none; }
.elza-card:hover::before { opacity: .85; }
/* Final-review fix (found during Fix 6/7's required real-Chromium overflow
   verification, 2026-09-23): this rule was missing `!important` on every
   property, the same dynamic-CSS-dropout category as CLAUDE.md's Divi 5
   gotcha #4/#5. Divi's own force-enqueued style-static.min.css carries a
   bare `.et_pb_button:after,.et_pb_button:before{...content:"5";opacity:0;
   position:absolute;...top:50%;transform:translateY(-50%)}` rule (equal
   (0,1,1) specificity to this single-class `::after` selector, but loaded
   LATER at wp_head priority 99) -- it was winning outright on `content`
   (showing Divi's icon-font glyph "5" instead of this rule's intended
   "\2192" arrow character) and winning by default on every property this
   rule didn't also declare (`position`, `opacity`, `top`, `transform`,
   `right`), since an undeclared property isn't a cascade conflict at all.
   Net effect: the arrow was `opacity:0` (invisible except on real
   `:hover`, which no static render captures) AND `position:absolute` with
   a computed `right:-31px` on any button flush against its row's right
   edge -- confirmed via getComputedStyle(btn,'::after') on
   `.elza-featured-header-row`'s "View all handbags" button, whose row sits
   exactly at the page's right edge, so that -31px bleed became ~30px of
   real, measurable `document.documentElement.scrollWidth` overflow
   (constant across viewport widths, confirming a fixed px/em offset, not a
   percentage-based row bug like `.elza-intro-row`/`.elza-story-intro-row`
   above). Fully overriding every property Divi's competing rule sets
   restores both the intended always-visible inline arrow (matching this
   project's other `elza-btn-*` buttons, all of which already carry
   `!important` per the same established gotcha #5 pattern) and eliminates
   the overflow. */
/* Correction (2026-09-23, second review pass): an earlier version of this
   fix added `.elza-btn-arrow { padding-right: .7em !important; }` here,
   reasoning that Divi's base `.et_pb_button` rule carried an asymmetric
   `padding-right:2em`/`padding-left:.7em` reserved for its own
   absolutely-positioned hover icon, now dead space once the icon renders
   inline. That reasoning was wrong -- re-checked directly against
   style-static.min.css: the ONLY rule whose selector list contains a bare,
   unqualified `.et_pb_button` (i.e. applies to every plain button on this
   site, not just ones carrying Divi's own `et_button_left`/
   `et_button_icon_visible` modifier classes) and sets padding is
   `.et_pb_button{font-size:20px;...padding:.3em 1em;...}` -- a SHORTHAND
   `padding` declaration, which sets all four longhand sides at once and so
   always wins over any earlier longhand-only `padding-left`/`padding-right`
   declaration at equal specificity, regardless of which specific em value
   that earlier longhand rule used. Real resolved padding for these buttons
   was therefore already `.3em 1em` = 6px/20px, SYMMETRIC left/right (1em
   resolves to 20px via that same rule's own `font-size:20px`) -- not the
   asymmetric 2em/.7em previously assumed. The `padding-right:.7em`
   override above was therefore removing 6px of real, correct button
   padding sitewide on every `elza-btn-arrow` button, for no actual reason.
   Reverted (deleted entirely) -- Divi's own already-correct symmetric
   padding needs no compensation now that the arrow itself renders inline
   via the ::after override below. The narrow-viewport overflow this was
   originally (mis-)diagnosed against was actually caused by
   `.elza-banner-copy-col` missing `flex-direction:column` (see that rule,
   ~line 513) -- once the copy column's children stack vertically instead
   of competing side-by-side, the button has its own full-width line and
   never needed a padding change at all. */
/* Task 18: the arrow is now a real 16px lucide `arrow-right` glyph rendered
   as a CSS mask, not the "\2192" text character. The source renders
   `<ArrowRight className="size-4" />` -- a 16x16 SVG -- separated from the
   label by the Button's own `gap-3` (12px). The text-character version was
   both a different shape and a different width, and its own `margin-left:.6em`
   stacked on top of the flex gap: measured, Home's "Discover our beginning"
   came out 276px wide against the source app's 316px. Using `mask` + a
   `currentColor` background keeps it inheriting the button's colour exactly
   as an inline SVG with `stroke="currentColor"` would.
   Every declaration keeps `!important` for the reason documented at length in
   the previous version of this block: Divi's force-enqueued
   style-static.min.css carries its own `.et_pb_button:after{content:"5";
   opacity:0;position:absolute;top:50%;transform:translateY(-50%)}` at equal
   (0,1,1) specificity, and every property it sets that this rule does NOT
   also set would otherwise silently apply. */
.elza-btn-arrow::after {
  content: "" !important;
  display: inline-block !important;
  width: 16px !important;
  height: 16px !important;
  flex-shrink: 0 !important;
  margin: 0 !important;
  position: static !important;
  opacity: 1 !important;
  top: auto !important;
  left: auto !important;
  right: auto !important;
  transform: none !important;
  background-color: currentColor !important;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14'/%3E%3Cpath d='m12 5 7 7-7 7'/%3E%3C/svg%3E") center / contain no-repeat !important;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14'/%3E%3Cpath d='m12 5 7 7-7 7'/%3E%3C/svg%3E") center / contain no-repeat !important;
  transition: none !important;
}
.elza-eyebrow { line-height: 1.4; }

/* --- Section 1: hero --- */
/* Task 16 fix: same missing-!important bug as .elza-footer-section above
   (see its docblock for the full root-cause writeup) -- masked here since
   a full-bleed background image sits on top, but the section's own
   fallback colour was still wrong (visible as a white flash before the
   image loads, or if the image ever fails). */
.elza-home-hero { position: relative; overflow: hidden; display: flex; flex-direction: column; justify-content: flex-end; min-height: 100vh; background: var(--el-primary) !important; color: #fff; }
.elza-home-hero::before { content: ""; position: absolute; inset: 0; z-index: 1; background: linear-gradient(90deg, rgba(20,22,17,.78) 0%, rgba(20,22,17,.24) 58%, rgba(20,22,17,.34) 100%); pointer-events: none; }
.elza-home-hero::after { content: ""; position: absolute; left: 0; top: 130px; bottom: 0; width: 8px; z-index: 2; background: var(--el-olive); }

/* Review fix (Important #2, cross-task, 2026-09-22): Task 13 discovered
   Divi's own style-static.min.css rule
   `.et_pb_row:not([class*=et_flex_column])` sets `position:relative` at
   specificity (0,2,0), beating a plain single-class `position:absolute`
   (0,1,0) regardless of source order or !important on width/max-width
   alone — this row had the width/max-width !important (Task 11 fix) but
   not position, so it silently computed position:relative and collapsed
   to its auto content height, making the hero background photo invisible.
   Also applying Task 13's Bug 2 fix to the column (explicit width/height
   !important + float:none !important) since Divi's own
   `.et_block_row>.et_pb_column{width:100%}` wasn't reliably resolving
   either — same `[et_pb_column type="4_4"]` structure as Story's hero,
   which needed both fixes together. See task-13-report.md's "Fix 2"
   section for the full repro/verification. */
.elza-hero-bg-row { position: absolute !important; inset: 0; z-index: 0; width: 100% !important; max-width: none !important; margin: 0; }
.elza-hero-bg-row .et_pb_column { padding: 0; position: relative; width: 100% !important; height: 100% !important; float: none !important; }
/* Margin fix (2026-09-25): real getComputedStyle() measurement showed this
   element computing to margin-bottom:49.5px despite `margin:0` right here --
   Divi's own per-module DEFERRED dynamic CSS (`et-core-unified-*-cached-
   inline-styles-2`, printed inside <body>, see functions.php's docblock)
   beats anything in <head> regardless of source order or specificity within
   <head>. For an absolutely-positioned element with top:0 and bottom:0 both
   set, a non-zero margin-bottom is subtracted from the auto-computed height
   (1100 - 49.5 = 1050.5, exactly what was measured) -- so the hero photo
   fell 49.5px short of the section's full height, and the gap revealed
   .elza-home-hero's own dark --el-primary fallback background at the very
   bottom of the hero on every page load. `!important` forces this to 0
   regardless of what Divi's deferred block sets. */
.elza-hero-bg-image { position: absolute; inset: 0; margin: 0 !important; }
.elza-hero-bg-image img { width: 100%; height: 100%; object-fit: cover; object-position: 55% center; display: block; }

.elza-hero-stitch-rail { position: absolute; right: 0; top: 130px; bottom: 0; width: 70px; z-index: 3; display: none; border-left: 1px solid rgba(255,255,255,.2); background: rgba(243,223,198,.9); color: var(--el-fg); }
@media (min-width: 768px) { .elza-hero-stitch-rail { display: flex; } }
/* Task 18 fix (measured, real browser): this rail renders dark ink on a
   champagne (#F3DFC6/90) panel in the source -- Home.tsx's
   `text-[#25271f]`. The blanket dark-section rule near the top of this file
   (`.elza-home-hero .et_pb_text { color: inherit !important }`, which exists
   so ordinary hero copy inherits the hero's white) was also catching this
   module, forcing the rail's text to #fff on a near-white panel, i.e.
   effectively invisible. Needs a more specific, equally-!important
   override -- when both rules carry !important, specificity decides, so
   (0,2,0) here beats that rule's (0,2,0)... hence the extra class on the
   inner element to reach (0,3,0). */
.elza-hero-stitch-rail .et_pb_text_inner { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; overflow: hidden; margin: 0; }
.elza-home-hero .elza-hero-stitch-rail .et_pb_text,
.elza-home-hero .elza-hero-stitch-rail .et_pb_text_inner,
.elza-home-hero .elza-hero-stitch-rail .elza-stitch-rail-inner,
.elza-home-hero .elza-hero-stitch-rail .elza-stitch-rail-inner span { color: var(--el-fg) !important; }
.elza-stitch-rail-inner { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; overflow: hidden; }
.elza-stitch-rail-inner span { width: max-content; font-family: 'Jost', sans-serif; font-size: 11px; font-weight: 500; letter-spacing: .22em; text-transform: uppercase; transform: rotate(90deg); }

.elza-hero-content-row { position: relative; z-index: 4; width: 100% !important; max-width: 1500px !important; margin: 0 auto; padding: 12rem 1.75rem 5rem; display: flex; flex-wrap: wrap; gap: 2.5rem; align-items: flex-end; }
@media (min-width: 768px) { .elza-hero-content-row { padding: 12rem 3.5rem 6rem; } }
@media (min-width: 980px) { .elza-hero-content-row { padding: 12rem 8rem 6rem 5rem; } }
.elza-hero-content-row .et_pb_column { padding: 0; margin: 0 !important; }
/* Layout change (2026-09-25): `.elza-hero-cta-col` (subhead + the 2 CTA
   buttons) is gone -- the subhead was removed in an earlier pass, and the
   buttons moved to the new .elza-hero-bar section below the photo (see
   class-page-home.php's section_hero_bar()). `.elza-hero-headline-col` is
   now the row's only column (Divi column type 4_4), so it just takes the
   row's full width -- no more asymmetric flex-basis split needed. */
.elza-hero-headline-col { flex: 0 0 100%; max-width: 100%; }
.elza-hero-eyebrow { color: rgba(255,255,255,.75); }
.elza-hero-heading { margin-top: 1.5rem; font-size: clamp(4.075rem, 8.8vw, 8.875rem); text-transform: uppercase; line-height: .8; letter-spacing: -.055em; max-width: 64rem; }
.elza-hero-heading-accent { color: var(--el-secondary); text-transform: none; letter-spacing: normal; }

/* New section (2026-09-25, explicit client request): dark bar directly
   below the hero photo holding the scroll cue (left) and the two CTA
   buttons -- see section_hero_bar()'s docblock in class-page-home.php for
   why this replaced the hero's old absolutely-positioned scroll-cue
   overlay. `--el-primary` matches the same dark colour `.elza-home-hero`
   itself falls back to, so the bar reads as a continuation of the hero's
   palette. */
/* `color:#fff` matters beyond the visible text here -- .elza-btn-outline's
   `color: inherit !important` (style.css) needs it to resolve to white
   instead of falling through to body's dark --el-fg, which is what made
   "Our story" render near-invisible dark-on-dark before this was added. */
.elza-hero-bar { background: var(--el-primary) !important; color: #fff; }
/* Round 2 (2026-09-25, client refinement): "reduce the size of the green,
   just a thin strip above and beneath the buttons" -- padding cut from
   40-48px to a flat 1rem (16px) top/bottom at every breakpoint; only the
   horizontal padding still grows with viewport, matching every other
   section's own left/right rhythm. */
/* Round 3 (2026-09-25, client refinement): pin "Follow the thread" harder
   left -- padding-left cut roughly in half at every breakpoint (right side
   left untouched, still gives the button pair the same breathing room
   against the row's own edge). */
.elza-hero-bar-row { width: 100% !important; max-width: 1500px !important; margin: 0 auto; padding: 1rem 1.75rem; }
@media (min-width: 768px) { .elza-hero-bar-row { padding-top: 1rem; padding-bottom: 1rem; padding-left: 1.75rem; padding-right: 3.5rem; } }
@media (min-width: 980px) { .elza-hero-bar-row { padding-left: 1.75rem; padding-right: 5rem; } }
.elza-hero-bar-row .et_pb_column { padding: 0; margin: 0 !important; }
/* Vertical-alignment fix (2026-09-25): real measurement found the "Explore
   the collection" button's own `.et_pb_button_module_wrapper` computing
   margin-bottom:8.8px while "Our story"'s had none -- Divi's own default
   module spacing (added between stacked modules in a column, skipped on
   the actual last child) doesn't know this column got turned into a
   horizontal row via the grid above. That stray margin shifted Explore's
   whole box up ~4.4px relative to Our story's, so their centres didn't
   land on the same horizontal line even though both boxes are the same
   56px height. Zeroing margin on every direct child of this column
   removes it regardless of which child Divi decides is "last". */
.elza-hero-bar-col > div { margin: 0 !important; }
/* Round 2 (2026-09-25, client refinement): "the explore button should be
   centred with the our story button directly next to it" -- rebuilt as a
   4-track CSS Grid (`1fr auto auto 1fr`) instead of the flex/margin-auto
   layout. The scroll cue sits in track 1 (justify-self:start, flush left);
   the two buttons sit in tracks 2 and 3 (side by side, own natural width);
   track 4 is a deliberately empty phantom spacer -- CSS Grid tracks don't
   need a DOM child to exist and still consume their share of space, so an
   empty 1fr there mirrors track 1's 1fr exactly, which is what actually
   centres the button pair in the row rather than just centring them
   within whatever space happens to be left over. Selecting the two button
   wrappers by `:has(> .elza-btn-primary/.elza-btn-outline)` rather than
   Divi's own auto-numbered `et_pb_button_N_wrapper` classes (page-wide
   indices, would silently break if another button is ever added earlier
   on this page) or `:nth-child` (position-based, exactly the kind of
   selector this project's own CLAUDE.md warns off for this reason). */
/* Below 768px there isn't reliably enough width for a 4-track grid without
   the buttons crowding the scroll cue, so mobile gets a simple stack
   instead -- the grid (and its actual centering job) only applies from
   768px up. Left-aligned (2026-09-25, explicit client request -- was
   centred, client wanted "Follow the thread" pinned to the left with no
   gap): the row's own padding (.elza-hero-bar-row) still applies, matching
   every other section's left-edge rhythm -- "no gap" reads as "don't add
   the centering gap on top of that," not "sit flush against the browser
   edge with no padding at all." */
.elza-hero-bar-col { display: flex; flex-direction: column; align-items: flex-start; gap: 1rem; text-align: left; }
@media (min-width: 768px) {
  .elza-hero-bar-col { display: grid; grid-template-columns: 1fr auto auto 1fr; align-items: center; column-gap: 1rem; text-align: left; }
  .elza-hero-bar-col .elza-hero-scrollcue { grid-column: 1; justify-self: start; }
  .elza-hero-bar-col > div:has(> .elza-btn-primary) { grid-column: 2; }
  .elza-hero-bar-col > div:has(> .elza-btn-outline) { grid-column: 3; }
}
/* Round 3 (2026-09-25, client refinement): "ensure the boxes are the same
   size" -- "Explore the collection" (with its arrow) measured 320.8px,
   "Our story" only 162.5px, since both were shrink-to-fit on their own
   text. `.et_pb_button` is already `inline-flex;justify-content:center`
   (see its base rule above), so a shared explicit width just centres each
   label/icon within an equal box rather than changing anything about the
   flex centring already in place. 320px covers the longer label with its
   arrow at every breakpoint this bar is visible (768px+ only, matching
   the grid layout above -- mobile keeps auto-width, shrink-to-fit buttons
   in its stacked, centred layout). */
@media (min-width: 768px) {
  .elza-hero-bar-col .elza-btn-primary, .elza-hero-bar-col .elza-btn-outline { width: 320px; }
}
.elza-scrollcue-icon { width: 16px; height: 16px; flex-shrink: 0; }
.elza-hero-scrollcue-link { display: inline-flex; align-items: center; gap: .75rem; font-family: 'Jost', sans-serif; font-size: 11px; text-transform: uppercase; letter-spacing: .22em; color: rgba(255,255,255,.7); text-decoration: none; font-weight: 500; }

/* Review fix (Critical #1): Home.tsx line 27 styles this one button
   uniquely — white bg / dark text / champagne hover — a deliberate
   high-contrast choice against the dark hero photo, NOT the shared
   elza-btn-primary dark-bg style used elsewhere on the site. Without this
   scoped override, elza-btn-primary's background (var(--el-primary),
   #292d24) is nearly identical to .elza-home-hero's own background,
   making the button nearly invisible. Scoped to .elza-home-hero so the
   shared class keeps its normal (correct) appearance everywhere else —
   never a positional selector, just an ancestor-scoped override per the
   project's established convention. */
.elza-home-hero .elza-btn-primary, .elza-hero-bar .elza-btn-primary { background: #fff !important; color: var(--el-fg) !important; border-color: #fff !important; }
.elza-home-hero .elza-btn-primary:hover, .elza-hero-bar .elza-btn-primary:hover { background: var(--el-secondary) !important; border-color: var(--el-secondary) !important; }
/* Task 18: Home.tsx's hero "Our story" button carries `border-white/55
   text-white hover:border-white hover:bg-white hover:text-foreground` --
   a 55%-white border, not the base outline rule's rgba(37,39,31,.25).
   Extended to .elza-hero-bar 2026-09-25 when the buttons moved there (see
   .elza-hero-bar's own docblock) -- same dark background, same treatment. */
.elza-home-hero .elza-btn-outline, .elza-hero-bar .elza-btn-outline { border-color: rgba(255,255,255,.55) !important; }
.elza-home-hero .elza-btn-outline:hover, .elza-hero-bar .elza-btn-outline:hover { border-color: #fff !important; background: #fff !important; color: var(--el-fg) !important; }

/* Padding pass (2026-09-25, explicit client request -- "reduce the top and
   bottom part of the section, there are big gaps where sections end and
   start"): every top-level section's vertical padding below this point was
   trimmed by roughly 15-20%, rounded to values already used elsewhere in
   this file (4/5/5.5/6.5/7/8rem; 44/48/56/64px for the footer bands).
   IMPORTANT -- checked against the source app first (elza-website's own
   Tailwind classes) and confirmed these values were NOT a Divi bug: every
   one of them matched the source's py-*/lg:py-* values exactly before this
   pass. This is a deliberate sitewide deviation from the previously
   pixel-matched design, not a fix -- if a future session re-diffs against
   the live Node app and finds these don't match, that's expected and
   correct, not a regression to "fix" back. */
/* --- Section 2: intro ("Who we are") --- */
.elza-intro-section { background: var(--el-bg-alt); padding: 5rem 1.5rem; }
@media (min-width: 768px) { .elza-intro-section { padding: 6.5rem 3rem; } }
@media (min-width: 980px) { .elza-intro-section { padding: 8rem 4rem; } }
/* Review fix (Critical #2): explicit width:100% needed — without it the
   base `.et_pb_row { width: 80%; margin: auto; }` rule (Task 2) wins
   underneath, since this rule only ever set max-width/display, never
   width, leaving the row ~20% narrower than intended on desktop.
   Task 11 fix round: !important added to width AND max-width — Divi's own
   force-enqueued style-static.min.css carries
   `.et_pb_row:not([class*=et_flex_column]){width:80%;...;max-width:1080px;...}`,
   specificity (0,2,0) (class + attribute-selector-inside-:not()), which
   beats every single-class selector on this page (0,1,0) regardless of
   source order or which longhand property is set — confirmed via real
   headless Chromium getBoundingClientRect() showing rows capped at exactly
   1080px before this fix. See functions.php / style.css Task 11 notes for
   the full writeup; every .et_pb_row-targeting width/max-width rule in this
   file now carries !important for the same reason. */
.elza-intro-row { width: 100% !important; max-width: 1280px !important; margin: 0 auto; display: flex; flex-wrap: wrap; align-items: center; gap: 3.5rem; }
@media (min-width: 980px) { .elza-intro-row { flex-wrap: nowrap; gap: 6rem; } }
.elza-intro-row .et_pb_column { padding: 0; margin: 0 !important; }
.elza-intro-image-col, .elza-intro-copy-col { flex: 0 0 100%; max-width: 100%; }
/* Final-review fix (Important, 2026-09-23): 43% + 57% already summed to
   100% of the row's content-box width; with `gap: 6rem` (line 333) still in
   force at this same breakpoint, the two columns' required total width
   (43% + 57% + 6rem) exceeded 100%, producing ~96px of real horizontal
   overflow at desktop widths (980-1360px) -- confirmed via real Chromium
   measurement. Same arithmetic bug as `.elza-contact-faq-row` (see that
   rule's docblock, ~line 1060, for the full root-cause writeup) and fixed
   with the identical precise pattern: half of this row's own 6rem gap
   (3rem) subtracted from each side's flex-basis so basis + gap sums to
   exactly 100% instead of silently overflowing. */
@media (min-width: 980px) {
  .elza-intro-image-col { flex: 0 0 calc((100% - 6rem) * .43); max-width: calc((100% - 6rem) * .43); }
  .elza-intro-copy-col { flex: 0 0 calc((100% - 6rem) * .57); max-width: calc((100% - 6rem) * .57); }
}
.elza-intro-image { max-width: 570px; margin: 0 auto; }
@media (min-width: 980px) { .elza-intro-image { margin: 0; } }
/* object-position (2026-10-09, explicit client request, "centre this image
   the focus should be on the handbag" /ui-ux-pro-max): maker-tan-bag.jpg is
   1600x1066 with the bag sitting well right-of-centre (body spans roughly
   x=580-1350 of 1600) -- default `center` object-position crops this 4:5
   portrait box around the SOURCE's own geometric centre (the shoulder/arm),
   not the bag, cutting the bag's right edge and strap while including
   unnecessary plain-background width on the left. 72% horizontal shifts the
   crop window to centre on the bag's own midpoint instead. */
.elza-intro-image img { aspect-ratio: 4 / 5; width: 100%; object-fit: cover; object-position: 72% center; display: block; }
.elza-intro-image::before { content: ""; position: absolute; right: 0; bottom: 0; width: 128px; height: 128px; border: 1px solid rgba(153,149,114,.45); display: none; z-index: 1; pointer-events: none; }
@media (min-width: 768px) { .elza-intro-image::before { display: block; } }
.elza-intro-eyebrow { color: var(--el-olive-dark); }
.elza-intro-heading { margin-top: 1.25rem; font-size: clamp(3.375rem, 6.5vw, 6.875rem); line-height: .9; letter-spacing: -.04em; max-width: 42rem; }
.elza-intro-heading .font-editorial { color: var(--el-terracotta); }
.elza-intro-body { margin-top: 2.25rem; max-width: 42rem; }
.elza-intro-body p { font-size: 1.125rem; line-height: 1.625; color: rgba(37,39,31,.68); margin: 0 0 1.25rem; }
.elza-intro-body p:last-child { margin-bottom: 0; }
/* Task 18: source is the Button component's `link` variant --
   `h-auto border-0 bg-transparent px-0 py-1 text-primary underline-offset-8
   hover:underline`. Three corrections against what was here before:
   (a) `text-primary` is --primary (#292d24), not --el-fg (#25271f);
   (b) the underline is a HOVER state in the source, not a permanent one --
       this rule had it always-on;
   (c) `underline-offset-8` is 8px, not 4px.
   The BOX, though, is NOT the variant's `h-auto px-0`: measured on the live
   app, this button computes `height: 48px; padding: 4px 24px`. That is
   tailwind-merge doing its job inside cva -- the `size: default` variant
   (`h-12 px-6`) is emitted AFTER the `variant: link` classes in the generated
   class string, so `h-12`/`px-6` win the merge over `h-auto`/`px-0`, while
   `py-1` survives because nothing later sets py. Matching what actually
   renders (48px / 4px 24px), not what the variant string reads like -- the
   difference measured 48px of link width, 268px here vs 316px on the source
   app. */
.elza-link-cta { background: transparent !important; border: none !important; color: var(--el-primary) !important; height: 48px !important; padding: .25rem 1.5rem !important; text-decoration: none; text-underline-offset: 8px; margin-top: 2rem !important; display: inline-flex !important; }
.elza-link-cta:hover { text-decoration: underline; background: transparent !important; color: var(--el-primary) !important; }

/* --- Section 3: featured collection --- */
.elza-featured-section { background: var(--el-bg); border-top: 1px solid rgba(37,39,31,.12); border-bottom: 1px solid rgba(37,39,31,.12); padding: 5rem 1.5rem; }
@media (min-width: 768px) { .elza-featured-section { padding: 6.5rem 3rem; } }
@media (min-width: 980px) { .elza-featured-section { padding: 6.5rem 4rem; } }
.elza-featured-header-row, .elza-featured-grid-row { max-width: 1500px !important; margin: 0 auto; width: 100% !important; }
.elza-featured-header-col { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: flex-end; gap: 1.75rem; margin-bottom: 3rem; padding: 0 !important; }
.elza-featured-eyebrow { color: var(--el-olive-dark); }
.elza-featured-heading { margin-top: 1rem; font-size: clamp(3.475rem, 6.5vw, 6.875rem); line-height: .9; margin-bottom: 0; }
.elza-featured-heading .font-editorial { color: var(--el-terracotta); }

.elza-product-grid { display: grid; gap: 1.25rem; grid-template-columns: 1fr; }
@media (min-width: 768px) { .elza-product-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1200px) { .elza-product-grid { grid-template-columns: repeat(3, 1fr); } }

.elza-product-card { display: flex; flex-direction: column; height: 100%; border: 1px solid rgba(37,39,31,.12); background: var(--el-bg-alt); text-decoration: none; color: inherit; }
.elza-product-card-image { position: relative; }
.elza-product-card-image img { aspect-ratio: 4/5; width: 100%; object-fit: cover; display: block; }
.elza-product-card-chip { position: absolute; left: 1rem; top: 1rem; background: rgba(251,248,242,.92); padding: .5rem .75rem; font-family: 'Jost', sans-serif; font-size: 12px; font-weight: 500; text-transform: uppercase; letter-spacing: .16em; }
.elza-product-card-body { display: flex; flex: 1; flex-direction: column; justify-content: space-between; gap: 1.75rem; padding: 1.25rem; }
@media (min-width: 768px) { .elza-product-card-body { padding: 1.5rem; } }
.elza-product-card-name { font-family: 'Jost', sans-serif; font-weight: 500; font-size: 28px; line-height: 1.25; margin: 0; }
.elza-product-card-desc { margin-top: .75rem; line-height: 1.625; color: var(--el-muted-fg); }
.elza-product-card-footer { display: flex; align-items: center; justify-content: space-between; border-top: 1px solid rgba(37,39,31,.12); padding-top: 1rem; }
.elza-product-card-viewpiece { font-family: 'Jost', sans-serif; font-size: 13px; text-transform: uppercase; letter-spacing: .16em; font-weight: 500; }
.elza-product-card-swatches { display: flex; gap: .5rem; }
.elza-swatch { width: 14px; height: 14px; border-radius: 50%; border: 1px solid rgba(37,39,31,.2); display: inline-block; }

/* --- Section 4: dark split banner --- */
/* Task 16 fix: same missing-!important bug as .elza-footer-section (Task
   8's docblock, above) -- this section is a flat colour fill with no
   image, so the bug was fully visible (white background, invisible white
   text) until this fix. */
.elza-dark-banner-section { background: var(--el-primary) !important; color: #fff; }
.elza-dark-banner-row { display: flex; flex-wrap: wrap; margin: 0; width: 100% !important; max-width: none !important; }
.elza-dark-banner-row .et_pb_column { padding: 0; margin: 0 !important; }
.elza-banner-image-col, .elza-banner-copy-col { flex: 0 0 100%; max-width: 100%; }
/* Second-review fix (Important, 2026-09-23): this column has no
   `flex-direction` (defaulting to `row`), so its 2 direct flex children --
   the et_pb_text module (eyebrow+heading+body paragraph) and the separate
   button module wrapper -- laid out SIDE BY SIDE instead of stacked, with
   `align-items:center` vertically centering that row. The adjacent
   `.elza-banner-copy-col .et_pb_button_module_wrapper { margin-top: 2.25rem }`
   rule below only makes sense for a vertical stack (a top margin between
   stacked children), confirming a vertical layout was always the intent --
   it was simply inert as long as flex-direction stayed row (no "top" edge
   between side-by-side items). Source (Home.tsx) confirms: the outer
   `flex items-center` wrapper there centers a single block-level child
   containing eyebrow/heading/paragraph/button, which stack naturally via
   normal block flow -- `flex-direction:column` here is the equivalent
   fix for Divi's flatter module structure (text module and button module
   as separate flex siblings, not one wrapped block). Beyond the visual bug
   (CTA button beside the paragraph instead of below it, at every
   viewport), this also caused real horizontal overflow at narrow widths --
   the side-by-side text (~259px) + button (~104px) didn't fit the column's
   available width. `justify-content:center` replaces `align-items:center`
   for the same vertical-centering intent, now on the correct axis for
   column mode; `align-items:flex-start` left-aligns both children,
   matching the source's naturally left-aligned block content. */
/* Source: `px-7 py-24 md:px-16 lg:px-[8vw]` -- the lg step is 8vw (115px at
   1440), NOT a fixed 5rem/80px, which measured this column 70px too wide. */
.elza-banner-copy-col { display: flex; flex-direction: column; justify-content: center; align-items: flex-start; padding: 4rem 1.75rem !important; }
@media (min-width: 768px) { .elza-banner-copy-col { padding-left: 4rem !important; padding-right: 4rem !important; } }
@media (min-width: 980px) {
  .elza-banner-image-col { flex: 0 0 52.5%; max-width: 52.5%; }
  .elza-banner-copy-col { flex: 0 0 47.5%; max-width: 47.5%; padding-left: 8vw !important; padding-right: 8vw !important; }
}
/* Section size reduced 2026-10-09 (explicit client request, "reduce the
   size of this section") -- min-height dropped from the source app's
   verbatim 70vh to 46vh (a deliberate departure from pixel-for-pixel
   replica fidelity, unlike every other `min-height`/`clamp()` value in
   this file, which intentionally match Home.tsx exactly). Heading clamp
   max and copy-col vertical padding (above) scaled down to match, so the
   shorter banner doesn't read as oddly cramped relative to its own type
   scale. */
.elza-banner-image { display: block; height: 100%; min-height: 46vh; margin: 0; }
.elza-banner-image img { width: 100%; height: 100%; min-height: 46vh; object-fit: cover; display: block; }
.elza-banner-eyebrow { color: var(--el-accent); }
.elza-banner-heading { margin-top: 1.25rem; font-size: clamp(2.75rem, 4.5vw, 5rem); line-height: .95; }
.elza-banner-heading .font-editorial { color: var(--el-secondary); }
.elza-banner-body { margin-top: 1.5rem; max-width: 34rem; font-size: 1.125rem; line-height: 1.625; color: rgba(255,255,255,.7); }
.elza-banner-copy-col .et_pb_button_module_wrapper { margin-top: 1.75rem; }
/* Task 18: Home.tsx's banner CTA carries `border-white/40 text-white
   hover:bg-white hover:text-foreground` -- 40%-white border, distinct from
   both the base outline rule and the hero's 55%. */
.elza-dark-banner-section .elza-btn-outline { border-color: rgba(255,255,255,.4) !important; }
.elza-dark-banner-section .elza-btn-outline:hover { border-color: #fff !important; background: #fff !important; color: var(--el-fg) !important; }

/* --- Section 5: trust strip --- */
.elza-trust-section { background: var(--el-bg-alt); padding: 3rem 1.5rem; }
@media (min-width: 768px) { .elza-trust-section { padding: 4rem 3rem; } }
/* Review fix (Critical #2): this row previously had no module_class at
   all, so the base `.et_pb_row { width: 80%; margin: auto; }` rule
   (Task 2) applied unopposed, making the section ~20% narrower than
   intended. class-page-home.php now sets module_class="elza-trust-row"
   on this row. */
.elza-trust-row { width: 100% !important; max-width: none !important; margin: 0; }
.elza-trust-grid { max-width: 1280px; margin: 0 auto; border-top: 1px solid rgba(37,39,31,.14); border-bottom: 1px solid rgba(37,39,31,.14); display: grid; grid-template-columns: 1fr; }
@media (min-width: 768px) { .elza-trust-grid { grid-template-columns: repeat(3, 1fr); border-top: none; border-bottom: none; } }
.elza-trust-item { display: flex; gap: 1.25rem; padding: 1.75rem 1.25rem; border-bottom: 1px solid rgba(37,39,31,.14); }
.elza-trust-item:last-child { border-bottom: none; }
@media (min-width: 768px) {
  .elza-trust-item { border-bottom: none; border-right: 1px solid rgba(37,39,31,.14); }
  .elza-trust-item:last-child { border-right: none; }
}
.elza-trust-icon { flex-shrink: 0; width: 24px; height: 24px; color: var(--el-olive-dark); margin-top: .25rem; }
.elza-trust-icon svg { width: 100%; height: 100%; }
.elza-trust-item h3 { font-family: 'Jost', sans-serif; font-weight: 500; font-size: 24px; line-height: 2rem; margin: 0; }
.elza-trust-item p { margin-top: .75rem; line-height: 1.625; color: var(--el-muted-fg); }

/* --- Section 6: closing CTA --- */
.elza-closing-cta-section { background: var(--el-secondary) !important; text-align: center; padding: 5rem 1.5rem; }
@media (min-width: 768px) { .elza-closing-cta-section { padding: 7rem 3rem; } }
/* Review fix (Critical #2): same missing-module_class bug as the trust
   strip above — this row previously had no module_class, so the base
   80%-width rule applied unopposed. class-page-home.php now sets
   module_class="elza-closing-row" on this row. */
.elza-closing-row { width: 100% !important; max-width: none !important; margin: 0; }
.elza-closing-cta-inner { max-width: 72rem; margin: 0 auto; }
.elza-closing-eyebrow { color: var(--el-olive-dark); }
.elza-closing-heading { margin-top: 1.5rem; font-size: clamp(3.375rem, 7vw, 7.675rem); line-height: .88; letter-spacing: -.045em; }
.elza-closing-heading .font-editorial { color: var(--el-terracotta); }
.elza-closing-sub { margin-top: 2rem; font-size: 1.25rem; line-height: 1.75rem; color: rgba(37,39,31,.62); }
.elza-closing-cta-section .et_pb_button_module_wrapper { margin-top: 2.25rem; }

/* ==========================================================================
   Task 11: Shop page (class-page-shop.php)
   ========================================================================== */

/* --- Section 1: hero ---
   Simpler than Home's hero: single content block pinned bottom-left, no
   split columns. Gradient stops/colour (rgba(26,29,23,...)) and opacity
   values below are copied verbatim from Shop.tsx's own inline
   bg-[linear-gradient(...)] and text-white/NN utilities — deliberately NOT
   reused from Home's slightly different hero gradient (rgba(20,22,17,...)),
   since Shop.tsx's own literal values are this page's source of truth. */
.elza-shop-hero { position: relative; overflow: hidden; display: flex; flex-direction: column; justify-content: flex-end; min-height: 72vh; background: var(--el-primary) !important; color: #fff; }
.elza-shop-hero::before { content: ""; position: absolute; inset: 0; z-index: 1; background: linear-gradient(90deg, rgba(26,29,23,.78) 0%, rgba(26,29,23,.35) 55%, rgba(26,29,23,.28) 100%); pointer-events: none; }

/* Review fix (Important #2, cross-task, 2026-09-22): same missing
   `!important` on `position` that Task 13 found and fixed on
   .elza-story-hero-bg-row — see that rule's docblock further down this
   file and task-13-report.md's "Fix 2" section. Column also needs the
   explicit width/height !important + float:none !important fix (Task
   13's Bug 2) since this row uses the identical `[et_pb_column
   type="4_4"]` structure. */
.elza-shop-hero-bg-row { position: absolute !important; inset: 0; z-index: 0; width: 100% !important; max-width: none !important; margin: 0; }
.elza-shop-hero-bg-row .et_pb_column { padding: 0; position: relative; width: 100% !important; height: 100% !important; float: none !important; }
.elza-shop-hero-bg-image { position: absolute; inset: 0; margin: 0; }
.elza-shop-hero-bg-image img { width: 100%; height: 100%; object-fit: cover; object-position: center; display: block; }

.elza-shop-hero-content-row { position: relative; z-index: 4; width: 100% !important; max-width: 1500px !important; margin: 0 auto; padding: 4rem 1.5rem; }
@media (min-width: 768px) { .elza-shop-hero-content-row { padding: 5rem 3rem; } }
@media (min-width: 980px) { .elza-shop-hero-content-row { padding: 5rem 4rem; } }
.elza-shop-hero-content-row .et_pb_column { padding: 0; margin: 0 !important; }

.elza-shop-hero-inner { max-width: 56rem; }
.elza-shop-hero-eyebrow { color: rgba(255,255,255,.7); }
.elza-shop-hero-heading { margin-top: 1.25rem; font-size: clamp(4.075rem, 9vw, 8.875rem); text-transform: uppercase; line-height: .82; letter-spacing: -.05em; }
.elza-shop-hero-heading-accent { color: var(--el-secondary); text-transform: none; letter-spacing: normal; }
.elza-shop-hero-sub { margin-top: 1.75rem; max-width: 36rem; font-size: 1.25rem; line-height: 1.625; color: rgba(255,255,255,.76); }

/* --- Section 2: filter + grid ---
   bg is var(--el-bg) (#F8F5EF), matching Shop.tsx's literal bg-[#F8F5EF] —
   not var(--el-bg-alt) (#FBF8F2), a different token; see class-page-shop.php
   docblock. */
.elza-shop-grid-section { background: var(--el-bg); padding: 4rem 1.5rem; }
@media (min-width: 768px) { .elza-shop-grid-section { padding: 5.5rem 3rem; } }
@media (min-width: 980px) { .elza-shop-grid-section { padding: 5.5rem 4rem; } }
/* Explicit width:100% on both rows — without it the base
   `.et_pb_row { width: 80%; margin: auto; }` rule wins underneath (the same
   Critical bug Task 10's review caught and fixed). !important on both
   width AND max-width — see the Task 11 fix-round note above
   .elza-intro-row for why a single-class selector alone isn't enough
   against Divi's own force-enqueued style-static.min.css. */
.elza-shop-filter-row, .elza-shop-grid-row { width: 100% !important; max-width: 1500px !important; margin: 0 auto; }

.elza-shop-filter-bar { display: flex; flex-direction: column; gap: 1.5rem; border-top: 1px solid rgba(37,39,31,.14); border-bottom: 1px solid rgba(37,39,31,.14); padding: 1.25rem 0; margin-bottom: 3rem; }
@media (min-width: 768px) { .elza-shop-filter-bar { flex-direction: row; align-items: center; justify-content: space-between; } }
.elza-filter-pills { display: flex; flex-wrap: wrap; gap: .5rem; }
/* Task 18 -- font-size deliberately 17px, NOT the 13px Shop.tsx's class list
   asks for. Shop.tsx writes `font-display text-[13px] font-medium uppercase
   tracking-[0.14em]`, but `text-[13px]` never makes it into the app's
   generated Tailwind CSS: measured on the live app at :8600, these pills
   compute font-size 17px (the inherited body size), letter-spacing 2.38px
   (= .14em of 17px, not of 13px) and 54px tall. This build's job is to
   replicate what the source app actually RENDERS, so it matches 17px/54px.
   If the source app is ever rebuilt and that utility starts applying, this
   rule needs to follow it back down to 13px. */
.elza-filter-pill { display: inline-block; border: 1px solid rgba(37,39,31,.18); padding: .75rem 1.25rem; font-family: 'Jost', sans-serif; font-size: 17px; font-weight: 500; text-transform: uppercase; letter-spacing: .14em; text-decoration: none; color: inherit; transition: border-color 200ms var(--el-ease), background-color 200ms var(--el-ease), color 200ms var(--el-ease); }
.elza-filter-pill:hover { border-color: var(--el-fg); }
.elza-filter-pill.is-active { border-color: var(--el-primary); background: var(--el-primary); color: #fff; }
.elza-shop-count { font-family: 'Jost', sans-serif; font-size: 13px; text-transform: uppercase; letter-spacing: .14em; color: var(--el-muted-fg); font-weight: 500; }

/* Product grid/card: intentionally no new rules here — this page reuses
   .elza-product-grid / .elza-card.elza-product-card and all its descendant
   classes verbatim from Task 10 (see "Section 3: featured collection"
   above). */

/* --- Section 3: closing CTA --- */
.elza-shop-closing-section { background: var(--el-secondary) !important; text-align: center; padding: 4rem 1.5rem; }
@media (min-width: 768px) { .elza-shop-closing-section { padding: 5.5rem 3rem; } }
.elza-shop-closing-row { width: 100% !important; max-width: none !important; margin: 0; }
.elza-shop-closing-inner { max-width: 56rem; margin: 0 auto; }
.elza-shop-closing-eyebrow { color: var(--el-olive-dark); }
.elza-shop-closing-heading { margin-top: 1.25rem; font-size: clamp(3.275rem, 6vw, 6.375rem); line-height: .9; }
.elza-shop-closing-heading .font-editorial { color: var(--el-terracotta); }
.elza-shop-closing-sub { margin-top: 1.75rem; max-width: 42rem; margin-left: auto; margin-right: auto; font-size: 1.125rem; line-height: 1.75rem; color: rgba(37,39,31,.65); }

/* ==========================================================================
   Task 12: Single product template (woocommerce/single-product.php,
   woocommerce/single-product/related.php)
   ========================================================================== */

/* --- Section 1: hero split (image / details) ---
   Source: Product.tsx `grid ... bg-[#F8F5EF] lg:grid-cols-[58%_42%]`.
   "lg:" here follows this project's established lg=980px convention (same
   breakpoint already used for every other "lg:"-prefixed source class in
   Tasks 10-11), not Tailwind's own default lg=1024px. */
.elza-product-hero { display: grid; min-height: calc(100svh - 125px); background: var(--el-bg); }
@media (min-width: 980px) { .elza-product-hero { grid-template-columns: 58% 42%; } }

.elza-product-image { position: relative; min-height: 68svh; overflow: hidden; background: var(--el-product-bg); }
@media (min-width: 980px) { .elza-product-image { min-height: 0; } }
.elza-product-image img { position: absolute; inset: 0; height: 100%; width: 100%; object-fit: cover; display: block; }

/* Automated multi-photo carousel (2026-10-08) — shared by product cards
   (.elza-carousel--card, inside .elza-product-card-image which already
   sizes via aspect-ratio:4/5) and the single-product hero image
   (.elza-carousel--hero, inside .elza-product-image which already sizes
   via position:absolute;inset:0). Renders only when a product has 2+ real
   photos (class-page-home.php's render_image_or_carousel()) — a
   single-photo product keeps the plain <img> these rules never touch. */
.elza-carousel { position: relative; overflow: hidden; }
.elza-product-card-image .elza-carousel { aspect-ratio: 4/5; width: 100%; display: block; }
.elza-product-image .elza-carousel { position: absolute; inset: 0; height: 100%; width: 100%; }
.elza-carousel-track { position: absolute; inset: 0; display: flex; overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none; -ms-overflow-style: none; }
.elza-carousel-track::-webkit-scrollbar { display: none; }
.elza-carousel-slide { flex: 0 0 100%; scroll-snap-align: start; height: 100%; }
/* Final-review fix (Critical, 2026-10-09): the pre-existing
   `.elza-product-image img { position:absolute; inset:0; ... }` rule
   (written for the old single hero <img>) also matches every
   `.elza-carousel-slide img` nested inside `.elza-product-image`, since
   this rule never resets position. Without this, every hero slide image
   stacks absolutely at inset:0 inside `.elza-carousel-track` instead of
   flowing in its own slide -- the client sees the LAST gallery photo on
   load (not the Featured Image) and a blank `--el-product-bg` panel after
   every autoplay tick. Confirmed live on 5 of 6 real products before this
   fix. `.elza-product-card-image img` has the same source-order fragility
   but currently survives only because its sibling rule declares no
   `position` -- not fixed here since cards aren't broken today, but worth
   the same explicit reset if this area is touched again. */
.elza-carousel-slide img { position: static; inset: auto; width: 100%; height: 100%; object-fit: cover; display: block; }

.elza-carousel-dots { position: absolute; left: 50%; bottom: .875rem; transform: translateX(-50%); z-index: 2; display: flex; gap: .4rem; }
.elza-carousel-dot { width: 6px; height: 6px; border-radius: 50%; border: none; padding: 0; background: rgba(255,255,255,.55); cursor: pointer; transition: background 220ms var(--el-ease), transform 220ms var(--el-ease); }
.elza-carousel-dot.is-active { background: #fff; transform: scale(1.3); }

.elza-carousel-arrow { display: none; position: absolute; top: 50%; transform: translateY(-50%); z-index: 2; width: 2.75rem; height: 2.75rem; border: none; border-radius: 50%; background: rgba(251,248,242,.85); align-items: center; justify-content: center; cursor: pointer; backdrop-filter: blur(4px); font-size: 18px; color: var(--el-fg); }
.elza-carousel--hero .elza-carousel-arrow { display: flex; }
.elza-carousel-arrow.is-prev { left: 1rem; }
.elza-carousel-arrow.is-next { right: 1rem; }

.elza-back-to-collection { position: absolute; left: 1.25rem; top: 1.25rem; z-index: 2; display: inline-flex; align-items: center; gap: .5rem; border: 1px solid rgba(255,255,255,.6); background: rgba(251,248,242,.92); padding: .75rem 1rem; font-family: 'Jost', sans-serif; font-size: 12px; text-transform: uppercase; letter-spacing: .14em; text-decoration: none; color: var(--el-fg); backdrop-filter: blur(6px); font-weight: 500; }
@media (min-width: 768px) { .elza-back-to-collection { left: 2rem; top: 2rem; } }

.elza-product-details { display: flex; align-items: center; padding: 4rem 1.75rem; }
@media (min-width: 768px) { .elza-product-details { padding: 4rem 3.5rem; } }
@media (min-width: 980px) { .elza-product-details { padding-left: 5vw; padding-right: 5vw; } }
.elza-product-details-inner { width: 100%; max-width: 36rem; }

.elza-product-eyebrow { color: var(--el-olive-dark); }
.elza-product-heading { margin-top: 1.25rem; font-size: clamp(3.675rem, 6vw, 6.875rem); line-height: .86; letter-spacing: -.045em; }
.elza-product-story { margin-top: 1.75rem; font-size: 1.25rem; line-height: 1.625; color: rgba(37,39,31,.65); }

.elza-spec-list { margin: 2.25rem 0 0; padding: 1.5rem 0; border-top: 1px solid rgba(37,39,31,.14); border-bottom: 1px solid rgba(37,39,31,.14); }
.elza-spec-list > div { display: flex; justify-content: space-between; gap: 1rem; }
.elza-spec-list > div + div { margin-top: .75rem; }
.elza-spec-list dt { margin: 0; color: var(--el-muted-fg); font-weight: normal; }
.elza-spec-list dd { margin: 0; text-align: right; }

.elza-colour-picker { margin-top: 2rem; border: 0; padding: 0; }
.elza-colour-picker legend { padding: 0; font-family: 'Jost', sans-serif; font-size: 13px; font-weight: 500; text-transform: uppercase; letter-spacing: .14em; }
.elza-colour-picker-current { margin-left: .5rem; font-family: 'Raleway', sans-serif; font-size: 15px; font-weight: 400; text-transform: none; letter-spacing: normal; color: var(--el-muted-fg); }
.elza-swatch-list { margin-top: 1rem; display: flex; flex-wrap: wrap; gap: .75rem; }
.elza-swatch-btn { width: 44px; height: 44px; border-radius: 50% !important; border: 3px solid var(--el-bg); box-shadow: 0 0 0 1px rgba(37,39,31,.2); cursor: pointer; padding: 0; transition: transform 200ms var(--el-ease), border-color 200ms var(--el-ease); }
.elza-swatch-btn:hover { transform: scale(1.05); }
.elza-swatch-btn.is-active { transform: scale(1.1); border-color: var(--el-olive); box-shadow: none; }

/* WooCommerce's native variation <select> table stays in the DOM (its own
   JS, wc-add-to-cart-variation, still drives Add to Cart/price/stock logic)
   but is visually replaced by the swatch picker above — see
   single-product.php's inline <script> docblock for why it's hidden with
   CSS rather than removed. */
.elza-product-details table.variations,
.elza-product-details .reset_variations_alert,
.elza-product-details a.reset_variations { display: none; }
.elza-product-details .woocommerce-variation-description { display: none; }

/* Task 17 fix: the client decided to show the real WooCommerce price
   (previously hidden via `display:none` above, to match the source app's
   enquiry-only design where no price was ever shown -- see
   single-product.php's now-corrected docblock). The client sets real
   per-product prices themselves in wp-admin; this CSS only makes whatever
   price is set actually render and sit correctly in this page's layout --
   no price value is hardcoded here.
   Two distinct WooCommerce price elements now render on this page (see
   single-product.php's own docblock at the `woocommerce_template_single_price()`
   call for the full reasoning):
     1. `p.price` (direct child of `.elza-product-details-inner`) -- the
        product's own base price, printed once via
        `woocommerce_template_single_price()`. Always present.
     2. `.woocommerce-variation-price .price` -- WooCommerce's own
        AJAX-populated per-variation price (inside `.single_variation_wrap`,
        alongside the add-to-cart button). Only actually has content when a
        variation's price differs from the base price above -- empty for
        every product in this catalog today, but left in place (rather than
        removed) so it starts working on its own the moment the client ever
        prices one colour differently from the others.
   Both share the same typography; only their placement in the page differs,
   so one rule set targets `.price` generically. */
.elza-product-details-inner > p.price { margin: 1rem 0 0; }
.elza-product-details .woocommerce-variation-price { margin: 0 0 .25rem; }
.elza-product-details .price {
  font-family: 'Raleway', sans-serif;
  font-size: 1.75rem;
  font-style: normal;
  color: var(--el-fg);
}
.elza-product-details .price ins { text-decoration: none; }
.elza-product-details .price del { opacity: .5; margin-right: .5em; }

.elza-product-details .single_variation_wrap { margin-top: 2.25rem; }
.elza-product-details form.cart { margin: 0; }
.elza-product-details .woocommerce-variation-add-to-cart,
.elza-product-details .quantity { margin: 0; }
.elza-product-details .woocommerce-variation-add-to-cart.variations_button { display: flex; flex-direction: column; gap: .75rem; }
@media (min-width: 640px) { .elza-product-details .woocommerce-variation-add-to-cart.variations_button { flex-direction: row; } }

.elza-product-details .quantity { display: flex; align-items: center; justify-content: space-between; height: 56px; border: 1px solid rgba(37,39,31,.18); padding: 0 .5rem; position: relative; }
@media (min-width: 640px) { .elza-product-details .quantity { width: 9rem; flex: 0 0 9rem; } }
.elza-product-details .quantity .elza-qty-minus,
.elza-product-details .quantity .elza-qty-plus { border: 0; background: none; padding: .75rem; font-size: 1rem; line-height: 1; cursor: pointer; color: inherit; }
.elza-product-details .quantity input.qty { width: 3rem; border: 0 !important; background: none; text-align: center; font-family: 'Jost', sans-serif; padding: 0; -moz-appearance: textfield; }
.elza-product-details .quantity input.qty::-webkit-outer-spin-button,
.elza-product-details .quantity input.qty::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

/* Task 16 fix: found via Step 6's side-by-side visual diff -- this button
   only ever had layout properties (flex/height/gap), never the project's
   actual button treatment, so it rendered as a plain unstyled link-button
   instead of matching every other CTA/submit button on the site. Not a
   Divi module (WooCommerce's own template output, no `et_pb_button`
   class), so it gets none of Divi's own button chrome either -- same
   situation as `.elza-contact-submit` (Task 14), whose already-approved
   self-contained button treatment is reused verbatim here rather than
   inventing new values. */
.elza-product-details .single_add_to_cart_button {
  flex: 1; height: 56px; display: inline-flex; align-items: center; justify-content: center; gap: .6em;
  background: var(--el-primary) !important; color: var(--el-bg-alt) !important; border: 1px solid var(--el-primary) !important;
  font-family: 'Raleway', sans-serif; font-weight: 400; font-size: 17px; line-height: 1.62; text-transform: uppercase; letter-spacing: .14em;
  cursor: pointer; transition: background-color 200ms, border-color 200ms;
}
.elza-product-details .single_add_to_cart_button:hover { background: var(--el-olive) !important; border-color: var(--el-olive) !important; }
.elza-product-details .single_add_to_cart_button.disabled { opacity: .5; cursor: not-allowed; }
.elza-product-details .single_add_to_cart_button::before { content: "\1F6CD"; font-size: 1.05em; }

.elza-price-note { margin-top: 1.25rem; line-height: 1.625; color: var(--el-muted-fg); }

/* --- Section 2: "You may also love" related products --- */
.elza-related-section { border-top: 1px solid rgba(37,39,31,.12); background: var(--el-bg-alt); padding: 5rem 1.5rem; }
@media (min-width: 768px) { .elza-related-section { padding: 6.5rem 3rem; } }
@media (min-width: 980px) { .elza-related-section { padding-left: 4rem; padding-right: 4rem; } }

.elza-related-header { margin-bottom: 3rem; display: flex; flex-direction: column; gap: 1.25rem; }
@media (min-width: 768px) { .elza-related-header { flex-direction: row; align-items: flex-end; justify-content: space-between; } }
.elza-related-eyebrow { color: var(--el-olive-dark); }
.elza-related-heading { margin-top: 1rem; font-size: 2.875rem; margin-bottom: 0; }
@media (min-width: 768px) { .elza-related-heading { font-size: 4.375rem; } }
.elza-related-heading .font-editorial { color: var(--el-terracotta); }

.elza-related-grid { display: grid; gap: 1.25rem; grid-template-columns: 1fr; }
@media (min-width: 768px) { .elza-related-grid { grid-template-columns: repeat(3, 1fr); } }

.elza-related-card { display: block; border: 1px solid rgba(37,39,31,.12); text-decoration: none; color: inherit; }
.elza-related-card-image img { aspect-ratio: 4 / 5; width: 100%; object-fit: cover; display: block; }
.elza-related-card-body { padding: 1.25rem; }
.elza-related-card-collection { color: var(--el-muted-fg); }
.elza-related-card-name { margin-top: .5rem; font-size: 1.5rem; margin-bottom: 0; }

/* ==========================================================================
   Task 13: Our Story page (class-page-story.php)

   Row-width rule: every .et_pb_row-targeting width/max-width selector below
   carries !important on both properties (Task 11's fix-round finding —
   Divi's own force-enqueued style-static.min.css has a higher-specificity
   `.et_pb_row:not([class*=et_flex_column])` rule that otherwise wins the
   cascade regardless of source order).

   Dark-background text: sections 1 and 4 use Story.tsx's literal
   `text-white` (exactly #fff), so their et_pb_text modules carry
   `elza-cta-text` (Task 3's marker class, forces `color:#fff !important`
   on the module + all descendants) as the Divi-5-dynamic-CSS-dropout
   backstop the class was built for. Every colour-differing child inside
   those two sections (eyebrows at partial white opacity, italic accent
   spans, subheads) gets its own scoped class + `!important`, declared here
   (after the shared `.elza-cta-text` rule near the top of this file) so it
   wins the specificity tie on source order. Section 9 instead uses
   Story.tsx's literal `text-[#F8F5EF]` (var(--el-bg), a warm off-white,
   NOT pure white) — `elza-cta-text` is deliberately NOT applied there
   (it would silently shift that exact colour to #fff); section 9 instead
   follows Home/Shop's own already-shipped `color: var(--el-bg)` convention.
   ========================================================================== */

/* --- Section 1: hero --- */
.elza-story-hero { position: relative; overflow: hidden; display: flex; flex-direction: column; justify-content: flex-end; min-height: 78vh; background: var(--el-primary) !important; color: #fff; padding: 4rem 1.5rem; }
@media (min-width: 768px) { .elza-story-hero { padding: 5rem 3rem; } }
@media (min-width: 980px) { .elza-story-hero { padding-left: 4rem; padding-right: 4rem; } }
.elza-story-hero::before { content: ""; position: absolute; inset: 0; z-index: 1; background: linear-gradient(90deg, rgba(24,27,21,.78) 0%, rgba(24,27,21,.32) 62%, rgba(24,27,21,.18) 100%); pointer-events: none; }

/* NEW finding (Task 13, not previously documented): the same
   `.et_pb_row:not([class*=et_flex_column])` rule that forces width/max-width
   (see divi5-syntax-reference.md's Task 11 addendum) ALSO sets
   `position:relative` at specificity (0,2,0) — beating a plain single-class
   `position:absolute` override (0,1,0) regardless of source order or
   !important on the width properties alone. Confirmed via a real headless-
   Chromium getBoundingClientRect() diagnostic: without `!important` here
   too, this row computed position:relative (not absolute), collapsing to
   ~53px of auto content height instead of filling the hero via inset:0,
   which made the hero background image invisible. `position` needs
   `!important` here for the same reason width/max-width already do — see
   task-13-report.md for full repro; Home's `.elza-hero-bg-row`/
   `.elza-hero-cue-row` and Shop's `.elza-shop-hero-bg-row` use the
   identical position:absolute-on-a-row pattern without this !important and
   are very likely affected the same way (flagged for follow-up, not fixed
   here — out of this task's scope). */
.elza-story-hero-bg-row { position: absolute !important; inset: 0; z-index: 0; width: 100% !important; max-width: none !important; margin: 0; }
.elza-story-hero-bg-row .et_pb_column { padding: 0; position: relative; width: 100% !important; height: 100% !important; float: none !important; }
.elza-story-hero-bg-image { position: absolute; inset: 0; margin: 0; }
.elza-story-hero-bg-image img { width: 100%; height: 100%; object-fit: cover; display: block; }

.elza-story-hero-content-row { position: relative; z-index: 2; width: 100% !important; max-width: none !important; margin: 0; }
.elza-story-hero-content-row .et_pb_column { padding: 0; margin: 0 !important; }
/* Story.tsx's hero <section> is `flex ... items-end`, so the Reveal that
   wraps the hero copy is a flex ITEM and shrink-wraps its content (measured
   620px on the live app) rather than filling the 64rem cap. */
.elza-story-hero-inner { position: relative; width: fit-content; max-width: 64rem; }
.elza-story-hero-eyebrow { color: rgba(255,255,255,.7) !important; }
.elza-story-hero-heading { margin-top: 1.25rem; font-size: clamp(4.075rem, 8vw, 8.675rem); text-transform: uppercase; line-height: .82; letter-spacing: -.05em; }
.elza-story-hero-heading-accent { text-transform: none; letter-spacing: normal; color: var(--el-secondary) !important; }
.elza-story-hero-sub { margin-top: 1.75rem; max-width: 36rem; font-size: 1.25rem; line-height: 1.625; color: rgba(255,255,255,.78) !important; }

/* --- Section 2: intro --- */
.elza-story-intro-section { background: var(--el-bg-alt); padding: 5rem 1.5rem; }
@media (min-width: 768px) { .elza-story-intro-section { padding: 7rem 3rem; } }
@media (min-width: 980px) { .elza-story-intro-section { padding-left: 4rem; padding-right: 4rem; } }
.elza-story-intro-row { width: 100% !important; max-width: 1280px !important; margin: 0 auto; display: flex; flex-wrap: wrap; gap: 3.5rem; }
@media (min-width: 980px) { .elza-story-intro-row { flex-wrap: nowrap; gap: 6rem; } }
.elza-story-intro-row .et_pb_column { padding: 0; margin: 0 !important; }
.elza-story-intro-heading-col, .elza-story-intro-copy-col { flex: 0 0 100%; max-width: 100%; }
/* Final-review fix (Important, 2026-09-23): same arithmetic bug as
   `.elza-intro-row` above and `.elza-contact-faq-row` -- 36% + 64% + this
   row's own 6rem gap (line 689) exceeded 100%, causing real horizontal
   overflow at desktop widths. Fixed with the same precise calc() pattern:
   half the 6rem gap (3rem) subtracted from each side. */
@media (min-width: 980px) {
  .elza-story-intro-heading-col { flex: 0 0 calc((100% - 6rem) * .36); max-width: calc((100% - 6rem) * .36); }
  .elza-story-intro-copy-col { flex: 0 0 calc((100% - 6rem) * .64); max-width: calc((100% - 6rem) * .64); }
}
.elza-story-intro-eyebrow { color: var(--el-olive-dark); }
.elza-story-intro-heading { margin-top: 1.25rem; font-size: 2.875rem; line-height: .9; }
@media (min-width: 768px) { .elza-story-intro-heading { font-size: 4.375rem; } }
.elza-story-intro-heading-accent { color: var(--el-terracotta); }
/* Task 18: `!important` added on font-size/line-height here (and on
   .elza-story-why-copy-col .et_pb_text below) as the second half of the
   base-rule fix documented at the top of this file. The base
   `body, .et_pb_text, .et-l` rule now needs `!important` on both properties
   to beat Divi's et-vb-global-fonts block; once it has it, an
   `!important`-free rule loses to it regardless of being more specific,
   because any `!important` declaration outranks every non-`!important` one.
   So every more-specific override of those two properties needs `!important`
   too -- the established pattern from this project's heading-colour fix. */
.elza-story-intro-copy-col .et_pb_text { font-size: 1.25rem !important; line-height: 1.625 !important; color: rgba(37,39,31,.68); }
.elza-story-intro-copy-col p { margin: 0 0 1.5rem; }
.elza-story-intro-copy-col p:last-child { margin-bottom: 0; }

/* --- Section 3: founder story (full-bleed image/copy split) --- */
.elza-story-founder-section { background: var(--el-taupe) !important; }
.elza-story-founder-row { display: flex; flex-wrap: wrap; width: 100% !important; max-width: none !important; margin: 0; }
.elza-story-founder-row .et_pb_column { padding: 0; margin: 0 !important; }
.elza-story-founder-image-col, .elza-story-founder-copy-col { flex: 0 0 100%; max-width: 100%; }
@media (min-width: 980px) {
  .elza-story-founder-image-col { flex: 0 0 47.5%; max-width: 47.5%; }
  .elza-story-founder-copy-col { flex: 0 0 52.5%; max-width: 52.5%; }
}
.elza-story-founder-image { min-height: 65vh; }
@media (min-width: 980px) { .elza-story-founder-image { min-height: 830px; } }
.elza-story-founder-image img { height: 100%; min-height: 65vh; width: 100%; object-fit: cover; display: block; }
@media (min-width: 980px) { .elza-story-founder-image img { min-height: 830px; } }

.elza-story-founder-copy-col { display: flex; align-items: center; padding: 5rem 1.75rem !important; }
@media (min-width: 768px) { .elza-story-founder-copy-col { padding-left: 4rem !important; padding-right: 4rem !important; } }
@media (min-width: 980px) { .elza-story-founder-copy-col { padding-left: 8vw !important; padding-right: 8vw !important; } }
.elza-story-founder-eyebrow { color: var(--el-taupe-dark); }
.elza-story-founder-heading { margin-top: 1.25rem; font-size: clamp(3.375rem, 6vw, 6.875rem); line-height: .88; }
.elza-story-founder-heading-accent { color: var(--el-terracotta); }
.elza-story-founder-body { margin-top: 2rem; max-width: 36rem; }
.elza-story-founder-body > p, .elza-story-founder-body > blockquote { margin: 0 0 1.25rem; }
.elza-story-founder-body > *:last-child { margin-bottom: 0; }
.elza-story-founder-body p { font-size: 1.125rem; line-height: 1.625; color: rgba(37,39,31,.68); }
/* #7c7a5e is Story.tsx's own literal blockquote-border shade — the design
   spec documents --el-taupe-dark as carrying two literal forms
   ("#6f6c52 / #7c7a5e") for this exact reason; only #6f6c52 has a
   :root custom property, so the second form is used as a direct literal
   here rather than inventing an unrequested second CSS variable. */
.elza-story-founder-quote { border-left: 1px solid #7c7a5e; padding-left: 1.5rem; font-size: 1.5rem; line-height: 1.625; color: var(--el-fg); }
/* `.elza-story-founder-body p` is (0,2,0) and sets rgba(...,.68); this
   single-class rule is (0,1,0) and lost outright. Source is
   `font-medium text-foreground` -- full-opacity ink. */
.elza-story-founder-body p.elza-story-founder-emphasis { font-weight: 500; color: var(--el-fg); }

/* --- Section 4: roles grid --- */
.elza-story-roles-section { background: var(--el-olive) !important; color: #fff; padding: 5rem 1.5rem; }
@media (min-width: 768px) { .elza-story-roles-section { padding: 6.5rem 3rem; } }
@media (min-width: 980px) { .elza-story-roles-section { padding-left: 4rem; padding-right: 4rem; } }
.elza-story-roles-row { width: 100% !important; max-width: none !important; margin: 0; }
.elza-story-roles-intro { max-width: 64rem; margin: 0 auto; text-align: center; }
.elza-story-roles-eyebrow { color: rgba(255,255,255,.65) !important; }
.elza-story-roles-heading { margin-top: 1.25rem; font-size: clamp(3.675rem, 7vw, 7.675rem); line-height: .9; }
.elza-story-roles-heading-accent { color: var(--el-secondary) !important; }
.elza-story-roles-sub { margin: 1.75rem auto 0; max-width: 42rem; font-size: 1.125rem; line-height: 1.75rem; color: rgba(255,255,255,.75) !important; }

.elza-story-roles-grid-wrap { margin-top: 3.5rem; }
.elza-story-roles-grid { max-width: 80rem; margin: 0 auto; display: grid; grid-template-columns: 1fr; border-left: 1px solid rgba(255,255,255,.2); border-top: 1px solid rgba(255,255,255,.2); }
@media (min-width: 640px) { .elza-story-roles-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 980px) { .elza-story-roles-grid { grid-template-columns: repeat(3, 1fr); } }
.elza-story-roles-item { display: flex; min-height: 10rem; align-items: center; gap: 1.25rem; border-bottom: 1px solid rgba(255,255,255,.2); border-right: 1px solid rgba(255,255,255,.2); padding: 1.75rem; }
.elza-story-roles-icon { flex-shrink: 0; width: 1.75rem; height: 1.75rem; color: var(--el-secondary) !important; }
.elza-story-roles-icon svg { width: 100%; height: 100%; }
.elza-story-roles-item h3 { font-family: 'Jost', sans-serif; font-weight: 500; font-size: 1.5rem; line-height: 1.25; margin: 0; }

/* --- Section 5: confident statement --- */
.elza-story-confident-section { background: var(--el-secondary) !important; text-align: center; padding: 5rem 1.5rem; }
@media (min-width: 768px) { .elza-story-confident-section { padding-top: 7rem; padding-bottom: 7rem; } }
.elza-story-confident-row { width: 100% !important; max-width: none !important; margin: 0; }
.elza-story-confident-eyebrow { color: var(--el-olive-dark); }
/* Divi/WordPress core's default `blockquote{border-left:5px solid;
   border-color:#2ea3f2;padding-left:20px}` (style-static.min.css) must be
   explicitly reset here — Story.tsx's "Confident." statement is a bare
   blockquote with no border, unlike section 3's founder pull-quote (which
   DOES want a border, styled separately on .elza-story-founder-quote). */
.elza-story-confident-statement { margin: 1.5rem auto 0; max-width: 64rem; border: none; padding-left: 0; font-family: 'Raleway', sans-serif; font-style: italic; font-weight: 400; font-size: clamp(5rem, 12vw, 12rem); line-height: .78; color: var(--el-terracotta); }
.elza-story-confident-sub { margin: 2.5rem auto 0; max-width: 42rem; font-size: 1.25rem; line-height: 1.625; color: rgba(37,39,31,.65); }

/* --- Section 6: philosophy (full-bleed split, image side reversed) ---
   `order` (not DOM position) flips visual side, matching Story.tsx's own
   order-2/lg:order-1 (copy) + order-1/lg:order-2 (image) — see
   class-page-story.php's section_philosophy() docblock. */
.elza-story-philosophy-section { background: var(--el-bg-alt); }
.elza-story-philosophy-row { display: flex; flex-wrap: wrap; width: 100% !important; max-width: none !important; margin: 0; }
.elza-story-philosophy-row .et_pb_column { padding: 0; margin: 0 !important; }
.elza-story-philosophy-copy-col, .elza-story-philosophy-image-col { flex: 0 0 100%; max-width: 100%; }
.elza-story-philosophy-copy-col { order: 2; }
.elza-story-philosophy-image-col { order: 1; min-height: 65vh; }
@media (min-width: 980px) {
  .elza-story-philosophy-row { align-items: stretch; }
  .elza-story-philosophy-copy-col { flex: 0 0 50%; max-width: 50%; order: 1; min-height: 820px; }
  .elza-story-philosophy-image-col { flex: 0 0 50%; max-width: 50%; order: 2; min-height: 0; }
}
.elza-story-philosophy-copy-col { display: flex; align-items: center; padding: 5rem 1.75rem !important; }
@media (min-width: 768px) { .elza-story-philosophy-copy-col { padding-left: 4rem !important; padding-right: 4rem !important; } }
@media (min-width: 980px) { .elza-story-philosophy-copy-col { padding-left: 8vw !important; padding-right: 8vw !important; } }
.elza-story-philosophy-image { height: 100%; }
.elza-story-philosophy-image img { height: 100%; width: 100%; min-height: 65vh; object-fit: cover; display: block; }
.elza-story-philosophy-eyebrow { color: var(--el-olive-dark); }
.elza-story-philosophy-heading { margin-top: 1.25rem; font-size: clamp(3.375rem, 6vw, 6.875rem); line-height: .88; }
.elza-story-philosophy-heading-accent { color: var(--el-terracotta); }
.elza-story-philosophy-body { margin-top: 2rem; max-width: 36rem; }
.elza-story-philosophy-body p { margin: 0 0 1.25rem; font-size: 1.125rem; line-height: 1.625; color: rgba(37,39,31,.68); }
.elza-story-philosophy-body p:last-child { margin-bottom: 0; }

/* --- Section 7: why handmade (heading/copy split + 3-pillar row) --- */
.elza-story-why-section { border-top: 1px solid rgba(37,39,31,.12); background: var(--el-bg); padding: 5rem 1.5rem; }
@media (min-width: 768px) { .elza-story-why-section { padding: 6.5rem 3rem; } }
@media (min-width: 980px) { .elza-story-why-section { padding-left: 4rem; padding-right: 4rem; } }

.elza-story-why-heading-row { width: 100% !important; max-width: 1280px !important; margin: 0 auto; display: flex; flex-wrap: wrap; gap: 3rem; }
.elza-story-why-heading-row .et_pb_column { padding: 0; margin: 0 !important; }
.elza-story-why-heading-col, .elza-story-why-copy-col { flex: 0 0 100%; max-width: 100%; }
/* Task 16 review fix: same flex-basis+gap-over-100% bug as
   .elza-contact-faq-row (see that rule's docblock below for full root
   cause) -- without `flex-wrap: nowrap` this was silently stacking into a
   single column at desktop widths. Fixed with the precise calc()
   flex-basis form (half the row's gap subtracted from each side) rather
   than plain nowrap-only, so the two columns' required width sums to
   exactly 100% instead of relying on section padding to silently absorb
   the gap overflow. */
@media (min-width: 980px) {
  .elza-story-why-heading-row { flex-wrap: nowrap; }
  .elza-story-why-heading-col { flex: 0 0 calc((100% - 3rem) * .425); max-width: calc((100% - 3rem) * .425); }
  .elza-story-why-copy-col { flex: 0 0 calc((100% - 3rem) * .575); max-width: calc((100% - 3rem) * .575); }
}
.elza-story-why-eyebrow { color: var(--el-olive-dark); }
.elza-story-why-heading { margin-top: 1.25rem; font-size: 2.875rem; line-height: .92; }
@media (min-width: 768px) { .elza-story-why-heading { font-size: 4.375rem; } }
.elza-story-why-heading-accent { color: var(--el-terracotta); }
.elza-story-why-copy-col .et_pb_text { font-size: 1.25rem !important; line-height: 1.625 !important; color: rgba(37,39,31,.68); }
.elza-story-why-copy-col p { margin: 0 0 1.25rem; }
.elza-story-why-copy-col p:last-child { margin-bottom: 0; }
.elza-story-why-strong { font-weight: 500; color: var(--el-fg); }

.elza-story-why-pillar-row { width: 100% !important; max-width: 1280px !important; margin: 0 auto; }
.elza-story-why-pillars-wrap { margin-top: 4rem; }
.elza-story-why-pillars { display: grid; grid-template-columns: 1fr; border-top: 1px solid rgba(37,39,31,.14); border-bottom: 1px solid rgba(37,39,31,.14); }
@media (min-width: 768px) { .elza-story-why-pillars { grid-template-columns: repeat(3, 1fr); } }
.elza-story-why-pillar { border-bottom: 1px solid rgba(37,39,31,.14); padding: 1.5rem 1.5rem; }
.elza-story-why-pillar:last-child { border-bottom: none; }
@media (min-width: 768px) {
  .elza-story-why-pillar { border-bottom: none; border-right: 1px solid rgba(37,39,31,.14); }
  .elza-story-why-pillar:last-child { border-right: none; }
}
.elza-story-why-pillar h3 { font-family: 'Jost', sans-serif; font-weight: 500; font-size: 1.875rem; line-height: 2.25rem; margin: 0; }
.elza-story-why-pillar p { margin-top: .5rem; color: var(--el-muted-fg); }

/* --- Section 8: responsible making --- */
.elza-story-responsible-section { background: var(--el-taupe) !important; padding: 5rem 1.5rem; }
@media (min-width: 768px) { .elza-story-responsible-section { padding: 6.5rem 3rem; } }
@media (min-width: 980px) { .elza-story-responsible-section { padding-left: 4rem; padding-right: 4rem; } }
.elza-story-responsible-row { width: 100% !important; max-width: 1280px !important; margin: 0 auto; display: flex; flex-wrap: wrap; gap: 3.5rem; }
.elza-story-responsible-row .et_pb_column { padding: 0; margin: 0 !important; }
.elza-story-responsible-heading-col, .elza-story-responsible-cards-col { flex: 0 0 100%; max-width: 100%; }
/* Task 16 review fix: same flex-basis+gap-over-100% bug as
   .elza-contact-faq-row -- see that rule's docblock for full root cause.
   calc() flex-basis (half the row's 3.5rem gap subtracted from each side)
   used instead of nowrap-only so the math is exact. */
@media (min-width: 980px) {
  .elza-story-responsible-row { flex-wrap: nowrap; }
  .elza-story-responsible-heading-col { flex: 0 0 calc((100% - 3.5rem) * .375); max-width: calc((100% - 3.5rem) * .375); }
  .elza-story-responsible-cards-col { flex: 0 0 calc((100% - 3.5rem) * .625); max-width: calc((100% - 3.5rem) * .625); }
}
.elza-story-responsible-eyebrow { color: var(--el-taupe-dark); }
.elza-story-responsible-heading { margin-top: 1.25rem; font-size: 2.875rem; line-height: .92; }
@media (min-width: 768px) { .elza-story-responsible-heading { font-size: 3.625rem; } }
.elza-story-responsible-heading-accent { color: var(--el-terracotta); }

.elza-story-responsible-grid { display: grid; gap: 2rem; grid-template-columns: 1fr; }
@media (min-width: 640px) { .elza-story-responsible-grid { grid-template-columns: repeat(2, 1fr); } }
.elza-story-responsible-card { border-top: 1px solid rgba(37,39,31,.2); padding-top: 1.25rem; }
.elza-story-responsible-card h3 { font-family: 'Jost', sans-serif; font-weight: 500; font-size: 1.5rem; line-height: 2rem; margin: 0; }
.elza-story-responsible-card p { margin-top: .75rem; font-size: 1.125rem; line-height: 1.75rem; color: rgba(37,39,31,.65); }

/* --- Section 9: closing promise band ---
   text: var(--el-bg) (#F8F5EF, Story.tsx's literal text-[#F8F5EF]) — NOT
   #fff and NOT elza-cta-text, see class-header docblock above. */
.elza-story-promise-section { background: var(--el-primary-alt) !important; color: var(--el-bg); padding: 5rem 1.5rem; }
@media (min-width: 768px) { .elza-story-promise-section { padding: 6.5rem 3rem; } }
@media (min-width: 980px) { .elza-story-promise-section { padding-left: 4rem; padding-right: 4rem; } }
.elza-story-promise-row { width: 100% !important; max-width: 1280px !important; margin: 0 auto; display: flex; flex-wrap: wrap; gap: 3.5rem; }
.elza-story-promise-row .et_pb_column { padding: 0; margin: 0 !important; }
.elza-story-promise-heading-col, .elza-story-promise-list-col { flex: 0 0 100%; max-width: 100%; }
/* Task 16 review fix: same flex-basis+gap-over-100% bug as
   .elza-contact-faq-row -- see that rule's docblock for full root cause.
   calc() flex-basis (half the row's 3.5rem gap subtracted from each side)
   used instead of nowrap-only so the math is exact. */
@media (min-width: 980px) {
  .elza-story-promise-row { flex-wrap: nowrap; }
  .elza-story-promise-heading-col { flex: 0 0 calc((100% - 3.5rem) * .4); max-width: calc((100% - 3.5rem) * .4); }
  .elza-story-promise-list-col { flex: 0 0 calc((100% - 3.5rem) * .6); max-width: calc((100% - 3.5rem) * .6); }
}
/* Gotcha #4 (dark-section text near-black, per project CLAUDE.md) — full
   root cause, confirmed via a real headless-Chromium ancestor-chain
   getComputedStyle() walk (not just a specificity read): Divi auto-adds
   `et_pb_bg_layout_light` to EVERY et_pb_text module whose
   `background_layout` attribute is unset (true for every module on this
   page — light is the module's own default), and style-static.min.css
   has a `.et_pb_bg_layout_light ... h2{color:#333}`-family rule that
   directly targets the HEADING ITSELF, not just its .et_pb_text ancestor.
   A non-!important override on an ancestor (what was here before) can
   never win against a rule that directly targets the descendant element —
   inheritance is always the lowest-priority source of a computed value,
   full stop, regardless of the ancestor selector's specificity. This is
   the same mechanism `elza-cta-text` (Task 3) was built to defeat via
   `!important` on `.elza-cta-text *`; section 9 needs the identical
   `!important`-on-all-descendants treatment, just with var(--el-bg)
   instead of literal #fff (see class-page-story.php's docblock for why
   elza-cta-text itself isn't reused verbatim here). Every colour-differing
   child below (accent span, eyebrow, promise-line) now also carries
   `!important` — without it here too, each would lose outright to this
   blanket rule regardless of its own selector specificity, per the same
   any-!important-beats-no-!important rule.

   Review fix (Critical #1, 2026-09-22): the backstop below was originally
   written as the two-class ancestor form
   `.elza-story-promise-section .et_pb_text, .elza-story-promise-section
   .et_pb_text *` — specificity (0,2,0). When BOTH a rule and its override
   carry `!important`, specificity is compared first (source order is only
   the tie-breaker), so that (0,2,0) backstop was beating the single-class
   (0,1,0) `!important` child overrides below (eyebrow/heading-accent/
   promise-line) regardless of where they sit in the file — flattening all
   three to the one backstop colour instead of their intended distinct
   colours. Fixed by moving the backstop onto a dedicated single class
   (`elza-story-promise-text`, applied via `module_class` on both
   `[et_pb_text]` calls in class-page-story.php's section_promise()) so it
   matches `.elza-cta-text`'s working (0,1,0) pattern exactly — the
   trailing `*` (universal selector) contributes zero specificity, so
   `.elza-story-promise-text *` stays at (0,1,0), same as `.elza-story-
   promise-text` itself. The child overrides, already (0,1,0) with
   `!important` and already positioned after this rule in the file, now
   correctly win via source order on equal specificity. */
.elza-story-promise-text,
.elza-story-promise-text * { color: var(--el-bg) !important; }
.elza-story-promise-eyebrow { color: var(--el-accent) !important; }
.elza-story-promise-heading { margin-top: 1.25rem; font-size: 2.875rem; line-height: .92; }
@media (min-width: 768px) { .elza-story-promise-heading { font-size: 4.375rem; } }
.elza-story-promise-heading-accent { color: var(--el-secondary) !important; }

.elza-story-promise-list { border-top: 1px solid rgba(255,255,255,.15); }
.elza-story-promise-line { border-bottom: 1px solid rgba(255,255,255,.15); padding: 1.25rem 0; font-size: 1.25rem; line-height: 1.625; color: rgba(255,255,255,.72) !important; margin: 0; }

/* ==========================================================================
   Task 14: Contact page (class-page-contact.php)
   ========================================================================== */

/* .thread-field — project-wide reusable motif (design spec §4: "faint
   rotated ring/shadow decoration"). Pulled verbatim from
   elza-website/client/src/index.css lines 105-106 + its 1023px breakpoint
   override (line 134). First introduced here (Contact hero is its first
   use in the built site) — Home/Shop/Story didn't need it. SiteShell.tsx's
   Footer also uses it on its top band, but that file (class-footer-
   content.php) is Task 8's already-shipped/reviewed output and is
   deliberately NOT touched here to avoid re-opening approved work; only
   this page's own hero picks the class up via module_class. */
.thread-field { position: relative; overflow: hidden; }
.thread-field::after { position: absolute; top: 50%; right: -8%; width: 44%; height: 150%; content: ""; border: 1px solid rgba(220,181,126,.3); border-radius: 50%; transform: translateY(-50%) rotate(-15deg); box-shadow: -28px 0 0 -27px rgba(220,181,126,.45), -56px 0 0 -55px rgba(220,181,126,.38); pointer-events: none; }
@media (max-width: 1023px) { .thread-field::after { right: -28%; width: 70%; } }

/* --- Form-control primitives (design spec §4 typography, project-wide
   reusable) — pulled verbatim from elza-website/client/src/index.css
   lines 108-130. First use is this page's contact form; no earlier task
   needed a real <input>/<select>/<textarea>. --- */
.field-label { display: block; font-family: 'Jost', sans-serif; font-size: 14px; font-weight: 500; letter-spacing: .14em; line-height: 1.35; text-transform: uppercase; }
.field-label > span { color: var(--el-muted-fg); font-family: 'Raleway', sans-serif; font-weight: 400; text-transform: none; letter-spacing: 0; }
.field-label .form-control { margin-top: .7rem; text-transform: none; letter-spacing: 0; }
.form-control {
  width: 100%;
  min-height: 56px;
  border: 1px solid rgba(37, 39, 31, .22) !important;
  border-radius: 0 !important;
  background: rgba(255, 255, 255, .72) !important;
  color: var(--el-fg) !important;
  box-shadow: none !important;
  padding: .85rem 1rem !important;
  font-size: 17px !important;
  line-height: 1.45;
  font-family: 'Raleway', sans-serif;
}
textarea.form-control { min-height: 160px; resize: vertical; }
select.form-control { appearance: auto; cursor: pointer; }
.form-control::placeholder { color: rgba(37, 39, 31, .48); opacity: 1; }
.form-control:hover { border-color: rgba(37, 39, 31, .42) !important; background: #fff !important; }
.form-control:focus-visible { border-color: #777557 !important; background: #fff !important; box-shadow: 0 0 0 3px rgba(153, 149, 114, .22) !important; }

/* --- Section 1: hero --- */
.elza-contact-hero { background: var(--el-secondary) !important; text-align: center; padding: 6rem 1.5rem; }
@media (min-width: 768px) { .elza-contact-hero { padding: 8rem 3rem; } }
@media (min-width: 980px) { .elza-contact-hero { padding-left: 4rem; padding-right: 4rem; } }
.elza-contact-hero-row { width: 100% !important; max-width: none !important; margin: 0; }
.elza-contact-hero-inner { max-width: 72rem; margin: 0 auto; }
.elza-contact-hero-eyebrow { color: var(--el-olive-dark); }
.elza-contact-hero-heading { margin-top: 1.25rem; text-transform: uppercase; line-height: .82; letter-spacing: -.05em; font-size: clamp(4.075rem, 8vw, 8.375rem); }
.elza-contact-hero-heading-accent { text-transform: none; letter-spacing: normal; color: var(--el-terracotta); }
.elza-contact-hero-sub { margin: 2rem auto 0; max-width: 42rem; font-size: 1.25rem; line-height: 1.625; color: rgba(37,39,31,.65); }

/* --- Section 2: info + form split (43%/57%, full-bleed, no max-width
   cap — same "full-bleed banner row" pattern as Story's founder-section;
   see divi5-syntax-reference.md's Task 8 addendum for why the split needs
   scoped nth-child-equivalent flex widths rather than Divi's own
   type="X_Y" CSS, and its Task 11 addendum for why the row override below
   needs !important on both width and max-width). --- */
.elza-contact-form-section { background: var(--el-bg-alt); }
.elza-contact-form-row { display: flex; flex-wrap: wrap; width: 100% !important; max-width: none !important; margin: 0; }
.elza-contact-form-row .et_pb_column { padding: 0; margin: 0 !important; }
.elza-contact-info-col, .elza-contact-form-col { flex: 0 0 100%; max-width: 100%; }
@media (min-width: 980px) {
  .elza-contact-info-col { flex: 0 0 43%; max-width: 43%; }
  .elza-contact-form-col { flex: 0 0 57%; max-width: 57%; }
}
.elza-contact-info-col { display: flex; align-items: center; padding: 5rem 1.75rem !important; }
@media (min-width: 768px) { .elza-contact-info-col { padding-left: 3.5rem !important; padding-right: 3.5rem !important; } }
@media (min-width: 980px) { .elza-contact-info-col { min-height: 780px; padding-top: 0 !important; padding-bottom: 0 !important; padding-left: 7vw !important; padding-right: 7vw !important; } }
.elza-contact-info-eyebrow { color: var(--el-olive-dark); }
.elza-contact-info-heading { margin-top: 1.25rem; max-width: 36rem; font-size: clamp(3.175rem, 5.5vw, 5.875rem); line-height: .9; }
.elza-contact-info-heading-accent { color: var(--el-terracotta); }
.elza-contact-info-copy { margin-top: 1.75rem; max-width: 32rem; font-size: 1.125rem; line-height: 1.625; color: rgba(37,39,31,.65); }
.elza-contact-info-list { margin-top: 2.5rem; border-top: 1px solid rgba(37,39,31,.14); }
.elza-contact-info-row { display: flex; align-items: center; gap: 1rem; border-bottom: 1px solid rgba(37,39,31,.14); padding: 1.25rem 0; }
.elza-contact-info-icon { flex-shrink: 0; display: inline-block; width: 1.25rem; height: 1.25rem; color: var(--el-olive-dark); }
.elza-contact-info-icon svg { width: 100%; height: 100%; }
.elza-contact-info-label { color: var(--el-muted-fg); }
.elza-contact-info-value { margin: .25rem 0 0; }

.elza-contact-form-col { background: var(--el-taupe); display: flex; align-items: center; padding: 4rem 1.5rem !important; }
@media (min-width: 768px) { .elza-contact-form-col { padding-left: 3.5rem !important; padding-right: 3.5rem !important; } }
@media (min-width: 980px) { .elza-contact-form-col { padding-left: 7vw !important; padding-right: 7vw !important; } }
.elza-contact-form-wrap { width: 100%; }
.elza-contact-form { display: flex; flex-direction: column; gap: 1.25rem; }
.elza-contact-form-eyebrow { color: var(--el-taupe-dark); }
.elza-contact-field-row { display: grid; gap: 1.25rem; grid-template-columns: 1fr; }
@media (min-width: 768px) { .elza-contact-field-row { grid-template-columns: repeat(2, 1fr); } }
/* ==========================================================================
   Task 18 -- the source app's `button { font: inherit }` rule.

   elza-website/client/src/index.css declares, OUTSIDE any @layer:
       button, input, textarea, select { font: inherit; }
   Tailwind v4 puts all of its own utilities inside `@layer utilities`, and
   an UNLAYERED rule beats every layered rule regardless of specificity. So
   on real <button> elements the `font` shorthand wipes out the Button
   component's own `text-[14px] font-semibold` utilities and the element
   falls back to the inherited body font: 17px / weight 400 / line-height
   1.62 / Bodoni Moda. `letter-spacing` is NOT part of the `font` shorthand,
   so `tracking-[0.14em]` survives -- and now resolves against 17px, giving
   2.38px rather than 1.96px.

   Anchor elements are untouched by that rule, so every `<Button asChild>`
   that renders an <a> (all of Home's CTAs, the Divi [et_pb_button] modules
   here) really is 14px / 600 / 1.96px. The two genuinely differ in the
   source app, and this build has to reproduce both.

   Measured on :8600 to confirm, not inferred: Contact's "Send message"
   <button> computes 17px / 400 / 2.38px / Bodoni Moda, while Home's
   "Explore the collection" <a> computes 14px / 600 / 1.96px.

   Every rule below styling a real <button> therefore matches the inherited
   form. `.et_pb_button` (an <a>) keeps the 14px/600 form. */
.elza-contact-submit {
  display: inline-flex; align-items: center; justify-content: center; gap: .75rem;
  width: 100%; height: 3.5rem; margin-top: .5rem;
  background: var(--el-primary) !important; color: var(--el-bg-alt) !important; border: 1px solid var(--el-primary) !important;
  font-family: 'Raleway', sans-serif; font-weight: 400; font-size: 17px; line-height: 1.62; text-transform: uppercase; letter-spacing: .14em;
  cursor: pointer; transition: background-color 200ms, border-color 200ms;
}
.elza-contact-submit:hover { background: var(--el-olive) !important; border-color: var(--el-olive) !important; }
.elza-contact-submit:disabled { opacity: .5; cursor: not-allowed; }
.elza-contact-submit-arrow { width: 1rem; height: 1rem; flex-shrink: 0; }
.elza-contact-form-disclaimer { margin: 0; color: rgba(37,39,31,.58); }

.elza-contact-success { display: none; min-height: 560px; flex-direction: column; align-items: center; justify-content: center; text-align: center; }
.elza-contact-success-icon { display: grid; place-items: center; width: 4rem; height: 4rem; background: var(--el-olive); color: #fff; }
.elza-contact-success-icon svg { width: 1.75rem; height: 1.75rem; }
.elza-contact-success-heading { margin-top: 1rem; font-size: 2.875rem; }
.elza-contact-success-copy { margin-top: 1rem; max-width: 28rem; color: rgba(37,39,31,.65); }
.elza-contact-reset {
  display: inline-flex; align-items: center; justify-content: center; gap: .75rem;
  height: 3rem; padding: 0 1.5rem; margin-top: 1.75rem;
  background: transparent !important; color: var(--el-fg) !important; border: 1px solid rgba(37,39,31,.25) !important;
  font-family: 'Raleway', sans-serif; font-weight: 400; font-size: 17px; line-height: 1.62; text-transform: uppercase; letter-spacing: .14em;
  cursor: pointer; transition: background-color 200ms, border-color 200ms, color 200ms;
}
.elza-contact-reset:hover { border-color: var(--el-fg) !important; background: var(--el-fg) !important; color: var(--el-bg) !important; }

/* --- Section 3: FAQ (centered/capped max-width:1280px = Tailwind's
   max-w-7xl, .8fr/1.2fr = 40%/60% split, gap 3rem — identical ratio/
   max-width/gap to Story's promise and why-heading rows above, reused
   deliberately for consistency). --- */
.elza-contact-faq-section { background: var(--el-bg); padding: 5rem 1.5rem; }
@media (min-width: 768px) { .elza-contact-faq-section { padding: 6.5rem 3rem; } }
@media (min-width: 980px) { .elza-contact-faq-section { padding-left: 4rem; padding-right: 4rem; } }
.elza-contact-faq-row { width: 100% !important; max-width: 1280px !important; margin: 0 auto; display: flex; flex-wrap: wrap; gap: 3rem; }
.elza-contact-faq-row .et_pb_column { padding: 0; margin: 0 !important; }
.elza-contact-faq-intro-col, .elza-contact-faq-accordion-col { flex: 0 0 100%; max-width: 100%; }
/* Review fix (Critical, 2026-09-23): flex-basis 40%+60% already sums to
   100% of the row's content-box width; with `gap: 3rem` still in force,
   the two columns' required total width (40% + 60% + 3rem) exceeds 100%,
   so `flex-wrap: wrap` (needed for the mobile single-column stack below
   980px) was dropping the accordion column onto a second line even on
   desktop. Same arithmetic bug Task 13's `.elza-story-intro-row` hit and
   fixed with this exact pattern (`flex-wrap: nowrap` once the two-column
   split is active).

   Task 16 follow-up (2026-09-23): the `nowrap`-only fix above was correct
   for layout (no more stacking) but left a harmless-but-imprecise 48px
   right-edge overflow -- 40%+60%+3rem gap still exceeds the row's 100%
   content-box by exactly the gap amount, silently absorbed by the
   section's own padding with no visible defect. Replaced the plain
   percentage flex-basis with calc(40% - 1.5rem) / calc(60% - 1.5rem)
   (half the 3rem gap subtracted from each side) so the two columns' total
   required width sums to exactly 100% instead of relying on padding to
   absorb the difference. The same precise treatment was applied to the 3
   Task 13 rows that had the identical bug --
   `.elza-story-why-heading-row`, `.elza-story-responsible-row`,
   `.elza-story-promise-row` -- each using half of its own row's gap
   value. */
@media (min-width: 980px) {
  .elza-contact-faq-row { flex-wrap: nowrap; }
  .elza-contact-faq-intro-col { flex: 0 0 calc((100% - 3rem) * .4); max-width: calc((100% - 3rem) * .4); }
  .elza-contact-faq-accordion-col { flex: 0 0 calc((100% - 3rem) * .6); max-width: calc((100% - 3rem) * .6); }
}
.elza-contact-faq-icon { display: inline-block; width: 2rem; height: 2rem; color: var(--el-olive-dark); }
.elza-contact-faq-icon svg { width: 100%; height: 100%; }
.elza-contact-faq-eyebrow { margin-top: 1.5rem; color: var(--el-olive-dark); }
.elza-contact-faq-heading { margin-top: 1rem; font-size: 2.875rem; }
.elza-contact-faq-heading-accent { color: var(--el-terracotta); }

.elza-faq-accordion { border-top: 1px solid rgba(37,39,31,.15); }
.elza-faq-item { border-bottom: 1px solid rgba(37,39,31,.15); }
.elza-faq-trigger { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; padding: 1rem 0; font-family: 'Raleway', sans-serif; font-size: 17px; line-height: 1.62; font-weight: 400; cursor: pointer; list-style: none; }
.elza-faq-trigger::-webkit-details-marker { display: none; }
.elza-faq-trigger::marker { content: ""; }
.elza-faq-trigger:hover span { text-decoration: underline; }
.elza-faq-chevron { flex-shrink: 0; width: 1rem; height: 1rem; margin-top: .2rem; color: var(--el-muted-fg); transition: transform 200ms; }
.elza-faq-item[open] .elza-faq-chevron { transform: rotate(180deg); }
.elza-faq-content { padding: 0 0 1rem; }
.elza-faq-content p { margin: 0; font-size: .875rem; line-height: 1.25rem; color: var(--el-muted-fg); }
/* (AccordionContent is a <div>, not a button, so its `text-sm` really does
   apply -- 14px/20px is correct here, unlike the trigger above.) */

/* ==========================================================================
   Task 14: order-bag drawer (template-parts/order-bag-drawer.php)
   ========================================================================== */
.elza-order-bag-drawer {
  position: fixed; top: 0; right: 0; bottom: 0; width: 100%; max-width: 32rem;
  background: var(--el-bg-alt); padding: 2.25rem; overflow-y: auto;
  transform: translateX(100%); transition: transform 320ms var(--el-ease);
  z-index: 100;
}
.elza-order-bag-drawer.is-open { transform: translateX(0); }
.elza-drawer-close { position: absolute; top: 1.5rem; right: 1.5rem; width: 2.5rem; height: 2.5rem; display: grid; place-items: center; font-size: 1.5rem; line-height: 1; background: none; border: 1px solid rgba(37,39,31,.18); cursor: pointer; }
.elza-drawer-title { font-size: 2.25rem; font-weight: 500; margin: 0; }
.elza-drawer-subtitle { margin-top: .5rem; color: var(--el-muted-fg); }

.elza-drawer-empty { display: flex; min-height: 65vh; flex-direction: column; align-items: center; justify-content: center; text-align: center; }
.elza-drawer-empty-heading { font-size: 1.75rem; margin: 1.25rem 0 0; }
.elza-drawer-empty-copy { margin-top: .75rem; max-width: 20rem; color: var(--el-muted-fg); }
.elza-drawer-empty-cta { display: inline-block; margin-top: 1.75rem; padding: .9rem 1.75rem; font-family: 'Jost', sans-serif; font-weight: 600; font-size: 14px; text-transform: uppercase; letter-spacing: .14em; text-decoration: none; }

.elza-drawer-items { margin-top: 2rem; }
.elza-drawer-item { display: grid; grid-template-columns: 94px 1fr; gap: 1rem; border-bottom: 1px solid rgba(37,39,31,.12); padding-bottom: 1.5rem; margin-bottom: 1.5rem; }
.elza-drawer-item img { aspect-ratio: 4/5; width: 100%; object-fit: cover; display: block; }
.elza-drawer-item-body { display: flex; flex-direction: column; justify-content: space-between; }
.elza-drawer-item-top { display: flex; align-items: flex-start; justify-content: space-between; gap: .75rem; }
.elza-drawer-item-name { font-size: 1.25rem; line-height: 1.25; margin: 0; }
.elza-drawer-remove { flex-shrink: 0; background: none; border: none; padding: .25rem; color: var(--el-muted-fg); cursor: pointer; font-size: 1.1rem; line-height: 1; }
.elza-drawer-remove:hover { color: var(--el-fg); }
.elza-drawer-colour { margin: .25rem 0 0; font-family: 'Jost', sans-serif; font-size: 13px; text-transform: uppercase; letter-spacing: .12em; color: var(--el-muted-fg); font-weight: 500; }
.elza-qty-stepper { display: inline-flex; align-items: center; border: 1px solid rgba(37,39,31,.18); width: fit-content; margin-top: .5rem; }
.elza-qty-stepper button { padding: .5rem .75rem; background: none; border: none; cursor: pointer; }
.elza-qty-stepper span { min-width: 2rem; text-align: center; font-size: .875rem; }

.elza-drawer-checkout { border-top: 1px solid rgba(37,39,31,.12); padding-top: 1.5rem; }
.elza-drawer-checkout p { margin: 0; color: var(--el-muted-fg); }
.elza-drawer-checkout-cta { display: block; text-align: center; margin-top: 1.25rem; padding: 1rem; font-family: 'Jost', sans-serif; font-weight: 600; font-size: 14px; text-transform: uppercase; letter-spacing: .14em; text-decoration: none; }

/* ==========================================================================
   Checkout-wizard pass (2026-09-25, explicit client request): 2-step
   checkout ported from Tshwane Leather's own wizard (same structural
   mechanism -- one real <form>, JS-only step toggling -- see
   woocommerce/checkout/form-checkout.php and class-checkout.php's
   docblocks for the full context), every class and colour rebuilt against
   this site's own design tokens instead of copying Tshwane Leather's look.
   ========================================================================== */

.elza-checkout-topbar { background: var(--el-bg-alt); border-bottom: 1px solid rgba(37,39,31,.12); padding: 1.25rem 1.5rem; }
.elza-checkout-topbar-inner { max-width: 1400px; margin: 0 auto; display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
/* Now a <button> (data-cart-toggle opens the header cart drawer instead of
   navigating, see form-checkout.php's docblock), not an <a> — needs its own
   reset since it no longer inherits an anchor's default transparent/
   borderless/cursor:pointer styling. */
.elza-checkout-back-link { display: inline-flex; align-items: center; gap: .6rem; background: none; border: none; padding: 0; cursor: pointer; font-family: 'Jost', sans-serif; font-size: 13px; font-weight: 500; text-transform: uppercase; letter-spacing: .12em; color: var(--el-fg); text-decoration: none; }
.elza-checkout-back-link:hover { color: var(--el-olive-dark); }
.elza-checkout-topbar-secure { display: inline-flex; align-items: center; gap: .5rem; font-family: 'Jost', sans-serif; font-size: 12px; font-weight: 500; text-transform: uppercase; letter-spacing: .1em; color: var(--el-muted-fg); }

.elza-checkout-wrap { max-width: 1400px; margin: 0 auto; padding: 3rem 1.5rem 6rem; }
@media (min-width: 768px) { .elza-checkout-wrap { padding: 4rem 3rem 7rem; } }
.elza-checkout-eyebrow { color: var(--el-olive-dark); }
.elza-checkout-heading { margin-top: .5rem; font-size: clamp(2.75rem, 5vw, 4rem); line-height: .95; }

.elza-checkout-stepper { display: flex; align-items: center; gap: .75rem; list-style: none; margin: 2.5rem 0 0; padding: 0; max-width: 24rem; }
.elza-checkout-stepper-step { display: flex; align-items: center; gap: .6rem; }
.elza-checkout-stepper-num { display: grid; place-items: center; width: 2rem; height: 2rem; border-radius: 50%; border: 1px solid rgba(37,39,31,.28); font-family: 'Jost', sans-serif; font-size: 13px; font-weight: 600; color: var(--el-muted-fg); flex-shrink: 0; transition: background-color 200ms, border-color 200ms, color 200ms; }
.elza-checkout-stepper-label { font-family: 'Jost', sans-serif; font-size: 13px; font-weight: 500; text-transform: uppercase; letter-spacing: .1em; color: var(--el-muted-fg); }
.elza-checkout-stepper-line { flex: 1; height: 1px; background: rgba(37,39,31,.18); }
.elza-checkout-stepper-step.is-active .elza-checkout-stepper-num { background: var(--el-primary); border-color: var(--el-primary); color: var(--el-bg-alt); }
.elza-checkout-stepper-step.is-active .elza-checkout-stepper-label { color: var(--el-fg); }
.elza-checkout-stepper-step.is-complete .elza-checkout-stepper-num { background: var(--el-olive); border-color: var(--el-olive); color: #fff; }

.elza-checkout-grid { margin-top: 3rem; display: grid; gap: 3rem; grid-template-columns: 1fr; align-items: start; }
@media (min-width: 980px) { .elza-checkout-grid { grid-template-columns: 1.6fr 1fr; } }

.elza-checkout-panel { padding-top: .5rem; }
/* Found 2026-10-09 while verifying the new shipping-method picker below:
   Divi's own force-enqueued Divi/style-static.min.css (Known Divi 5
   Gotcha #2 in CLAUDE.md -- required sitewide to stop .et_pb_column grids
   from stacking) ships a generic HTML5-elements reset,
   `article, aside, footer, header, hgroup, nav, section { display: block }`.
   As an AUTHOR stylesheet rule it beats the browser's own UA-stylesheet
   `[hidden] { display: none }` regardless of specificity (origin is
   compared before specificity in the cascade) -- so EVERY <section hidden>
   on the site, not just this one, has been rendering visible this whole
   time. For checkout-wizard.js's two-step panel toggle specifically, this
   meant Step 2 "Payment method" (with its real "Place order" button) was
   always visible stacked directly below Step 1, defeating the step-by-step
   wizard the client explicitly asked for (2026-09-25, "integrate the same
   checkout system as Tshwane Leather's website") -- confirmed via a real
   Playwright full-page screenshot and a getComputedStyle() check showing
   display:block despite the hidden attribute being present. Scoped
   !important override restores real hidden behaviour for this element
   without touching Divi's own static CSS file or affecting any other
   section/article/aside/etc. element sitewide. */
.elza-checkout-panel[hidden] { display: none !important; }
.elza-checkout-panel-heading { margin: 0 0 1.5rem; }
.elza-checkout-fieldgroup { margin-bottom: 2.5rem; }
.elza-checkout-fieldgroup-heading { margin: 0 0 1.5rem; }
.elza-checkout-field-row.woocommerce-billing-fields__field-wrapper { display: grid; gap: 1.25rem; grid-template-columns: 1fr; }
@media (min-width: 640px) { .elza-checkout-field-row.woocommerce-billing-fields__field-wrapper { grid-template-columns: repeat(2, 1fr); } }
/* WooCommerce's own layout classes on the <p class="form-row ..."> wrapper
   -- form-row-wide fields (address line 2, etc.) span both grid columns. */
.elza-checkout-field-row .form-row-wide { grid-column: 1 / -1; }
.elza-checkout-field-row .form-row { margin: 0; }
.elza-checkout-panel .form-row label { margin-bottom: 0; }

.elza-checkout-panel-nav { margin-top: 1.5rem; display: flex; }
.elza-checkout-panel-nav-back { margin-top: 1.25rem; }

/* Checkout buttons are plain <button>/<a> elements (not Divi [et_pb_button]
   shortcodes), so they never pick up .et_pb_button's base layout rule --
   this reproduces the same base properties directly, then still layers the
   existing .elza-btn-primary/.elza-btn-outline/.elza-btn-lg classes on top
   for colour/sizing (those are already self-contained, no dependency on
   .et_pb_button). */
.elza-checkout-panel-nav button,
.elza-checkout-place-order {
  display: inline-flex; align-items: center; justify-content: center; gap: .75rem;
  white-space: nowrap; box-sizing: border-box; border: 1px solid transparent; border-radius: 0;
  font-family: 'Raleway', sans-serif; font-size: 14px; font-weight: 600; letter-spacing: .14em;
  text-transform: uppercase; text-decoration: none; line-height: 1.62; cursor: pointer;
  transition: transform 200ms, background-color 200ms, color 200ms, border-color 200ms;
}
.elza-checkout-place-order { width: 100%; margin-top: 1.5rem; }

/* Coupon toggle (WooCommerce's own $('.checkout_coupon').slideToggle(),
   class-based -- kept as a <div> not a <form>, see form-coupon.php). */
.woocommerce-form-coupon-toggle { margin: -.5rem 0 1.5rem; color: var(--el-muted-fg); }
.woocommerce-form-coupon-toggle .showcoupon { color: var(--el-fg); text-decoration: underline; cursor: pointer; }
.elza-checkout-coupon { display: flex; flex-wrap: wrap; gap: 1rem; align-items: flex-start; margin-bottom: 2rem; }
.elza-checkout-coupon .form-row { flex: 1 1 220px; margin: 0; }
.elza-checkout-coupon-error { flex-basis: 100%; color: var(--el-destructive); font-size: .875rem; margin: 0; }

/* Payment method list -- WooCommerce's own #payment/.wc_payment_methods
   class names kept identical to core (see payment.php's docblock: its AJAX
   fragment replacement targets them by class, not by which template
   rendered them), styled to this site's card/border language instead of
   WooCommerce's default grey box. */
#payment.woocommerce-checkout-payment { background: var(--el-bg-alt); border: 1px solid rgba(37,39,31,.14); padding: 1.5rem; margin-bottom: 1.5rem; }
#payment ul.wc_payment_methods { list-style: none; margin: 0; padding: 0; }
#payment ul.payment_methods li { padding: 1rem 0; border-bottom: 1px solid rgba(37,39,31,.1); }
#payment ul.payment_methods li:last-child { border-bottom: none; }
#payment ul.payment_methods label { font-family: 'Jost', sans-serif; font-weight: 500; }
#payment .payment_box { margin-top: .75rem; padding: 1rem; background: #fff; border: 1px solid rgba(37,39,31,.12); color: var(--el-muted-fg); font-size: .9375rem; }

/* Shipping method list (2026-10-09) -- the real delivery picker rendered
   by core's wc_cart_totals_shipping_html() (Door-to-door / PUDO collection
   / Free shipping), wrapped in a bare <table> in form-checkout.php's Step 1
   panel since that core function emits a <tr>/<td> designed to live inside
   one. Styled to match the payment-method card above (#payment, directly
   above) rather than WooCommerce's default grey totals-table look -- same
   card/border language, same list-reset pattern. */
.elza-checkout-shipping-methods { background: var(--el-bg-alt); border: 1px solid rgba(37,39,31,.14); padding: 1.5rem; margin-bottom: 1.5rem; }
.elza-checkout-shipping-table { width: 100%; border-collapse: collapse; }
.elza-checkout-shipping-table th { display: none; }
.elza-checkout-shipping-table td { padding: 0; }
ul#shipping_method.woocommerce-shipping-methods { list-style: none; margin: 0; padding: 0; }
ul#shipping_method.woocommerce-shipping-methods li { padding: 1rem 0; border-bottom: 1px solid rgba(37,39,31,.1); }
ul#shipping_method.woocommerce-shipping-methods li:last-child { border-bottom: none; }
ul#shipping_method.woocommerce-shipping-methods label { font-family: 'Jost', sans-serif; font-weight: 500; margin-left: .5rem; }
.woocommerce-shipping-destination { margin: .75rem 0 0; font-size: .8125rem; color: var(--el-muted-fg); }
.woocommerce-terms-and-conditions-wrapper { margin: 1.5rem 0; font-size: .875rem; color: var(--el-muted-fg); }

/* Order summary sidebar. */
.elza-checkout-summary { position: sticky; top: 6.5rem; }
.elza-checkout-summary-card { background: var(--el-bg-alt); border: 1px solid rgba(37,39,31,.14); padding: 1.75rem; }
.elza-checkout-summary-heading { margin: 0 0 1.5rem; font-size: 1.5rem; }
.elza-checkout-summary-items { display: flex; flex-direction: column; gap: 1.25rem; margin-bottom: 1.5rem; padding-bottom: 1.5rem; border-bottom: 1px solid rgba(37,39,31,.12); }
.elza-checkout-summary-item { display: grid; grid-template-columns: 56px 1fr auto; gap: .85rem; align-items: start; }
.elza-checkout-summary-item img { width: 56px; height: 70px; object-fit: cover; display: block; }
.elza-checkout-summary-item-name { margin: 0; font-size: .9375rem; line-height: 1.3; }
.elza-checkout-summary-item-variant { margin: .2rem 0 0; font-size: .8125rem; color: var(--el-muted-fg); }
.elza-checkout-summary-item-qty { margin: .2rem 0 0; font-size: .8125rem; color: var(--el-muted-fg); }
.elza-checkout-summary-item-price { font-size: .9375rem; white-space: nowrap; }
.elza-checkout-summary-totals { display: flex; flex-direction: column; gap: .65rem; }
.elza-checkout-summary-row { display: flex; align-items: center; justify-content: space-between; font-size: .9375rem; color: var(--el-muted-fg); }
.elza-checkout-summary-row--discount { color: var(--el-olive-dark); }
.elza-checkout-summary-row--total { margin-top: .5rem; padding-top: .75rem; border-top: 1px solid rgba(37,39,31,.12); font-size: 1.125rem; font-weight: 600; color: var(--el-fg); }
.elza-checkout-summary-badges { display: flex; flex-direction: column; gap: .75rem; margin-top: 1.75rem; padding-top: 1.5rem; border-top: 1px solid rgba(37,39,31,.12); }
.elza-checkout-summary-badge { display: flex; align-items: center; gap: .65rem; font-family: 'Jost', sans-serif; font-size: .8125rem; font-weight: 500; text-transform: uppercase; letter-spacing: .06em; color: var(--el-muted-fg); }
.elza-checkout-summary-badge svg { flex-shrink: 0; color: var(--el-olive-dark); }

/* Coupon-notice colour fix (2026-09-25, explicit client request -- "replace
   the blue on the checkout page with our green colour"): the bright blue on
   the "Have a coupon? Click here to enter your code" bar is Divi's own
   forced-enqueued style-static.min.css (`.woocommerce-info{background:
   #2ea3f2}`), not a WooCommerce default (WC core's own .woocommerce-info is
   a light lavender, #f6f5f8) and not anything this project's own CSS ever
   set -- confirmed by reading Divi's actual static sheet. Divi ships a
   built-in "green colour scheme" variant of this exact rule
   (`.et_color_scheme_green .woocommerce-message{background:#7cc68d}`), but
   it only activates via a body class this project's Divi Theme Options
   never set, and applies to `.woocommerce-message` (order-placed
   confirmations) rather than `.woocommerce-info` (this coupon-prompt
   notice) regardless. Scoped to `.woocommerce-info, .woocommerce-message`
   (matching Divi's own equally-global, unscoped selector) since the same
   generic Divi blue would otherwise resurface on every other WC notice on
   this site (order-received confirmations, "please fill in your details to
   see payment methods", etc.), not just this one coupon toggle -- fixing
   it in every place at once rather than patching this single instance.
   `--el-olive` (not a dedicated "green" token -- this palette has no other
   true green) is the same colour already used for hover states and success
   iconography elsewhere on this site (e.g. .elza-btn-primary:hover,
   .elza-checkout-summary-badge svg above), so this reads as consistent
   brand colour rather than a one-off pick. */
.woocommerce-info, .woocommerce-message { background: var(--el-olive) !important; }

/* ==========================================================================
   Product quick-view popup (template-parts/product-modal.php, js/product-modal.js)
   ========================================================================== */
html.elza-modal-open { overflow: hidden; }
.elza-product-modal-overlay {
  position: fixed; inset: 0; background: rgba(0,0,0,.5);
  display: flex; align-items: flex-start; justify-content: center;
  padding: 3vh 1.5rem; overflow-y: auto;
  opacity: 0; visibility: hidden; transition: opacity 220ms var(--el-ease);
  z-index: 200;
}
.elza-product-modal-overlay.is-open { opacity: 1; visibility: visible; }
.elza-product-modal {
  position: relative; background: var(--el-bg); width: 100%; max-width: 72rem;
  max-height: 94vh; overflow-y: auto; padding: 2.5rem;
}
.elza-product-modal-close {
  position: absolute; top: 1.5rem; right: 1.5rem; width: 2.5rem; height: 2.5rem;
  display: grid; place-items: center; font-size: 1.5rem; line-height: 1;
  background: none; border: 1px solid rgba(37,39,31,.18); cursor: pointer; z-index: 1;
}
.elza-product-modal-loading { display: flex; align-items: center; justify-content: center; min-height: 40vh; }
/* Task 4 verification fix: without this, the spinner never actually goes
   away once content loads. product-modal.js toggles the native `hidden`
   attribute (`loading.hidden = true`) to hide this element, but an AUTHOR
   stylesheet's `display` rule always wins over the browser's own built-in
   `[hidden]{display:none}` User-Agent rule regardless of selector
   specificity -- origin is compared before specificity in the cascade (the
   exact same bug class already documented and fixed above for
   `.elza-checkout-panel[hidden]`, different mechanism, same root cause
   category: an author `display` rule silently defeats the native `hidden`
   toggle). Confirmed via a real browser: `loading.hidden` was `true` and
   the `hidden` attribute was present in the DOM, yet
   `getComputedStyle(loading).display` still read `flex` -- the spinner sat
   permanently stacked on top of the loaded product content. */
.elza-product-modal-loading[hidden] { display: none !important; }
/* Review fix (Finding 1, add-to-cart error handling): the base
   `.elza-product-modal-error` rule above is sized for the full-popup "this
   piece could not be loaded" state (large centered padding). Reused here
   for the add-to-cart failure message instead of inventing a separate
   error colour/component -- this project has no dedicated danger/red
   token, and the existing rule's `color: var(--el-muted-fg)` already reads
   clearly as an error state in context (appearing directly under the
   add-to-cart button after a failed submit) -- just repositioned to sit
   inline under the form instead of filling the whole popup. */
.elza-product-modal-error.elza-add-to-cart-error { margin-top: 1rem; padding: 0; text-align: left; }
.elza-product-modal-spinner {
  width: 2.5rem; height: 2.5rem; border: 3px solid rgba(37,39,31,.15);
  border-top-color: var(--el-fg); border-radius: 50%;
  animation: elza-modal-spin 700ms linear infinite;
}
@keyframes elza-modal-spin { to { transform: rotate(360deg); } }
.elza-product-modal-error { text-align: center; padding: 4rem 1rem; color: var(--el-muted-fg); }
/* .elza-product-hero was written for a full page; inside the narrower,
   scrollable modal card it needs its own column behaviour rather than the
   page's full-viewport split -- confirm against a real render during
   testing below and adjust only if the existing page-level rule actively
   breaks inside this container (e.g. a min-height meant for a full
   viewport). */
.elza-product-modal .elza-product-hero { display: grid; gap: 2rem; }
@media (min-width: 768px) { .elza-product-modal .elza-product-hero { grid-template-columns: 1fr 1fr; } }
/* Final-review fix (Important, I3): the override above only reset
   `display`/`gap`/`grid-template-columns` -- the page-level
   `.elza-product-hero { min-height: calc(100svh - 125px) }` and
   `.elza-product-image { min-height: 68svh }` rules (written for a
   full-viewport page) were still winning inside the modal's much shorter
   `max-height: 94vh` card (same CSS-specificity/origin precedence as every
   other override in this block -- a more specific selector is required to
   beat them, not just a later rule on the same properties). Confirmed via
   a real 390x844 mobile screenshot: the product image alone filled most of
   the viewport and "Add to order bag" sat roughly 1400px down. Explicit
   zero/auto resets below make the modal's own `max-height` the only height
   constraint in play. */
.elza-product-modal .elza-product-hero  { min-height: 0; }
.elza-product-modal .elza-product-image { min-height: 0; aspect-ratio: 4 / 5; }
.elza-product-modal .elza-product-details { padding: 0; align-items: flex-start; }

/* Final-review fix (Important, I4): WooCommerce's own wc-add-to-cart.js
   (AddToCartHandler.updateButton(), add-to-cart.js) inserts an unstyled
   "View cart" <a class="added_to_cart wc-forward"> right after the add-to-
   cart button on every successful AJAX add -- this is default WC behaviour
   on ANY page, not something this project's code ever added. It points at
   wc_get_cart_url(), which this site deliberately redirects to the
   homepage (Elza_Setup_Cart_Handler::redirect_full_cart_page() --
   unrelated, pre-existing, not changed here) in favour of the real order-
   bag drawer. Now that the header badge (see class-cart-handler.php's
   cart_badge_fragment()) gives real, visible feedback that the add
   worked, this stray link is simply noise inside the popup -- hidden
   rather than restyled, since there's no useful destination for it to
   point to that isn't already one click away via the header icon it sits
   right next to.

   `!important` required, not optional here (confirmed by inspecting the
   actual winning rule in a real browser): WooCommerce core's own
   `.woocommerce a.added_to_cart { display: inline-block }`
   (woocommerce.css) carries TWO classes plus a type selector (`a`) --
   specificity (0,2,1) -- which beats this rule's two-class-only (0,2,0)
   regardless of this stylesheet's later position in `<head>` source order;
   source order only acts as the tie-breaker for EQUAL specificity, and
   this one isn't equal. Same "an author rule needs an unconditional win
   over a WC/Divi default" situation already documented and fixed the same
   way elsewhere in this file (e.g. `.elza-product-modal-loading[hidden]`
   above, `.woocommerce-info, .woocommerce-message` above that). */
.elza-product-modal .added_to_cart { display: none !important; }

/* ==========================================================================
   Thank-you (order-received) page — 2026-10-13
   Overrides WooCommerce's default order-received output (see
   woocommerce/checkout/thankyou.php, woocommerce/order/order-details.php,
   woocommerce/order/order-details-item.php) with brand styling. Scoped
   under .elza-thankyou- and the WooCommerce classes those three templates
   are known to emit — never applies outside this one page.
   ========================================================================== */

.elza-thankyou { background: var(--el-bg); }

/* Client request, 2026-10-13: "reduce the hero sections a bit i want some
   white spaces on both ends" -- the hero ran full-bleed edge to edge; every
   other section on this page (Order details, bank details, closing band,
   delivery details) is already capped at `max-width: 72rem; margin: 0
   auto`, so the hero was the one section without that framing. Matched it
   to the same width for consistency with the rest of the page, rather
   than inventing a separate value. */
.elza-thankyou-hero {
  display: grid;
  grid-template-columns: 1fr;
  max-width: 72rem;
  margin: 0 auto;
  background: var(--el-bg-alt);
}
@media (min-width: 980px) {
  .elza-thankyou-hero { grid-template-columns: 1.1fr .9fr; align-items: stretch; }
}

.elza-thankyou-hero-copy { padding: 3rem 1.5rem; align-self: center; }
@media (min-width: 768px) { .elza-thankyou-hero-copy { padding: 4rem 3rem; } }
@media (min-width: 980px) { .elza-thankyou-hero-copy { padding: clamp(3rem, 6vw, 5.5rem); } }

/* Client request, 2026-10-13: "make sure the text is centered over the 3
   blocks" -- the eyebrow/heading/intro copy was left-aligned and narrower
   than the order-meta row beneath it (that row spans this column's full
   width; the copy above it didn't), reading as off-centre relative to it.
   Centred the copy itself to match -- `.elza-thankyou-meta` and
   `.elza-thankyou-confirmation` are deliberately NOT touched here, so the
   order-number/date/total data and its labels stay left-aligned within
   their own cells, exactly as asked (only "the text" moves, not "the 3
   blocks"). */
.elza-thankyou-eyebrow { color: var(--el-olive-dark); }
.elza-thankyou-hero-copy .elza-thankyou-eyebrow,
.elza-thankyou-hero-copy .elza-thankyou-heading { text-align: center; }

.elza-thankyou-heading {
  margin: .75rem 0 1rem;
  font-size: clamp(2.5rem, 6vw, 4.25rem);
  line-height: .95;
  letter-spacing: -.03em;
}
.elza-thankyou-heading-accent { display: block; margin-top: .25rem; font-size: 0.42em; color: var(--el-terracotta); }

.elza-thankyou-intro {
  max-width: 32rem;
  margin-left: auto;
  margin-right: auto;
  text-align: center;
  color: var(--el-muted-fg);
  font-size: 1.0625rem;
  line-height: 1.8;
}

.elza-thankyou-meta {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  margin-top: 1.75rem;
  border-top: 1px solid rgba(37,39,31,.15);
  border-bottom: 1px solid rgba(37,39,31,.15);
}
.elza-thankyou-meta > div { min-width: 0; padding: 1rem .75rem 1rem 0; }
.elza-thankyou-meta > div + div { padding-left: .875rem; border-left: 1px solid rgba(37,39,31,.15); }
.elza-thankyou-meta-label {
  display: block;
  font-family: 'Jost', sans-serif;
  font-size: .625rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--el-muted-fg);
}
.elza-thankyou-meta-value { display: block; margin-top: .4rem; font-size: .9375rem; overflow-wrap: anywhere; }

/* Client request, 2026-10-13: "centre the text beneath the columns" --
   same reasoning as the earlier "centre the text over the 3 blocks" fix
   above: this line was left-aligned, reading off-centre relative to the
   meta row above it once that row's own copy was centred. */
.elza-thankyou-confirmation { margin-top: 1.25rem; text-align: center; color: var(--el-muted-fg); font-size: .8125rem; }

/* Client request, 2026-10-13: "this section needs the hero and text to
   fade into one another" -- there was a hard rectangular seam where the
   cream text column met the photo. A CSS mask fades the photo's own
   leading edge to transparent (stacked edge on mobile, left edge
   alongside the copy at 980px+, matching the grid breakpoint the 2-column
   layout itself switches on at), letting this container's background
   show through the fade -- matched to `--el-bg-alt`, the same cream the
   text column sits on (was `--el-product-bg`, a mismatched tan swatch
   colour meant for empty product-image placeholders elsewhere on the
   site, not this photographic hero), so the blend reads as one
   continuous surface rather than two panels. `-webkit-mask-image` is
   required alongside the unprefixed property for Safari/WebKit. */
/* Client request, 2026-10-14: "we need to resize this image so the
   handbags actually fit" -- root cause, not guessed: this box used
   `align-items: stretch` (inherited from the parent `.elza-thankyou-hero`
   grid) with no aspect-ratio of its own, so its height was forced to
   match the TEXT column's height, which has nothing to do with the
   photo's own 1600x900 proportions. The 2026-10-13 "white space on both
   ends" fix (max-width: 72rem on the hero) made this measurably worse --
   capping the hero's total width narrowed the image column (still only
   .9fr of a now-smaller total) while the text column's height was
   unchanged, stretching the photo into a much taller, narrower box than
   before and forcing `object-fit: cover` into an aggressive crop that cut
   the handbags off at both edges to keep the model centred. Fixed at the
   real cause: `align-self: center` opts this one grid item out of the
   parent's stretch, and `aspect-ratio: 16 / 9` sizes the box from its own
   width using the photo's real proportions, so cover only needs to trim
   a sliver rather than crop to an arbitrary, unrelated height. */
.elza-thankyou-hero-image { min-height: 260px; background: var(--el-bg-alt); }
@media (min-width: 980px) {
  /* No min-height override here (unlike before) -- at this breakpoint's
     real column widths (roughly 440-520px once the 72rem hero cap is
     applied), aspect-ratio: 16/9 alone already produces a sensible
     240-290px-tall box; a min-height floor anywhere near the old 420px
     would just re-force the same too-tall, over-cropped box this fix
     exists to remove. */
  .elza-thankyou-hero-image {
    align-self: center;
    aspect-ratio: 16 / 9;
  }
}
.elza-thankyou-hero-image img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  -webkit-mask-image: linear-gradient(to bottom, transparent, black 12%);
  mask-image: linear-gradient(to bottom, transparent, black 12%);
}
@media (min-width: 980px) {
  .elza-thankyou-hero-image img {
    -webkit-mask-image: linear-gradient(to right, transparent, black 16%);
    mask-image: linear-gradient(to right, transparent, black 16%);
  }
}

/* --- Order details (WooCommerce's own markup, restyled) --- */

.elza-thankyou-order-section { padding: 2.5rem 1.25rem; max-width: 72rem; margin: 0 auto; }
@media (min-width: 768px) { .elza-thankyou-order-section { padding: 3.5rem 2rem; } }

.elza-thankyou-section-label { color: var(--el-olive-dark); margin-bottom: .5rem; }

.elza-thankyou-section-heading {
  margin: 0 0 1.5rem;
  font-size: 1.75rem;
}

.elza-thankyou-order-table {
  width: 100%;
  border-collapse: collapse;
  border: 1px solid rgba(37,39,31,.15);
}
.elza-thankyou-order-table th,
.elza-thankyou-order-table td {
  padding: .9rem 1rem;
  border-bottom: 1px solid rgba(37,39,31,.12);
  text-align: left;
  font-size: .875rem;
}
.elza-thankyou-order-table thead th {
  background: var(--el-bg-alt);
  font-family: 'Jost', sans-serif;
  font-size: .6875rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--el-muted-fg);
}
.elza-thankyou-order-table td.product-total,
.elza-thankyou-order-table th.product-name + th.product-total,
.elza-thankyou-order-table tfoot td { text-align: right; }
.elza-thankyou-order-table tfoot tr:last-child th,
.elza-thankyou-order-table tfoot tr:last-child td {
  background: var(--el-bg-alt);
  font-size: 1rem;
  border-bottom: none;
}

.elza-thankyou-item-row { display: flex; align-items: center; gap: 1rem; }
.elza-thankyou-item-image {
  width: 56px;
  height: 68px;
  object-fit: cover;
  background: var(--el-product-bg);
  flex-shrink: 0;
}
.elza-thankyou-item-text a { color: inherit; text-decoration: none; }
.elza-thankyou-item-text a:hover { text-decoration: underline; }
.elza-thankyou-item-text .product-quantity { display: block; margin-top: .2rem; font-weight: 400; color: var(--el-muted-fg); font-size: .8125rem; }

/* --- Closing CTA band --- */

/* Client request, 2026-10-14: "do the same with the bottom hero please" --
   same fix as the top hero band above: contained to the same
   max-width: 72rem; margin: 0 auto as every other section on this page,
   instead of running full-bleed edge to edge. */
.elza-thankyou-closing {
  display: grid;
  grid-template-columns: 1fr;
  max-width: 72rem;
  margin: 0 auto;
  background: var(--el-secondary);
}
@media (min-width: 980px) { .elza-thankyou-closing { grid-template-columns: .85fr 1.15fr; align-items: stretch; } }

/* Proactive fix, 2026-10-14, applied in the same pass as the hero image
   fix above rather than waiting for a separate report: this element has
   the exact same structural cause (align-items: stretch on the parent
   grid, no aspect-ratio of its own, this same max-width: 72rem hero-band
   containment narrowing the column) -- confirmed via the photo's real
   dimensions (1536x1024, i.e. 3:2) that the old 360px min-height floor
   was already overriding a 3:2-derived height at this column's real
   width, over-stretching the box just like the hero's was. Less visually
   severe here (this photo's many small bags tolerate a tighter crop
   better than the hero's two people-width bags did), but the same real
   bug, so fixed the same way rather than left until it's reported. */
.elza-thankyou-closing-image { min-height: 240px; }
@media (min-width: 980px) {
  .elza-thankyou-closing-image {
    align-self: center;
    aspect-ratio: 3 / 2;
  }
}
/* Client request, 2026-10-14: "create a fade for the bottom hero like we
   did for the top hero" -- same mask technique as the top hero image
   above, mirrored for this band's opposite layout: there the image sits
   on the right with text on its left, so the fade was on the image's own
   left edge; here the image sits on the LEFT with text on its right, so
   the fade is on the image's own RIGHT edge instead (`to left` instead of
   `to right`). Mobile direction mirrors the same way: the top hero stacks
   text-then-image (seam at the image's top edge), this band stacks
   image-then-text (seam at the image's BOTTOM edge), so `to top` instead
   of `to bottom`. No background-colour fix needed here unlike the top
   hero's -- `.elza-thankyou-closing-image` has no background of its own,
   so the fade already reveals the parent `.elza-thankyou-closing`'s real
   `--el-secondary`, not a mismatched placeholder colour. */
.elza-thankyou-closing-image img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  -webkit-mask-image: linear-gradient(to top, transparent, black 12%);
  mask-image: linear-gradient(to top, transparent, black 12%);
}
@media (min-width: 980px) {
  .elza-thankyou-closing-image img {
    -webkit-mask-image: linear-gradient(to left, transparent, black 16%);
    mask-image: linear-gradient(to left, transparent, black 16%);
  }
}

.elza-thankyou-closing-copy { padding: 3rem 1.5rem; text-align: center; align-self: center; }
@media (min-width: 768px) { .elza-thankyou-closing-copy { padding: 4rem 3rem; } }

.elza-thankyou-closing-eyebrow { color: var(--el-olive-dark); }
.elza-thankyou-closing-heading {
  margin: .75rem 0 1.25rem;
  font-size: clamp(1.875rem, 3.6vw, 2.75rem);
  letter-spacing: -.02em;
}
.elza-thankyou-closing-body {
  max-width: 30rem;
  margin: 0 auto 1.75rem;
  color: rgba(37,39,31,.65);
  font-size: .9375rem;
  line-height: 1.8;
}
.elza-thankyou-buttons { display: flex; flex-wrap: wrap; justify-content: center; gap: .75rem; }
/* Client request, 2026-10-13: "centre the text in the buttons" -- every
   other `.elza-btn-primary`/`.elza-btn-outline` button on this site gets
   its real vertical centring from Divi's own `.et_pb_button` base class
   (display:flex;align-items:center;justify-content:center -- style.css
   ~line 265), which those buttons carry automatically because they're
   rendered through a real Divi [et_pb_button] shortcode. This page's
   buttons are plain custom HTML, not a Divi module, so they never got
   that base class -- confirmed via inspection, not guessed: without it
   there's no flex centring at all, just a fixed height with zero
   vertical padding, so the text sat wherever the inherited line-height
   happened to place it. Deliberately NOT adding the `et_pb_button` class
   itself to fix this (the simpler-looking option) -- that class also
   forces Raleway, uppercase, 600-weight, letter-spaced 14px text, none
   of which this page's buttons currently have or were asked to change;
   only the missing centring behaviour is added here, nothing else. */
.elza-thankyou-buttons .elza-btn-primary,
.elza-thankyou-buttons .elza-btn-outline {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.elza-thankyou-signoff { display: block; margin-top: 1.75rem; color: var(--el-muted-fg); font-size: .625rem; }

/* --- Bank-transfer details (BACS instructions) ---
   Lives with Order Details, not the Delivery details section further down
   -- explicit client request, 2026-10-13: "add a section for the banking
   details... in the order details, only until payflex is setup." BACS is
   this store's only payment method right now, so the instructions for how
   to actually pay are surfaced immediately next to what was ordered,
   rather than requiring a scroll past the closing CTA band first. Revisit
   this placement once a real gateway (Payflex or otherwise) means a
   customer no longer needs to manually complete a bank transfer. */

.elza-thankyou-bank-details { padding: 0 1.25rem 2.5rem; max-width: 72rem; margin: 0 auto; }
@media (min-width: 768px) { .elza-thankyou-bank-details { padding: 0 2rem 3rem; } }

.elza-thankyou-bank-details .wc-bacs-bank-details-account-name {
  font-family: 'Jost', sans-serif;
  font-size: 1.125rem;
  margin: 0 0 .75rem;
}
.elza-thankyou-bank-details ul.wc-bacs-bank-details {
  list-style: none;
  margin: 0;
  padding: 1.25rem 1.5rem;
  background: var(--el-bg-alt);
  border: 1px solid rgba(37,39,31,.12);
}
.elza-thankyou-bank-details ul.wc-bacs-bank-details li { padding: .3rem 0; font-size: .875rem; }

/* --- Delivery details (billing/shipping addresses) --- */

.elza-thankyou-payment-section { padding: 2.5rem 1.25rem 4rem; max-width: 72rem; margin: 0 auto; }
@media (min-width: 768px) { .elza-thankyou-payment-section { padding: 3.5rem 2rem 5rem; } }

.elza-thankyou-payment-section .woocommerce-columns--addresses {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.5rem;
  list-style: none;
  margin: 0;
  padding: 0;
}
@media (min-width: 768px) { .elza-thankyou-payment-section .woocommerce-columns--addresses { grid-template-columns: 1fr 1fr; } }
/* WooCommerce's own woocommerce-layout.css sets `.col2-set .col-1 { float:
   left; width: 48% }` (its matching `float: none; width: 100%` reset for
   this only lives inside woocommerce-smallscreen.css's own mobile media
   query, so it never reaches desktop) -- confirmed via a real browser's
   matched-rules inspection, not guessed: that rule has higher selector
   specificity than this one (three classes vs two) and was winning
   outright. `!important` neutralises it regardless of that rule's
   specificity or any future WooCommerce core CSS change to it.

   Neutralising float alone was not enough, though (confirmed via a
   computed-style check after the float fix): the two cards still landed
   in two separate auto-generated grid rows, each sized to its own card's
   height, with their column order reversed from DOM order -- auto-
   placement was not resolving the way the CSS Grid spec says it should
   on this install's rendering engine. Rather than keep chasing that,
   both cards get an explicit grid position here, which is unambiguous
   under the spec and doesn't depend on the auto-placement algorithm at
   all. */
.elza-thankyou-payment-section .woocommerce-column {
  float: none !important;
  width: 100% !important;
  padding: 1.25rem 1.5rem;
  border: 1px solid rgba(37,39,31,.12);
}
.elza-thankyou-payment-section .woocommerce-column--billing-address { grid-column: 1; grid-row: 1; }
.elza-thankyou-payment-section .woocommerce-column--shipping-address { grid-column: 2; grid-row: 1; }
@media (max-width: 767px) {
  .elza-thankyou-payment-section .woocommerce-column--billing-address,
  .elza-thankyou-payment-section .woocommerce-column--shipping-address { grid-column: 1; }
  .elza-thankyou-payment-section .woocommerce-column--shipping-address { grid-row: 2; }
}
.elza-thankyou-payment-section .woocommerce-column__title {
  font-family: 'Jost', sans-serif;
  font-size: 1rem;
  margin: 0 0 .75rem;
}
.elza-thankyou-payment-section address { font-style: normal; font-size: .875rem; line-height: 1.7; }
