/*
Theme Name: Deeds Pine Creations
Template: Divi
Author: Mighty Maine
Description: Divi 5 child theme replicating the Deeds Pine Creations Manus/React reference app (localhost:4500). Design-only — no page content lives here, see the deeds-pine-importer plugin.
Version: 1.0.0
Text Domain: deeds-pine-child
*/

/* ==========================================================================
   Design tokens — ported verbatim from the source app's client/src/index.css
   :root block (Tailwind's oklch/shadcn tokens dropped — unused by these
   static pages, which only ever reference the plain hex/rgba custom
   properties below). Source of truth: deeds-pine-store/client/src/index.css
   ========================================================================== */
:root {
  --espresso: #3b2a22;
  --walnut: #6b4a3a;
  --timber: #9c7a5a;
  --sand: #d8c6ae;
  --sage: #8a8f7a;
  --cream: #f5f0e8;
  --paper: #fbf9f5;
  --ink: #2b211c;
  /* The reference's shadcn/Tailwind oklch token used for headings on
     light-background sections — slightly different from --ink (its own
     hand-picked hex fallback elsewhere), copied verbatim (not a hex
     approximation) so heading color is an exact, not just close, match.
     Source: deeds-pine-store/client/src/index.css's `--foreground`. */
  --foreground: oklch(0.245 0.027 48);
  --copy-muted: #756b64;
  --border-soft: rgba(59, 42, 34, 0.16);
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
  --font-sans: "Montserrat", sans-serif;
  --font-serif: "Montserrat", sans-serif;
}

*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body { margin: 0; background: var(--paper) !important; color: var(--ink) !important; font-family: var(--font-sans) !important; font-weight: 400 !important; font-size: 17px !important; line-height: 1.65 !important; antialiased: true; -webkit-font-smoothing: antialiased; }
.et_pb_text { line-height: 1.65 !important; }
button, a, input, select, textarea { font: inherit; }
button, a { -webkit-tap-highlight-color: transparent; }
button { cursor: pointer; }
img { max-width: 100%; display: block; }
::selection { background: var(--sand); color: var(--espresso); }
/* Divi 5's own dynamic CSS carries a bare `a { color: #2ea3f2 }` (bright
   blue) at the same 0,0,1 tag-selector specificity as this rule, and
   loads later — same recurring "Divi dynamic CSS beats an equal-
   specificity custom rule" pattern documented repeatedly elsewhere in
   this file, just never hit on the anchor tag itself until now. Since
   almost nothing in this build sets its own explicit link color (most
   links were relying on `color:inherit` from a colored ancestor, e.g.
   footer links inheriting the footer's off-white), this one rule losing
   silently turned EVERY such link bright blue site-wide — confirmed via
   CSS.getMatchedStylesForNode, not guessed. */
a { color: inherit !important; text-decoration: none; }
button:focus-visible, a:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible { outline: 3px solid rgba(156, 122, 90, .55); outline-offset: 3px; }
ul { box-sizing: border-box; }

/* Divi 5 gotchas #2/#3 — restore row centering + column grid dropped under dynamic CSS */
.et_pb_row { width: 80%; margin: auto; }

/* `.dp-flush` strips Divi's own default section/row/column padding/
   max-width for the few remaining pieces that need genuinely zero Divi
   padding (kept for any fullwidth Code module use). Applied via
   module_class only — never a positional selector, per this project's
   CSS rule. Most sections now rely on plain CSS cascade instead (see the
   "Real Divi modules" block below): a section's own class sets real
   padding at the same specificity as Divi's default and loads later, so
   it wins without needing dp-flush at all. */
.et_pb_section.dp-flush { padding: 0; }
.et_pb_row.dp-flush { width: 100%; max-width: 100%; padding: 0; margin: 0; }
.et_pb_column.dp-flush { padding: 0; }
.et_pb_section.dp-flush .et_pb_row.dp-flush { display: block; }

/* Real Divi modules used for editability (rebuilt from a single
   page-length Code module per page to real et_pb_section/row/column/
   text/image/button modules, per this project's own CLAUDE.md rule:
   "All CSS must use explicit module_class selectors... they break in
   the Visual Builder" only makes sense for pages actually built from
   real, separately classed modules). Every row/column this build
   generates also always needs full width (never Divi's default 80%
   centred box — this design manages its own max-widths per section), so
   dp-shell also strips that the same way dp-flush already does.
   dp-shell / dp-flat dissolve Divi's own row/column/module wrapper boxes
   via display:contents so the ported flat-DOM CSS below (written for the
   source app's plain HTML) keeps applying with no selector rewrites —
   modules stay real and individually selectable/editable in the Visual
   Builder, they just don't generate their own layout box. See
   DECISIONS.md for the full explanation of this technique. */
.et_pb_row.dp-shell { width: 100%; max-width: 100%; margin: 0; padding: 0; }
/* Divi 5's OWN dynamic CSS also applies `.et_block_row { padding: 27px 0 }`
   (a DIFFERENT class than .et_pb_row/.et_pb_section, so none of the
   earlier !important fixes on those touched it) to every real row this
   build generates (dp_realrow() output — category-grid, footer-grid,
   contact-details, shop-sidebar, shop-results, site-header-inner...).
   None of these rows want ANY padding of their own — every one of them
   spaces its children with `gap`, never `padding` — so this is always
   safe to zero out unconditionally, unlike the per-section padding case
   above which needed most sections' own padding re-declared afterward.
   Confirmed via CSS.getMatchedStylesForNode: this exact rule was still
   adding ~54px of unwanted height to .contact-details even after every
   other padding/gap fix in this file. */
.et_block_row { padding: 0 !important; }
/* dp_realrow() output (a REAL, visible row carrying an original semantic
   grid/flex class — category-grid, shop-sidebar, shop-results,
   values-grid, contact-details, footer-grid...) isn't dp-shell (it must
   keep its own box for that class's CSS to apply), so it never picked up
   the dp-shell width reset above — it was silently sitting at Divi 5
   gotcha #3's `.et_pb_row{width:80%;margin:auto}` fix (this file, near
   the top) instead of filling its parent, breaking every multi-column
   grid built from dp_realrow() (confirmed on /shop/: the sidebar
   rendered as an 80%-centred block several rows below the product grid
   instead of beside it). dp-full is the equivalent reset for real rows.
   Needs `!important`: Divi's own dynamic CSS carries a
   `.et_pb_row:not([class*="et_flex_column"])` rule at the SAME 2-unit
   specificity as `.et_pb_row.dp-full` and loads later, so a plain
   declaration here still loses the tie exactly like the padding/
   background/position bugs above (confirmed via
   CSS.getMatchedStylesForNode). */
.et_pb_row.dp-full { width: 100% !important; max-width: 100% !important; margin: 0 !important; }
.et_pb_column.dp-shell { padding: 0; }
/* !important required as of the 2026-09-18 native-module rebuild: Divi 5's
   own combined utility selector `.et_flex_column, .et_flex_group,
   .et_flex_module, .et_flex_row, .et_flex_section { display: flex }`
   (present on every native/flex-rendered row/column/module — absent from
   the legacy shortcode renderer this rule was originally written against)
   is equal-specificity (single class) and loads later in the cascade, so
   it silently won over plain `display: contents` and broke the entire
   dp-shell/dp-flat promotion technique sitewide. Confirmed via
   CSS.getMatchedStylesForNode on a real module — same collision-class
   as every other "Divi's own dynamic CSS beats a plain custom rule" bug
   documented in DECISIONS.md, just on a newly-introduced class pair. */
.dp-shell,
.dp-shell > .et_pb_column_inner { display: contents !important; }
.dp-flat,
.dp-flat > .et_pb_text_inner,
.dp-flat > .et_pb_image_wrap,
.dp-flat > .et_pb_button_wrapper_wrapper,
.dp-flat > .et_pb_button_wrapper,
.dp-flat > .et_pb_code_inner { display: contents !important; }

/* `.site-header`'s `position:sticky` (below) needs a containing block
   (its own direct parent) tall enough to remain "stuck" for the whole
   page scroll. In the reference React app, `.site-header`'s direct
   parent is the single top-level wrapper div that also holds `<main>`
   and `<footer>` — i.e. the FULL page height — so sticky works for the
   entire scroll. In this rebuild, `.site-header` is nested one level
   deeper, inside its own small `site-header-shell` Divi section (only
   ~200px tall, since it holds just the announcement bar + header +
   hidden mobile-nav) — confirmed via direct measurement 2026-09-18:
   the header stopped being "stuck" after ~120px of scroll and then
   scrolled away for the rest of the ~9000px page, exactly matching a
   too-short sticky containing block. Dissolving `.site-header-shell`
   itself with the SAME `display:contents` technique already used
   throughout this project (just applied one level higher, to the
   section instead of a row/column/module) promotes its children up to
   its own parent's level (`.et_builder_inner_content`, which DOES span
   the full page since `<main>` and the footer section are its other
   children) — giving `.site-header` the correctly-tall containing block
   it needs, with zero visual side effects confirmed (this section has
   no background/padding/border of its own; every visible piece inside
   it — announcement bar, header, mobile-nav — already carries its own
   explicit styling independent of this wrapper). Trade-off: this
   section can no longer be selected as a whole in the Visual Builder
   canvas (its children remain individually selectable, same as any
   other dp-shell/dp-flat-dissolved content) — acceptable for a
   header/nav shell that's edited piece-by-piece anyway. */
.site-header-shell { display: contents !important; }

/* Same bug, footer side, found 2026-09-18 shortly after the header fix
   above: `.site-footer-shell` is a real Divi section with Divi's own
   default `display:flex; flex-direction:row` (via `.et_flex_section`).
   Its box-tree children are the promoted WhatsApp-float link (dissolved
   dp-shell/dp-flat row) and the literal `<footer>` tag. The WhatsApp
   link is `position:fixed` — removed from flex participation entirely —
   leaving `<footer>` as the ONLY real flex item in a row-direction flex
   container, so it gets sized to its own shrink-to-fit content width
   instead of stretching full-width, and ends up horizontally centered
   with symmetric white gutters on both sides (confirmed via direct
   measurement at 1920px viewport: footer width 1652px, centered with
   ~134px gutters each side, section itself correctly full-width).
   Same fix as the header: dissolve this wrapper section too — it has no
   background/padding of its own (confirmed), so `<footer>` (a normal
   block element once promoted out of the flex context) naturally
   returns to full width with zero visual side effects. */
.site-footer-shell { display: contents !important; }

/* Divi 5's own dynamic/generated CSS emits `.et_pb_section { padding:
   54px 0 }` (a bare tag+class selector, same 0,1,0 specificity as our
   own single-class section rules below) and — being dynamically
   generated per page load — it lands LATER in the cascade than this
   child theme's stylesheet, so it wins the specificity tie on source
   order alone and silently overrides every section's intended padding.
   Confirmed via Chrome DevTools Protocol CSS.getMatchedStylesForNode
   (not guessed) — same failure class as the DIVI5-GOTCHAS.md #4/#5
   "dynamic CSS dropout" entries. Fix, per this project's established
   default move for this exact bug class: neutralise Divi's rule with
   `!important` (beats ANY non-important rule regardless of specificity
   or order), then every section below that needs non-zero padding also
   declares its `padding` with `!important` — among competing `!important`
   declarations the normal specificity/order rules apply again, and since
   those all live in THIS file, source order is ours to control. Sections
   that want zero padding (hero-section, craft-section, about-hero,
   about-image-band — the source design already gives these none,
   children provide their own) need no further rule at all. */
.et_pb_section { padding: 0 !important; }

/* ==========================================================================
   Global shell — announcement bar / header / mobile nav / WhatsApp float / footer
   ========================================================================== */
.announcement { min-height: 34px; background: var(--espresso); color: var(--cream); padding: 8px clamp(20px, 4vw, 68px); display: flex; align-items: center; justify-content: space-between; gap: 20px; font-size: 11px; letter-spacing: .11em; text-transform: uppercase; }
.announcement p { margin: 0; }
.announcement a { color: var(--sand); display: none; align-items: center; gap: 4px; }
/* The reference's PHP/JSX emits this link with Tailwind's `hidden
   sm:inline-flex` utility classes literally in the markup (this child
   theme carries those exact class NAMES over from the port, but never
   loads Tailwind itself, so they're inert — the link was rendering at
   every width instead of only ≥640px). Reference behavior: hidden below
   Tailwind's default `sm` breakpoint (640px), `inline-flex` at/above it.
   Confirmed as the actual cause of an "announcement text isn't centered"
   report: with the link still visible at mobile widths, the centered
   text sits in a narrower, asymmetric space instead of the full bar
   width the reference uses once the link disappears. */
@media (min-width: 640px) {
  .announcement a { display: inline-flex; }
}
.site-header { position: sticky; top: 0; z-index: 40; background: rgba(251, 249, 245, .94); backdrop-filter: blur(14px); border-bottom: 1px solid var(--border-soft); }
/* display:grid !important below — as of the 2026-09-18 native-module
   rebuild, this class sits on a REAL Divi row element (dp5_realrow()),
   which carries Divi's own `.et_flex_row{display:flex}` combined-selector
   class — equal specificity, later in cascade, silently wins without
   !important. Same collision as .dp-shell/.dp-flat above, just on classes
   that are themselves real (non-dissolved) grid/flex containers. Confirmed
   via CSS.getMatchedStylesForNode on this exact element. */
.site-header-inner { height: 82px; width: 100%; margin: 0; padding: 0 clamp(20px, 2.6vw, 50px); display: grid !important; grid-template-columns: 1fr auto 1fr; align-items: center; }
.brand-lockup { display: inline-flex; align-items: center; gap: 12px; justify-self: start; }
.brand-lockup img { width: 52px; height: 52px; object-fit: cover; border-radius: 50%; border: 1px solid rgba(59, 42, 34, .2); }
.brand-lockup div { display: flex; flex-direction: column; line-height: 1; }
.brand-name { font-family: var(--font-serif); font-weight: 600; font-size: 17px; letter-spacing: .08em; }
.brand-subtitle { font-size: 8px; letter-spacing: .42em; margin-top: 6px; color: var(--walnut); }
.desktop-nav { display: flex; align-items: center; gap: clamp(22px, 3vw, 44px); }
.desktop-nav a { position: relative; padding: 30px 0; font-size: 13px; font-weight: 600; color: #4e433d; }
.desktop-nav a::after { content: ""; position: absolute; left: 0; right: 100%; bottom: 21px; height: 1px; background: var(--walnut); transition: right 220ms var(--ease-out); }
.desktop-nav a:hover::after, .desktop-nav a.active::after { right: 0; }
.header-actions { display: flex; justify-content: flex-end; align-items: center; gap: 4px; }
.icon-button.menu-trigger { display: none; }
.icon-button { width: 42px; height: 42px; border: 0; background: transparent; display: inline-grid; place-items: center; transition: background 180ms var(--ease-out), transform 150ms var(--ease-out); }
.icon-button:hover { background: rgba(216, 198, 174, .38); }
.icon-button:active { transform: scale(.96); }
.cart-button { position: relative; }
.cart-button span { position: absolute; top: 2px; right: 1px; width: 18px; height: 18px; border-radius: 50%; background: var(--walnut); color: white; display: grid; place-items: center; font-size: 9px; font-weight: 700; }
.mobile-nav-backdrop { position: fixed; inset: 0; z-index: 70; background: rgba(59, 42, 34, .38); display: none; }
.mobile-nav-backdrop.open { display: flex; }
.mobile-nav-panel { width: min(88vw, 390px); min-height: 100%; background: var(--paper); padding: 24px; box-shadow: 30px 0 80px rgba(0,0,0,.18); animation: menu-in 240ms var(--ease-out) both; }
.mobile-nav-panel .mnp-top { display: flex; align-items: center; justify-content: space-between; }
.mobile-nav-panel nav { margin-top: 50px; display: flex; flex-direction: column; }
.mobile-nav-panel nav a { padding: 17px 0; border-bottom: 1px solid var(--border-soft); font-family: var(--font-serif); font-size: 28px; }
.mobile-nav-panel > p { margin-top: 50px; max-width: 270px; color: var(--copy-muted); line-height: 1.7; }
@keyframes menu-in { from { opacity: 0; transform: translateX(-18px); } to { opacity: 1; transform: translateX(0); } }

.eyebrow { margin: 0 0 15px; color: var(--walnut); font-size: 10px; font-weight: 700; letter-spacing: .2em; text-transform: uppercase; }
h1, h2, h3, p { margin-top: 0; }
h1, h2 { font-family: var(--font-serif); font-weight: 600; letter-spacing: -.035em; }
/* Divi 5's own dynamic CSS emits a bare `h1,h2,h3,h4,h5,h6{color:#333}`
   rule. A DIRECT declaration on an element always wins over an INHERITED
   value regardless of specificity, so every heading that relies on
   inheriting its color from a coloured section (.hero-copy, .craft-copy,
   .about-hero-copy, etc — the vast majority of h1/h2 in this design) was
   rendering dark grey instead of white/cream. Confirmed via Chrome
   DevTools Protocol CSS.getMatchedStylesForNode, same failure class as
   the padding/background section-level bug above. Fix: force headings
   back to inheriting (their real, intended behaviour) with `!important`,
   then re-promote every MORE SPECIFIC heading-color rule below (h1 em /
   h2 em and its section-scoped variants) to `!important` too so they
   still win over this blanket rule — among competing `!important`
   declarations normal specificity/order rules apply again. */
h1, h2, h3, h4, h5, h6 { color: inherit !important; }
h1 em, h2 em { color: var(--timber) !important; font-weight: 600; }
.hero-section { min-height: calc(100vh - 116px); display: grid; grid-template-columns: minmax(0, .9fr) minmax(520px, 1.1fr); background: var(--cream); }
.hero-copy { padding: clamp(70px, 8vw, 130px) clamp(28px, 4.5vw, 86px); display: flex; flex-direction: column; justify-content: center; position: relative; }
.hero-copy::before { content: ""; position: absolute; width: 40%; height: 55%; top: 10%; left: 8%; border: 1px solid rgba(156, 122, 90, .18); pointer-events: none; }
.hero-kicker { position: relative; color: var(--walnut); font-size: 11px; letter-spacing: .19em; text-transform: uppercase; font-weight: 700; }
.hero-copy h1 { position: relative; margin: 22px 0 28px; font-size: clamp(55px, 6.5vw, 104px); line-height: .92; }
.hero-copy h1 em { display: inline-block; margin-top: 8px; }
.hero-lede { position: relative; max-width: 560px; font-size: clamp(17px, 1.5vw, 21px); line-height: 1.65; color: #5e524b; }
.hero-actions { display: flex; align-items: center; gap: 32px; margin-top: 28px; }
.button-primary, .button-secondary, .button-sand { border: 1px solid transparent; min-height: 50px; padding: 0 25px; display: inline-flex; align-items: center; justify-content: center; gap: 10px; font-size: 12px; font-weight: 700; letter-spacing: .06em; transition: background 180ms var(--ease-out), color 180ms var(--ease-out), border 180ms var(--ease-out), transform 150ms var(--ease-out); }
.button-primary { background: var(--espresso); color: white; }
.button-primary:hover { background: var(--walnut); }
.button-secondary { border-color: var(--espresso); color: var(--espresso); background: transparent; }
.button-secondary:hover { background: var(--espresso); color: white; }
.button-sand { background: var(--sand); color: var(--espresso) !important; }
.button-sand:hover { background: var(--paper); }
.button-primary:active, .button-secondary:active, .button-sand:active { transform: scale(.97); }
.text-link { display: inline-flex; align-items: center; gap: 8px; padding: 10px 0; border-bottom: 1px solid rgba(59,42,34,.45); font-size: 13px; font-weight: 700; }
.text-link:hover { color: var(--walnut); }
.text-link.light { color: var(--sand); border-color: rgba(216,198,174,.55); }
.hero-proof { display: flex; gap: clamp(28px, 4vw, 64px); margin-top: clamp(52px, 7vw, 95px); padding-top: 23px; border-top: 1px solid var(--border-soft); }
.hero-proof div { display: flex; flex-direction: column; }
.hero-proof strong { font-family: var(--font-serif); font-size: 28px; line-height: 1; }
.hero-proof span { margin-top: 6px; font-size: 10px; color: var(--copy-muted); text-transform: uppercase; letter-spacing: .08em; }
.hero-visual { position: relative; min-height: 640px; overflow: hidden; }
.hero-visual > img { width: 100%; height: 100%; object-fit: cover; }
/* Hero carousel (added 2026-09-18, not in source — see DECISIONS.md): each
   .hero-visual-slide stacks in the same box via absolute positioning and
   crossfades opacity; JS (initHeroCarousel in deeds-pine.js) toggles
   .is-active every 5s. A single-slide hero (today's default) just shows
   its one .is-active image with no visible transition. */
.hero-visual > img.hero-visual-slide { position: absolute; inset: 0; opacity: 0; transition: opacity 1400ms ease; z-index: 0; }
.hero-visual > img.hero-visual-slide.is-active { opacity: 1; z-index: 1; }
.hero-visual::after { content: ""; position: absolute; inset: 0; background: linear-gradient(180deg, rgba(59,42,34,.04) 35%, rgba(59,42,34,.48) 100%); }
.grain-overlay { position: absolute; inset: 0; opacity: .13; mix-blend-mode: multiply; pointer-events: none; background-image: repeating-linear-gradient(95deg, transparent 0 23px, rgba(59,42,34,.08) 24px); z-index: 1; }
.hero-product-note { position: absolute; z-index: 3; left: 38px; right: 38px; bottom: 36px; background: rgba(251,249,245,.93); backdrop-filter: blur(10px); padding: 18px 20px; display: grid; grid-template-columns: 1fr auto auto; align-items: center; gap: 16px; }
.hero-product-note span { font-size: 13px; font-weight: 600; }
.hero-product-note strong { font-size: 13px; }
.hero-product-note a { width: 36px; height: 36px; display: grid; place-items: center; background: var(--espresso); color: white; }
.trust-strip { display: grid !important; grid-template-columns: repeat(4, 1fr); background: var(--sage); color: #fff; padding: 22px clamp(22px, 5vw, 80px) !important; column-gap: 20px; }
.trust-strip .ts-item { display: flex; gap: 12px; align-items: center; justify-content: center; font-size: 15px; line-height: 1.45; }
/* DEVIATION FROM SOURCE (approved 2026-09-18): source sets this at 11px;
   user asked to increase it for legibility. See DECISIONS.md. */
.trust-strip span { display: flex; flex-direction: column; color: rgba(255,255,255,.8); }
.trust-strip strong { color: white; }
.section { width: 100%; padding: clamp(85px, 9vw, 145px) clamp(20px, 3vw, 58px) !important; margin: 0; }
.section-heading h2 { margin: 0; font-size: clamp(44px, 5vw, 74px); line-height: 1.02; }
.split-heading { display: grid; grid-template-columns: 1fr minmax(300px, 460px); gap: 60px; align-items: end; margin-bottom: 56px; }
.split-heading > p { color: var(--copy-muted); font-size: 16px; line-height: 1.75; }
.centered-heading { text-align: center; margin: 0 auto 58px; }
.centered-heading > p:last-child { margin-top: 15px; color: var(--copy-muted); }
/* column-gap only — same phantom-second-grid-row issue as
   .values-section (see that comment): every multi-column grid built
   from dp_realrow()'s dissolved-column children gets a bogus
   `grid-template-rows: <content> 0px` from Chrome, and the shorthand
   `gap` was applying its row-gap value to that non-existent row,
   inflating section height for no visual reason. Confirmed via
   getComputedStyle().gridTemplateRows on every dp_realrow()-based grid
   in this build. */
.category-grid { display: grid !important; grid-template-columns: 1.1fr .9fr 1fr; column-gap: 16px; }
/* !important required: .category-card is an <a>, and `a{color:inherit
   !important}` (line 57, the site-wide Divi-link-blue guard) always wins
   over a plain (non-important) color rule on the same element regardless
   of class specificity — forces the anchor's own color to inherit from
   its ancestor chain, which walks all the way up through unstyled dp-shell/
   dp-flat wrapper divs to `.section{color:var(--foreground)!important}`
   (dark brown), instead of the intended white overlay-card text. Only
   `!important` here (0-1-0 class, beats `a`'s 0-0-1 element selector at
   equal importance) restores it. Confirmed on deeds-pine (2026-09-17
   section-by-section rebuild): every category card's h3/p rendered in
   near-invisible dark brown instead of white against the dark image
   overlay. */
.category-card { position: relative; min-height: 570px; overflow: hidden; display: block; color: white !important; }
.category-card img { width: 100%; height: 100%; object-fit: cover; position: absolute; transition: transform 700ms var(--ease-out); }
.category-card:hover img { transform: scale(1.035); }
.category-grid .cat-1 .category-card { min-height: 500px; margin-top: 70px; }
.category-overlay { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(43,33,28,.04) 25%, rgba(43,33,28,.78) 100%); }
.category-copy { position: absolute; left: 28px; right: 65px; bottom: 27px; }
.category-copy > span { font-size: 10px; letter-spacing: .16em; opacity: .75; }
.category-copy h3 { margin: 8px 0 6px; font-family: var(--font-serif); font-size: 38px; }
.category-copy p { margin: 0; font-size: 12px; opacity: .8; }
.category-arrow { position: absolute; right: 24px; bottom: 26px; width: 38px; height: 38px; border: 1px solid rgba(255,255,255,.55); display: grid; place-items: center; transition: background 180ms var(--ease-out), color 180ms var(--ease-out); }
.category-card:hover .category-arrow { background: white; color: var(--espresso); }
.featured-section { border-top: 1px solid var(--border-soft); padding-bottom: 20px !important; }
/* DEVIATION FROM SOURCE (approved 2026-09-18): source's generic .section class gives
   every section up to 145px of top+bottom padding via clamp(85px,9vw,145px), which is
   fine as a section's OWN internal breathing room but, combined with .craft-section's
   own clamp(30px,6vw,90px) top margin right after it, opened up to 235px of empty
   space specifically at this one transition (verified identical on the live reference
   app, not a build bug). .featured-section/.craft-section are each used exactly once,
   only on this Home-page transition, so scoping the fix to these two classes (rather
   than the shared .section class) can't affect any other section on the site. See
   DECISIONS.md. */
.product-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 48px 18px; }
.product-card { min-width: 0; }
.product-image-wrap { display: block; position: relative; aspect-ratio: .85; overflow: hidden; background: #ebe5dc; width: 100%; border: 0; padding: 0; text-align: left; }
.product-image { width: 100%; height: 100%; object-fit: cover; transition: transform 650ms var(--ease-out); }
.product-card:hover .product-image { transform: scale(1.025); }
.product-badge { position: absolute; left: 14px; top: 14px; padding: 7px 10px; background: var(--paper); color: var(--espresso); font-size: 9px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; }
.view-product { position: absolute; left: 14px; right: 14px; bottom: 14px; background: rgba(59,42,34,.9); color: white; min-height: 42px; padding: 0 15px; display: flex; justify-content: space-between; align-items: center; font-size: 11px; font-weight: 700; opacity: 0; transform: translateY(7px); transition: opacity 180ms var(--ease-out), transform 180ms var(--ease-out); }
.product-card:hover .view-product { opacity: 1; transform: translateY(0); }
/* Multi-image product cards (2026-09-19): a product with more than one
   real photo gets its extra images stacked as absolutely-positioned
   crossfading slides (same technique as .hero-visual-slide), auto-advanced
   by initProductCardCarousels() in deeds-pine.js. The active slide needs
   an explicit z-index above auto so it doesn't cover the badge/CTA
   overlay, which are position:absolute with no z-index of their own. */
.product-image.is-carousel-slide { position: absolute; inset: 0; opacity: 0; z-index: 0; transition: opacity 900ms ease, transform 650ms var(--ease-out); }
.product-image.is-carousel-slide.is-active { opacity: 1; z-index: 1; }
.product-badge, .view-product { z-index: 2; }
.product-card-body { display: flex; justify-content: space-between; align-items: flex-start; gap: 15px; padding-top: 16px; }
.product-category { margin: 0 0 6px; color: var(--timber); font-size: 9px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; }
.product-name { font-family: var(--font-serif); font-size: 20px; font-weight: 600; line-height: 1.2; border: 0; padding: 0; background: transparent; text-align: left; color: inherit; cursor: pointer; }
.product-name:hover { color: var(--walnut); }
.quick-add { flex: 0 0 34px; width: 34px; height: 34px; border: 1px solid var(--border-soft); background: transparent; display: grid; place-items: center; transition: background 180ms var(--ease-out), color 180ms var(--ease-out); }
.quick-add:hover { background: var(--espresso); color: white; }
.product-price { margin: 8px 0 0; color: var(--copy-muted); font-size: 13px; }
.center-action { text-align: center; margin-top: 62px; }
.craft-section { width: 100%; margin: 20px 0 0 !important; display: grid !important; grid-template-columns: 1.05fr .95fr; min-height: 800px; background: var(--espresso); color: var(--cream); }
.craft-image img { width: 100%; height: 100%; object-fit: cover; }
.craft-copy { padding: clamp(65px, 8vw, 125px); display: flex; flex-direction: column; justify-content: center; }
.craft-copy .eyebrow { color: var(--sand); }
.craft-copy h2 { font-size: clamp(50px, 5vw, 76px); line-height: .98; margin-bottom: 26px; }
.craft-copy > p:not(.eyebrow) { color: rgba(245,240,232,.73); line-height: 1.8; }
.craft-copy ul { list-style: none; padding: 0; margin: 38px 0; }
.craft-copy li { display: grid; grid-template-columns: 38px 1fr; gap: 16px; padding: 18px 0; border-top: 1px solid rgba(255,255,255,.14); }
/* white-space:nowrap needed: at 10px + .14em letter-spacing, "Choose"
   genuinely measures ~45.7px (Range/canvas-measured, confirmed identical
   glyph metrics between build and reference) against a 38px grid track —
   objectively too wide either way. The reference renders it on one line
   anyway (text quietly overflows into the row's 16px column-gap, which has
   room to spare); this build's default `white-space:normal` occasionally
   let the exact same text wrap to "Choo"/"se" instead, a sub-pixel
   line-breaking-threshold coin-flip (same class of hairline rendering
   variance already documented on this project's trust-strip labels) —
   force the single-line behavior explicitly rather than leave it to
   chance. */
.craft-copy li > span { color: var(--sand); font-size: 10px; letter-spacing: .14em; white-space: nowrap; }
.craft-copy li strong { display: block; margin-bottom: 5px; }
.craft-copy li p { margin: 0; color: rgba(245,240,232,.62); font-size: 12px; }
/* Testimonial marquee (added 2026-09-19, replaces the old .values-section
   "Why Deeds Pine" block entirely — not in the source app, see
   DECISIONS.md). Two rows scroll continuously in opposite directions via
   pure CSS animation. No JS needed: animation-play-state:paused on
   :hover handles the pause, and prefers-reduced-motion below freezes it.
   Fixed 2026-09-21: the loop used to hardcode 3 copies of each row's
   content + a rough -33.3334% shift — mathematically imprecise (didn't
   account for the missing trailing gap after the last copy, so every
   loop restart snapped back a few pixels early) AND not wide enough to
   guarantee full coverage on a wide/ultra-wide monitor, leaving a real
   gap of bare background once the visible window outran the remaining
   content (confirmed via screenshot). pages.php's
   deeds_pine_marquee_row_html() now repeats each row 8x and computes
   the exact per-row shift percentage from the real card-width/gap/count
   math, passed in as the `--marquee-shift` custom property on each
   .marquee-track element — this keyframe just reads that value, with a
   fallback matching the current 4-cards-per-row layout in case the
   custom property is ever missing. */
.testimonial-section { overflow: hidden; padding: 40px 0 !important; }
.marquee-row { position: relative; overflow: hidden; display: flex; }
.marquee-row + .marquee-row { margin-top: 22px; }
.marquee-row::before, .marquee-row::after { content: ""; position: absolute; top: 0; bottom: 0; width: 90px; z-index: 2; pointer-events: none; }
.marquee-row::before { left: 0; background: linear-gradient(90deg, var(--paper), transparent); }
.marquee-row::after { right: 0; background: linear-gradient(270deg, var(--paper), transparent); }
.marquee-track { display: flex; gap: 20px; flex-shrink: 0; width: max-content; animation: marquee-scroll 46s linear infinite; }
.marquee-row.reverse .marquee-track { animation-direction: reverse; }
.marquee-row:hover .marquee-track { animation-play-state: paused; }
@keyframes marquee-scroll { from { transform: translateX(0); } to { transform: translateX(calc(-1 * var(--marquee-shift, 16.7488%))); } }
.testimonial-card { flex-shrink: 0; width: 320px; background: var(--cream); border: 1px solid var(--border-soft); padding: 26px; }
.testimonial-card p { margin: 0; color: var(--espresso); line-height: 1.65; font-size: 14px; }
.testimonial-card .t-author { margin-top: 18px; display: flex; flex-direction: column; }
.testimonial-card .t-author strong { font-size: 13px; }
.testimonial-card .t-author span { margin-top: 2px; font-size: 10px; color: var(--copy-muted); text-transform: uppercase; letter-spacing: .08em; }
@media (prefers-reduced-motion: reduce) { .marquee-track { animation: none; } }
.closing-cta { background: var(--walnut); color: white; text-align: center; padding: clamp(90px, 12vw, 170px) 25px !important; margin-top: 35px; }
.closing-cta .eyebrow { color: var(--sand); }
.closing-cta h2 { font-size: clamp(53px, 7vw, 102px); line-height: .93; margin: 20px 0 42px; }
.closing-cta h2 em { color: var(--sand) !important; }

.page-hero { padding: clamp(75px, 9vw, 140px) clamp(20px, 3vw, 58px) !important; background: var(--cream); }
.page-hero .page-hero-inner { width: 100%; margin: 0; }
.page-hero h1 { font-size: clamp(60px, 8vw, 116px); line-height: .93; margin-bottom: 24px; }
.page-hero .page-hero-inner > p:last-child { max-width: 650px; color: var(--copy-muted); font-size: 16px; line-height: 1.7; }
.shop-layout { width: 100%; margin: 0; padding: 70px clamp(20px, 3vw, 58px) 140px !important; display: grid !important; grid-template-columns: 230px minmax(0, 1fr); gap: clamp(32px, 4vw, 72px); }
/* display:block !important below — .shop-sidebar and .shop-results are
   real (non-dissolved) dp5_realrow() rows with no grid/flex layout of
   their own in the source design (their children — filter-title/filter-
   list/shop-note, and toolbar/product-grid respectively — are meant to
   simply stack vertically, normal block flow). Without an explicit
   override, Divi's own `.et_flex_row{display:flex}` default still applies
   (row direction), laying those children out side-by-side instead of
   stacked — same collision class as every other real-grid fix above, just
   needing `block` instead of `grid` as the restored value. */
.shop-sidebar, .shop-results { display: block !important; }
.shop-sidebar { position: sticky !important; top: 130px; align-self: start; }
.filter-title { display: flex; align-items: center; gap: 8px; margin-bottom: 22px; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .12em; }
/* Pill filter buttons (changed 2026-09-19 from a vertical divided list
   with a "Browse" label, per user request — same click-to-filter JS,
   just a different look). */
.category-filter { display: flex; flex-wrap: wrap; gap: 10px; }
.category-filter button { border: 1px solid var(--border-soft); border-radius: 999px; background: transparent; padding: 9px 18px; color: var(--copy-muted); font-size: 13px; transition: background 160ms var(--ease-out), color 160ms var(--ease-out), border-color 160ms var(--ease-out); }
.category-filter button:hover { border-color: var(--timber); color: var(--espresso); }
.category-filter button.active { background: var(--espresso); border-color: var(--espresso); color: var(--paper); font-weight: 700; }
.shop-note { margin-top: 45px; padding: 25px; background: var(--sand); color: var(--espresso); }
.shop-note strong { display: block; font-family: var(--font-serif); font-size: 22px; line-height: 1.25; }
.shop-note > p:last-child { margin: 15px 0 0; font-size: 11px; line-height: 1.6; opacity: .75; }
.shop-toolbar { display: flex; justify-content: space-between; align-items: center; gap: 22px; margin-bottom: 34px; padding-bottom: 16px; border-bottom: 1px solid var(--border-soft); }
.search-field { min-width: 260px; display: flex; align-items: center; gap: 9px; }
.search-field input { width: 100%; border: 0; background: transparent; padding: 8px 0; outline: 0; font-size: 13px; }
.toolbar-meta { display: flex; align-items: center; gap: 24px; }
.toolbar-meta span { color: var(--copy-muted); font-size: 11px; }
.toolbar-meta select { border: 0; background: transparent; color: var(--espresso); font-size: 12px; padding: 8px 22px 8px 5px; }
.shop-product-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.empty-state { text-align: center; padding: 100px 20px; display: flex; flex-direction: column; align-items: center; gap: 14px; }
.empty-state h1, .empty-state h2 { font-size: clamp(36px, 5vw, 60px); margin: 0; }
.empty-state p { max-width: 520px; color: var(--copy-muted); line-height: 1.6; }
.page-empty { min-height: 65vh; justify-content: center; }

.dimension-row { padding: 15px 0; display: flex; gap: 12px; border-top: 1px solid var(--border-soft); border-bottom: 1px solid var(--border-soft); color: var(--copy-muted); font-size: 12px; }
.dimension-row span { display: flex; flex-direction: column; gap: 3px; }
.dimension-row strong { color: var(--espresso); }
.add-row { display: grid; grid-template-columns: 110px 1fr; gap: 10px; margin-top: 28px; }
.quantity-control { min-height: 50px; border: 1px solid var(--border-soft); display: grid; grid-template-columns: 1fr 32px 1fr; align-items: center; }
.quantity-control button { border: 0; background: transparent; display: grid; place-items: center; height: 100%; }
.quantity-control span { text-align: center; font-size: 12px; }
.add-button { width: 100%; }
.detail-assurances { margin-top: 24px; background: var(--cream); padding: 18px; display: grid; gap: 14px; }
.detail-assurances > div { display: flex; gap: 12px; align-items: flex-start; font-size: 10px; color: var(--copy-muted); }
.detail-assurances span { display: flex; flex-direction: column; }
.detail-assurances strong { color: var(--espresso); margin-bottom: 2px; }
.option-group { border: 0; padding: 0; margin: 32px 0; }
.option-group legend { width: 100%; margin-bottom: 13px; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .1em; }
.option-group legend span { float: right; color: var(--timber); text-transform: none; letter-spacing: 0; }
.variant-list { display: grid; gap: 7px; }
.variant-list button { position: relative; min-height: 48px; border: 1px solid var(--border-soft); background: transparent; padding: 11px 42px 11px 14px; display: flex; align-items: center; justify-content: space-between; gap: 20px; text-align: left; font-size: 11px; width: 100%; }
.variant-list button:hover, .variant-list button.active { border-color: var(--walnut); background: rgba(216,198,174,.16); }
.variant-list button strong { white-space: nowrap; }
.variant-list button svg { position: absolute; right: 14px; }
.finish-list { display: grid; grid-template-columns: repeat(5, 1fr); gap: 7px; }
.finish-list button { border: 1px solid transparent; background: transparent; padding: 5px; color: var(--copy-muted); }
.finish-list button.active { border-color: var(--walnut); color: var(--espresso); }
.finish-list small { display: block; margin-top: 6px; font-size: 8px; }
.finish-swatch { display: block; height: 42px; border: 1px solid rgba(59,42,34,.1); }
.finish-grey { background: #817b74; }.finish-brown { background: #6b4a3a; }.finish-light-oak { background: #cba87f; }.finish-grey-brown { background: #887569; }.finish-antique-age { background: #9c7a5a; }
details p, .product-config details li { color: var(--copy-muted); font-size: 12px; line-height: 1.7; }
details ul { padding-left: 18px; }
details summary { cursor: pointer; font-size: 12px; font-weight: 700; }

.about-hero { min-height: 720px; display: grid !important; grid-template-columns: 1.1fr .9fr; background: var(--espresso); color: white; }
.about-hero-copy { padding: clamp(75px, 8vw, 135px) clamp(28px, 4.5vw, 86px); display: flex; flex-direction: column; justify-content: center; }
.about-hero-copy .eyebrow { color: var(--sand); }
.about-hero-copy h1 { font-size: clamp(62px, 8vw, 118px); line-height: .91; margin-bottom: 30px; }
.about-hero-copy h1 em { color: var(--sand) !important; }
.about-hero-copy > p:last-child { max-width: 650px; color: rgba(255,255,255,.7); font-size: 18px; line-height: 1.75; }
.about-logo-wrap { display: grid; place-items: center; background: var(--timber); padding: clamp(40px, 8vw, 130px); }
.about-logo-wrap img { width: min(100%, 600px); border-radius: 50%; box-shadow: 0 40px 80px rgba(59,42,34,.22); }
.about-intro { display: grid !important; grid-template-columns: 1fr 1fr; column-gap: clamp(60px, 10vw, 160px); align-items: start; padding-top: 32px !important; padding-bottom: 32px !important; }
/* DEVIATION FROM SOURCE (approved 2026-09-18, proactive sweep after the
   4th negative-space report on Home): same fix as .values-section/
   .category-section/.featured-section. See DECISIONS.md. */
.about-intro h2 { font-size: clamp(48px, 5.5vw, 80px); line-height: 1; }
.about-intro-copy { padding-top: 15px; }
.about-intro-copy p { color: var(--copy-muted); line-height: 1.8; }
.about-intro-copy .large-copy { font-family: var(--font-serif); font-size: clamp(25px, 2.5vw, 35px); line-height: 1.35; color: var(--espresso); }
.about-image-band { width: 100%; height: 640px; margin: 0; position: relative; overflow: hidden; }
.about-image-band img { width: 100%; height: 100%; object-fit: cover; object-position: center top; }
.about-cta { margin-top: 0; }

.site-footer { background: var(--espresso); color: rgba(255,255,255,.7); padding: 75px clamp(24px, 6vw, 95px) 25px; }
.footer-grid { width: 100%; margin: 0; display: grid !important; grid-template-columns: 2fr repeat(3, 1fr); column-gap: 60px; }
.footer-intro { display: flex; gap: 18px; align-items: flex-start; }
.footer-intro img { width: 76px; height: 76px; border-radius: 50%; object-fit: cover; }
.footer-title { font-family: var(--font-serif); font-size: 28px; color: white; margin-bottom: 8px; }
.footer-intro div p:last-child { max-width: 280px; font-size: 11px; line-height: 1.6; }
.footer-heading { color: white; font-size: 10px; font-weight: 700; letter-spacing: .13em; text-transform: uppercase; }
.footer-grid .footer-col > a { display: block; margin: 11px 0; font-size: 11px; }
.footer-grid a:hover { color: var(--sand); }
.social-links { display: flex; gap: 7px; }
.social-links a { width: 38px; height: 38px; border: 1px solid rgba(255,255,255,.25); display: grid !important; place-items: center; }
.footer-small { margin-top: 18px; max-width: 250px; font-size: 10px; line-height: 1.6; }
.footer-bottom { width: 100%; margin: 65px 0 0; padding-top: 18px; border-top: 1px solid rgba(255,255,255,.13); display: flex; justify-content: space-between; gap: 20px; font-size: 9px; }
/* Real WhatsApp brand button (2026-09-20, replacing the earlier sage
   text pill): icon-only circular FAB in WhatsApp's own brand green, with
   a soft green glow, matching the platform's own floating-button
   convention rather than this site's usual palette. */
.whatsapp-float { position: fixed; right: 24px; bottom: 24px; z-index: 35; width: 60px; height: 60px; display: inline-flex; align-items: center; justify-content: center; border-radius: 50%; background: #25D366; color: white; box-shadow: 0 0 0 8px rgba(37,211,102,.18), 0 12px 32px rgba(0,0,0,.28); transition: transform 160ms var(--ease-out), box-shadow 180ms var(--ease-out); }
.whatsapp-float:hover { transform: translateY(-2px) scale(1.04); box-shadow: 0 0 0 10px rgba(37,211,102,.22), 0 14px 36px rgba(0,0,0,.32); }
.whatsapp-float:active { transform: scale(.96); }

.reveal { opacity: 0; transform: translateY(22px); transition: opacity 680ms var(--ease-out), transform 680ms var(--ease-out); }
.reveal-visible { opacity: 1; transform: translateY(0); }
.fade-up { animation: fade-up 700ms var(--ease-out) both; }.fade-in { animation: fade-in 900ms var(--ease-out) both; }.delay-1 { animation-delay: 80ms; }.delay-2 { animation-delay: 160ms; }.delay-3 { animation-delay: 240ms; }.delay-4 { animation-delay: 320ms; }
@keyframes fade-up { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: translateY(0); } }
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }

@media (min-width: 1600px) {
  .shop-product-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

@media (max-width: 1180px) {
  .site-header-inner { grid-template-columns: minmax(250px, 1fr) auto minmax(130px, 1fr); }
  .icon-button.menu-trigger { display: inline-grid; }
  .desktop-nav { display: none; }
  .brand-lockup { justify-self: center; }
  .header-actions { justify-self: end; }
  .hero-section { grid-template-columns: 1fr 1fr; }
  .hero-copy { padding: 70px 45px; }
  .hero-copy h1 { font-size: clamp(55px, 7vw, 78px); }
  .trust-strip { grid-template-columns: 1fr 1fr; }
  .trust-strip .ts-item { justify-content: flex-start; }
  .product-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .shop-product-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .craft-copy { padding: 65px; }
  .footer-grid { grid-template-columns: 2fr 1fr 1fr; }
  .footer-grid .footer-col-follow { grid-column: 2 / 4; }
}

@media (max-width: 860px) {
  .announcement { justify-content: center; text-align: center; }
  .site-header-inner { grid-template-columns: 1fr auto 1fr; height: 70px; padding: 0 16px; }
  .brand-lockup img { width: 42px; height: 42px; }
  .brand-name { font-size: 14px; }.brand-subtitle { font-size: 7px; }
  .hero-section { grid-template-columns: 1fr; min-height: 0; }
  .hero-copy { min-height: 620px; padding: 80px 24px 60px; }
  .hero-copy::before { left: 3%; width: 72%; }
  .hero-copy h1 { font-size: clamp(55px, 14vw, 82px); }
  .hero-visual { min-height: 620px; }
  .hero-product-note { left: 18px; right: 18px; bottom: 18px; }
  .split-heading { grid-template-columns: 1fr; gap: 20px; }
  .category-grid { grid-template-columns: 1fr 1fr; }
  .category-grid .cat-0 { grid-column: 1 / 3; }
  .category-grid .cat-1 .category-card { margin-top: 0; }
  .category-card { min-height: 450px !important; }
  .product-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .craft-section { grid-template-columns: 1fr; }
  .craft-image { height: 600px; }
  .shop-layout { grid-template-columns: 1fr; }
  .shop-sidebar { position: static; }
  .category-filter { flex-wrap: nowrap; overflow-x: auto; padding-bottom: 5px; }
  .category-filter button { flex: 0 0 auto; }
  .shop-note { display: none; }
  .about-hero { grid-template-columns: 1fr; }
  .about-logo-wrap { padding: 60px 20vw; }
  .about-intro { grid-template-columns: 1fr; }
  .footer-grid { grid-template-columns: 1fr 1fr; }
  .footer-intro { grid-column: 1 / 3; }
  .footer-grid .footer-col-follow { grid-column: auto; }
}

@media (max-width: 560px) {
  .brand-lockup div { display: none; }
  .header-actions .icon-button:first-child { display: none; }
  .hero-copy { min-height: 590px; }
  .hero-actions { align-items: flex-start; flex-direction: column; gap: 12px; }
  .hero-proof { gap: 20px; justify-content: space-between; }
  .hero-proof strong { font-size: 24px; }
  .hero-proof span { font-size: 8px; }
  .hero-visual { min-height: 510px; }
  .hero-product-note { grid-template-columns: 1fr auto; }
  .hero-product-note strong { grid-row: 2; }
  .hero-product-note a { grid-column: 2; grid-row: 1 / 3; }
  .trust-strip { grid-template-columns: 1fr; gap: 16px; }
  .category-grid { grid-template-columns: 1fr; }
  .category-grid .cat-0 { grid-column: auto; }
  .category-card { min-height: 420px !important; }
  .product-grid, .shop-product-grid, .three-grid { grid-template-columns: 1fr; }
  .product-image-wrap { aspect-ratio: 1 / 1.06; }
  .view-product { opacity: 1; transform: none; }
  .craft-image { height: 480px; }
  .craft-copy { padding: 60px 24px; }
  .shop-toolbar { align-items: stretch; flex-direction: column; }
  .search-field { min-width: 0; }
  .toolbar-meta { justify-content: space-between; }
  .finish-list { grid-template-columns: repeat(3, 1fr); }
  .add-row { grid-template-columns: 1fr; }
  .quantity-control { width: 130px; }
  .about-hero-copy { padding: 80px 24px; }
  .about-logo-wrap { padding: 50px 12vw; }
  .about-image-band { height: 550px; }
  .footer-grid { grid-template-columns: 1fr; }
  .footer-intro, .footer-grid > div:last-child { grid-column: auto; }
  .footer-bottom { flex-direction: column; }
}

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

/* ==========================================================================
   Luxury editorial layer — ported from client/src/luxury.css, which the
   source app loads AFTER index.css (see main.tsx: `import "./index.css"`
   then `import "./luxury.css"`). Kept in the same cascade position here so
   later same-specificity rules win identically to the reference.
   ========================================================================== */
:root {
  --luxury-ink: #241711;
  --luxury-espresso: #302018;
  --luxury-brown: #584034;
  --luxury-brass: #b69770;
  --luxury-champagne: #e6d8c5;
  --luxury-ivory: #f7f3ed;
  --luxury-cream: #eee5d9;
  --luxury-sage: #7d826f;
  --luxury-rule: rgba(182, 151, 112, .36);
}

body { background: var(--luxury-ivory) !important; color: var(--luxury-ink) !important; }

.announcement { min-height: 46px; background: #1d130f; color: rgba(247, 243, 237, .78); border-bottom: 1px solid rgba(230, 216, 197, .12); letter-spacing: .1em; font-size: 9px; padding: 8px 14px; line-height: 1.3; }
.announcement p { font-size: 17px; letter-spacing: .1em; }
.announcement a { color: var(--luxury-champagne); }
.site-header { background: rgba(36, 23, 17, .96); color: var(--luxury-ivory); border-color: rgba(230, 216, 197, .12); backdrop-filter: blur(18px) saturate(115%); }
.site-header-inner { height: 84px; }
.brand-lockup img { border-color: rgba(230, 216, 197, .34); box-shadow: 0 0 0 5px rgba(230, 216, 197, .04); }
.brand-name { color: white; letter-spacing: .11em; font-size: 18px; font-weight: 800; }
.brand-subtitle { color: var(--luxury-brass); letter-spacing: .18em; line-height: 1.2; }
.desktop-nav { gap: clamp(22px, 2.8vw, 42px); }
.desktop-nav a { color: rgba(255,255,255,.76); font-size: 11px; letter-spacing: .08em; text-transform: uppercase; padding: 25px 0; }
.desktop-nav a::after { background: var(--luxury-brass); bottom: 16px; }
.desktop-nav a:hover, .desktop-nav a.active { color: white; }
.header-actions .icon-button { color: var(--luxury-ivory); width: 48px; height: 48px; }
.header-actions .icon-button:hover { background: rgba(230,216,197,.1); }
.cart-button span { background: var(--luxury-brass); color: var(--luxury-ink); width: 23px; height: 23px; top: 1px; right: 0; }

.hero-section { position: relative; display: block !important; min-height: calc(100svh - 115px); background: var(--luxury-ink) !important; overflow: hidden; }
.hero-visual { position: absolute; inset: 0; min-height: 0; }
.hero-visual > img { object-position: center 56%; filter: saturate(.78) contrast(1.04) brightness(.78); transform: scale(1.01); }
.hero-visual::after { z-index: 2; background: linear-gradient(90deg, rgba(26,16,11,.94) 0%, rgba(30,18,13,.78) 35%, rgba(30,18,13,.25) 66%, rgba(30,18,13,.12) 100%), linear-gradient(0deg, rgba(20,12,8,.4), transparent 55%); }
.hero-copy { position: relative; z-index: 5; width: min(57%, 970px); min-height: calc(100svh - 115px); padding: clamp(78px, 9vw, 145px) clamp(28px, 4.5vw, 88px); color: white; }
.hero-copy::before { display: none; }
.hero-kicker { color: var(--luxury-champagne); letter-spacing: .13em; font-size: 9px; line-height: 1.35; }
.hero-copy h1 { font-size: clamp(72px, 7.7vw, 138px); line-height: .78; letter-spacing: -.045em; margin: 27px 0 35px; text-shadow: 0 3px 38px rgba(0,0,0,.18); font-weight: 800; }
.hero-copy h1 em { color: var(--luxury-champagne) !important; font-weight: 700; }
.hero-lede { max-width: 600px; color: rgba(255,255,255,.72); font-size: clamp(18px, 1.35vw, 22px); line-height: 1.75; }
.hero-actions { margin-top: 37px; }
.hero-actions .button-primary { background: var(--luxury-champagne); color: var(--luxury-ink) !important; border-color: var(--luxury-champagne); }
.hero-actions .button-primary:hover { background: white; border-color: white; }
.hero-actions .text-link { color: white; border-color: rgba(255,255,255,.34); font-size: 17px; }
.hero-proof { width: min(100%, 620px); margin-top: clamp(40px, 6vw, 70px); padding-top: 26px; border-color: rgba(255,255,255,.18); gap: clamp(20px, 3.5vw, 54px); }
/* DEVIATION FROM SOURCE (approved 2026-09-18): source uses margin-top:auto here, which
   pins this trust-strip to the very bottom of the viewport-height hero box via flex
   auto-margin, opening up to ~300px of dead space at common laptop window sizes
   (verified present in the live reference app too, not a build bug). Replaced with a
   fixed clamp so the strip sits a consistent, proportionate distance below the CTA
   buttons regardless of window height. See DECISIONS.md. */
.hero-proof strong { color: var(--luxury-champagne); font-size: clamp(18px, 1.55vw, 24px); font-weight: 800; }
.hero-proof span { color: rgba(255,255,255,.56); margin-top: 4px; letter-spacing: .04em; line-height: 1.3; }
.hero-product-note { left: auto; right: clamp(20px, 3vw, 58px); bottom: clamp(25px, 4vw, 58px); width: min(410px, 34vw); background: rgba(32,20,14,.86); color: white; border: 1px solid rgba(230,216,197,.3); padding: 20px 22px; }
.hero-product-note strong { color: var(--luxury-champagne); font-weight: 600; font-size: 17px; }
.hero-product-note span { font-size: 17px; }
.hero-product-note a { background: var(--luxury-champagne); color: var(--luxury-ink); }
.grain-overlay { opacity: .12; mix-blend-mode: screen; }

.trust-strip { background: var(--luxury-ink) !important; color: white; border-top: 1px solid rgba(230,216,197,.14); padding-top: 26px !important; padding-bottom: 26px !important; }
.trust-strip .ts-item { position: relative; }
.trust-strip .ts-divider::after { content: ""; position: absolute; right: 0; width: 1px; height: 28px; background: rgba(230,216,197,.18); }
.trust-strip svg { color: var(--luxury-brass); }
.trust-strip span { color: rgba(255,255,255,.55); }

/* Ported gap found via a computed-style diff against the live reference
   (.category-section .eyebrow measured 10px here vs 17px on the
   reference): the reference's luxury.css sets font-size:17px across this
   whole combined selector list in one rule — only the letter-spacing/
   line-height companion rule below got ported originally, this one never
   did. Added verbatim, not just for .eyebrow. */
.eyebrow, .hero-kicker, .announcement, .desktop-nav a, .brand-subtitle, .footer-heading, .product-category, .product-badge, .view-product, .pay-note, .image-disclaimer, .filter-title, .prototype-warning, .footer-bottom, .footer-small, .shop-toolbar, .social-links a, .contact-social-links a, .cart-button span, .hero-proof span { font-size: 17px; }
.eyebrow { color: var(--luxury-brass); letter-spacing: .13em; line-height: 1.35; }
h1, h2 { font-weight: 800 !important; letter-spacing: -.045em; }
.section-heading h2 { font-size: clamp(54px, 5.5vw, 90px); line-height: .9; }
/* The reference app's headings on light-background sections use a
   distinct token (`--foreground`, oklch(0.245 0.027 48) ≈ #2b1d15 — very
   close to but NOT the same as `--ink`/`--luxury-ink` used for body text/
   dark section backgrounds) rather than inheriting body's own (darker)
   base text color. Found via a computed-style diff against the live
   reference (getComputedStyle on .category-section h2 / .value-item h3 /
   .about-value h3 returned oklch(0.245 0.027 48) on the reference,
   rgb(36,23,17) i.e. --luxury-ink on this build) — the `color:inherit`
   heading fix above is correct for DARK sections (hero/craft/closing-cta,
   which set their own explicit white/cream color and headings correctly
   inherit it) but was chaining all the way up to body's own --luxury-ink
   for headings on LIGHT sections instead, since body's own text isn't
   actually what these headings use in the reference. `--ink` (#2b211c,
   already defined at :root) is close enough to be visually
   indistinguishable — setting it once here lets every light-section
   heading (category/featured/values/about-values — everything sharing
   the `.section` class) inherit the correct tone via the same mechanism. */
.section { background: var(--luxury-ivory) !important; color: var(--foreground) !important; }
.category-section { padding-top: 32px !important; padding-bottom: 20px !important; }
.featured-section { padding-top: 20px !important; }
/* DEVIATION FROM SOURCE (approved 2026-09-18): same pattern as the other
   tightened gaps — .category-section's bottom and .featured-section's
   top were still inheriting the base .section class's full
   clamp(85px,9vw,145px), since only the FACING edges of each section
   (category-section's top, featured-section's bottom) had been tightened
   earlier. This is the 4th instance of this pattern on Home — see
   DECISIONS.md, a full-page sweep is queued next. */
/* DEVIATION FROM SOURCE (approved 2026-09-18, same pattern as the
   .featured-section/.craft-section gap): source's top padding here
   (clamp(110px,11vw,180px)) matched the reference exactly (202px total
   gap after the trust-strip, verified identical on both apps) but read
   as excessive negative space. Tightened; .category-section is used
   exactly once (Home page only), so this can't affect any other
   section. See DECISIONS.md. */
.category-card { min-height: 650px; }
.category-grid { column-gap: 10px; }
.category-grid .cat-1 .category-card { min-height: 570px; margin-top: 80px; }
.category-card img { filter: saturate(.78) contrast(1.02); }
.category-overlay { background: linear-gradient(180deg, rgba(22,14,10,.02) 24%, rgba(22,14,10,.88) 100%); }
.category-copy > span { color: var(--luxury-champagne); font-size: 17px; }
.category-copy p { font-size: 17px; }
.category-copy h3 { font-size: clamp(28px, 2vw, 40px); font-weight: 800; }
.category-arrow { border-color: rgba(230,216,197,.5); }
.category-card:hover .category-arrow { background: var(--luxury-champagne); border-color: var(--luxury-champagne); }

.featured-section { background: #f1ebe3; border-color: var(--luxury-rule); }
.product-grid { gap: 60px 22px; }
.product-image-wrap { background: #ded5ca; aspect-ratio: .78; }
.product-image { filter: saturate(.72) contrast(1.015); }
.product-card:hover .product-image { transform: scale(1.035); filter: saturate(.9) contrast(1.025); }
.product-badge { background: rgba(36,23,17,.92); color: var(--luxury-champagne); letter-spacing: .15em; }
.view-product { background: rgba(36,23,17,.92); color: white; border-top: 1px solid rgba(230,216,197,.26); }
.product-card-body { padding-top: 20px; }
.product-name { font-size: 20px; font-weight: 800; }
.product-price { color: var(--luxury-brown); font-size: 13px; letter-spacing: .05em; }
.quick-add { border-color: var(--luxury-rule); color: var(--luxury-brown); flex-basis: 42px; width: 42px; height: 42px; }
.quick-add:hover { background: var(--luxury-ink); }

.button-primary, .button-secondary, .button-sand { min-height: 58px; padding: 0 28px; letter-spacing: .055em; text-transform: none; font-size: 17px; }
.button-primary { background: var(--luxury-ink); }
.button-primary:hover { background: var(--luxury-brown); }
.button-secondary { border-color: var(--luxury-ink); }
.button-secondary:hover { background: var(--luxury-ink); }
.button-sand { background: var(--luxury-champagne); }
.text-link { letter-spacing: .08em; text-transform: uppercase; font-size: 17px; }

.craft-section { background: var(--luxury-ink) !important; }
.craft-image img { filter: saturate(.62) contrast(1.08); }
.craft-copy { border-left: 1px solid rgba(230,216,197,.14); }
.craft-copy h2 { font-size: clamp(62px, 6vw, 100px); font-weight: 800; }
.craft-copy li { border-color: rgba(230,216,197,.14); }
.closing-cta { position: relative; overflow: hidden; background: var(--luxury-espresso) !important; }
.closing-cta::before { content: ""; position: absolute; inset: 28px; border: 1px solid rgba(230,216,197,.16); pointer-events: none; }
.closing-cta .cta-inner { position: relative; z-index: 1; }
.closing-cta h2, .about-intro h2, .about-image-band p { font-weight: 800; }

.page-hero { background: var(--luxury-ink) !important; color: white; }
.page-hero h1 em { color: var(--luxury-champagne) !important; font-weight: 700; }
.page-hero .page-hero-inner > p:last-child { color: rgba(255,255,255,.57); font-size: 17px; }
.shop-layout { background: var(--luxury-ivory) !important; }
.shop-note { background: var(--luxury-espresso); color: white; border-top: 2px solid var(--luxury-brass); }
.shop-note .eyebrow { color: var(--luxury-champagne); }
.shop-note strong { font-size: 25px; font-weight: 800; }
.category-filter button { border-color: rgba(182,151,112,.28); }
.shop-toolbar { border-color: var(--luxury-rule); }

.about-hero { background: var(--luxury-ink) !important; }
.about-logo-wrap { background: linear-gradient(145deg, #9b7957, #6b4a3a); }
.about-logo-wrap img { border: 1px solid rgba(230,216,197,.35); box-shadow: 0 42px 110px rgba(17,9,5,.44); }
.about-intro { background: var(--luxury-ivory) !important; }
.about-image-band img { filter: saturate(.7) contrast(1.04); }

.site-footer { background: #1d130f; border-top: 1px solid rgba(230,216,197,.13); }
.footer-title { font-size: 32px; font-weight: 800; }
.footer-heading { color: var(--luxury-champagne); letter-spacing: .18em; }
.footer-grid .footer-col > a { font-size: 17px; line-height: 1.55; }
.footer-intro div p:last-child { font-size: 17px; max-width: 350px; }
.social-links a { border-color: rgba(230,216,197,.24); width: 46px; height: 46px; }
.footer-bottom { font-size: 17px; line-height: 1.5; }

@media (max-width: 1180px) {
  .site-header { background: rgba(36,23,17,.98); }
  .mobile-nav-panel { background: var(--luxury-ink); color: white; }
  .mobile-nav-panel nav a { border-color: rgba(230,216,197,.17); font-size: 30px; font-weight: 800; }
  .mobile-nav-panel > p { color: rgba(255,255,255,.58); font-size: 17px; }
  .mobile-nav-panel .icon-button { color: white; }
  .hero-copy { width: 68%; }
}

@media (max-width: 860px) {
  .hero-section { min-height: 790px; }
  .hero-visual { position: absolute; }
  .hero-visual > img { object-position: 62% center; }
  .hero-visual::after { background: linear-gradient(90deg, rgba(24,14,10,.91), rgba(24,14,10,.58) 65%, rgba(24,14,10,.2)); }
  .hero-copy { width: 78%; min-height: 790px; padding: 92px 28px 64px; }
  .hero-copy h1 { font-size: clamp(64px, 12vw, 95px); }
  .hero-product-note { width: min(380px, calc(100% - 40px)); right: 20px; bottom: 20px; }
  .trust-strip .ts-second::after { display: none; }
  .category-grid .cat-1 .category-card { margin-top: 0; }
  .category-filter button { font-size: 17px; }
}

@media (max-width: 560px) {
  .announcement { font-size: 8px; letter-spacing: .12em; min-height: 42px; padding: 8px 14px; }
  .announcement p { font-size: 17px; letter-spacing: .1em; }
  .hero-section, .hero-copy { min-height: 740px; }
  .hero-copy { width: 100%; padding: 72px 22px 170px; justify-content: flex-start; }
  .hero-copy h1 { margin-top: 22px; font-size: clamp(59px, 18vw, 82px); line-height: .82; }
  .hero-lede { color: rgba(255,255,255,.8); }
  .hero-proof { margin-top: 34px; display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
  .hero-proof div:last-child { grid-column: 1 / -1; }
  .hero-proof strong { font-size: 19px; }
  .hero-proof span { font-size: 17px; }
  .hero-product-note { left: 18px; right: 18px; width: auto; }
  .trust-strip .ts-item::after { display: none !important; }
  .category-card { min-height: 480px !important; }
  .product-name { font-size: 27px; }
  .product-image-wrap { aspect-ratio: .8; }
  .closing-cta::before { inset: 14px; }
  .footer-bottom { font-size: 17px; }
}

/* Unified shop panels (product configurator + cart drawer) and direct-contact page */
.shop-panel-backdrop { position: fixed; inset: 0; z-index: 90; display: none; justify-content: flex-end; background: rgba(22, 13, 9, .62); backdrop-filter: blur(5px); animation: panel-fade 200ms var(--ease-out) both; }
.shop-panel-backdrop.open { display: flex; }
.shop-product-panel, .shop-cart-panel { position: relative; width: min(720px, 100%); min-height: 100%; overflow-y: auto; background: var(--luxury-ivory); box-shadow: -28px 0 80px rgba(0,0,0,.32); animation: panel-slide 300ms var(--ease-out) both; }
.shop-product-panel { display: grid; grid-template-columns: minmax(260px, .82fr) minmax(370px, 1.18fr); }
.panel-close { position: absolute; top: 18px; right: 18px; z-index: 4; width: 42px; height: 42px; border: 1px solid rgba(230,216,197,.36); display: grid; place-items: center; background: rgba(36,23,17,.9); color: white; transition: background 160ms var(--ease-out), transform 160ms var(--ease-out); border-width:1px; }
.panel-close:hover { background: var(--luxury-brown); }.panel-close:active { transform: scale(.96); }
.panel-close.static { position: static; background: var(--luxury-ink); flex: 0 0 42px; }
.panel-product-image { position: sticky; top: 0; align-self: start; height: 100vh; min-height: 600px; background: #d6ccc0; }
.panel-product-image img { width: 100%; height: 100%; object-fit: cover; filter: saturate(.76) contrast(1.02); }
.panel-product-image > span { position: absolute; top: 20px; left: 20px; padding: 8px 10px; background: var(--luxury-ink); color: var(--luxury-champagne); font-size: 8px; text-transform: uppercase; letter-spacing: .14em; }
.panel-product-content { padding: 78px clamp(26px, 4vw, 52px) 58px; }
.panel-product-content h2, .shop-cart-panel h2 { margin: 10px 0 16px; font-size: clamp(44px, 4.5vw, 66px); line-height: .86; font-family: var(--font-serif); font-weight: 800; }
.panel-summary { color: var(--copy-muted); font-size: 17px; line-height: 1.7; }
.panel-price { margin: 25px 0 4px; color: var(--luxury-brown); font: 800 31px/1 var(--font-serif); }
.panel-product-content .option-group { margin: 27px 0; }
.panel-product-content .detail-assurances { margin-top: 20px; }
.panel-product-content details { border-bottom: 1px solid var(--luxury-rule); padding: 17px 0; }
.panel-product-content details p, .panel-product-content details li { color: var(--copy-muted); font-size: 17px; line-height: 1.65; }
.panel-product-content details ul { padding-left: 18px; }
.panel-heading-row { display: flex; justify-content: space-between; align-items: flex-start; padding: 40px clamp(24px, 4vw, 56px) 26px; border-bottom: 1px solid var(--luxury-rule); }
.panel-heading-row .eyebrow { margin-bottom: 8px; }
.panel-heading-row h2 { margin: 0; }
.cart-panel-empty { min-height: 55vh; padding: 72px 40px; display: flex; flex-direction: column; justify-content: center; align-items: flex-start; gap: 18px; color: var(--luxury-ink); }
.cart-panel-empty h3 { margin: 0; font: 800 38px/.95 var(--font-serif); }.cart-panel-empty p { margin: 0; max-width: 360px; color: var(--copy-muted); line-height: 1.7; font-size: 17px; }
.cart-panel-items { padding: 0 clamp(24px, 4vw, 56px); }
.cart-panel-item { display: grid; grid-template-columns: 105px 1fr auto; align-items: start; gap: 17px; padding: 22px 0; border-bottom: 1px solid var(--luxury-rule); }
.cart-panel-image { border: 0; background: transparent; padding: 0; cursor: pointer; }.cart-panel-image img { width: 105px; height: 123px; object-fit: cover; filter: saturate(.75); }
.cart-panel-name { border: 0; padding: 0; background: transparent; color: var(--luxury-ink); text-align: left; font: 800 20px/1.05 var(--font-serif); cursor: pointer; }.cart-panel-name:hover { color: var(--luxury-brown); }
.cart-panel-item p { margin: 7px 0 0; color: var(--copy-muted); font-size: 17px; line-height: 1.35; }.cart-panel-actions { display: flex; min-width: 108px; flex-direction: column; align-items: flex-end; gap: 16px; }.cart-panel-actions > strong { font-size: 17px; white-space: nowrap; }
.cart-panel-summary { margin: 28px clamp(24px, 4vw, 56px) 48px; padding: 26px; background: var(--luxury-cream); border-top: 2px solid var(--luxury-brass); }.cart-panel-summary > div { display: flex; justify-content: space-between; gap: 18px; padding: 9px 0; font-size: 17px; }.cart-panel-summary > div strong { font-family: var(--font-serif); font-size: 17px; font-weight: 800; }.cart-panel-summary > p { color: var(--copy-muted); font-size: 17px; line-height: 1.6; margin: 14px 0 20px; }
@keyframes panel-fade { from { opacity: 0; } to { opacity: 1; } } @keyframes panel-slide { from { transform: translateX(34px); } to { transform: translateX(0); } }

.contact-hero { background: var(--luxury-ink) !important; color: white; padding: clamp(95px, 12vw, 180px) clamp(20px, 7vw, 120px) !important; }.contact-hero > .reveal { max-width: 900px; }.contact-hero .eyebrow { color: var(--luxury-champagne); }.contact-hero h1 { margin: 0 0 28px; font: 800 clamp(68px, 8.8vw, 142px)/.78 var(--font-serif); letter-spacing: -.052em; }.contact-hero h1 em { color: var(--luxury-champagne) !important; font-weight: 700; }.contact-hero p:last-child { max-width: 585px; color: rgba(255,255,255,.68); font-size: 17px; line-height: 1.75; }
.contact-content { display: grid !important; grid-template-columns: minmax(0, 1fr) minmax(370px, .85fr); column-gap: clamp(54px, 9vw, 170px); padding: clamp(82px, 10vw, 150px) clamp(20px, 7vw, 120px) !important; background: var(--luxury-ivory) !important; }.contact-primary h2 { max-width: 620px; margin: 0 0 45px; font: 800 clamp(50px, 5vw, 84px)/.88 var(--font-serif); letter-spacing: -.045em; }.contact-actions { display: grid; gap: 1px; background: var(--luxury-rule); }.contact-actions a { min-height: 105px; padding: 19px 21px; display: flex; align-items: center; gap: 16px; background: var(--luxury-ivory); transition: background 160ms var(--ease-out), color 160ms var(--ease-out); }.contact-actions a:hover { background: var(--luxury-cream); color: var(--luxury-brown); }.contact-actions svg { color: var(--luxury-brass); flex: 0 0 auto; }.contact-actions span { display: flex; flex-direction: column; gap: 5px; }.contact-actions strong { font: 800 23px/1 var(--font-serif); }.contact-actions small { color: var(--copy-muted); font-size: 11px; }
/* flex, not grid: this is just a simple vertical stack of 3 items (no
   2D layout need), and CSS Grid was persistently reserving space for a
   phantom trailing row track (confirmed via getComputedStyle().
   gridTemplateRows reporting a spurious extra "0px" row no matter how
   the explicit template/columns were declared — a genuine, unexplained
   Chromium quirk specific to this composition, not fixed by any of the
   column-gap/grid-template-rows/grid-template-columns variants tried).
   Flexbox has no row/column track concept to misfire this way, and the
   1px hairline divider between items still works via a bottom border
   substituted for the old gap-as-divider trick. */
.contact-details { display: flex !important; flex-direction: column !important; gap: 0 !important; align-content: start; background: var(--luxury-rule); border-top: 2px solid var(--luxury-brass); }
.contact-details .cd-item.cd-divider { border-bottom: 1px solid var(--luxury-rule); }
.contact-details .cd-item { min-height: 150px; padding: 28px; display: flex; gap: 15px; background: #f1ebe3; }.contact-details .cd-item > svg { color: var(--luxury-brass); flex: 0 0 auto; }.contact-details span { display: flex; flex-direction: column; }.contact-details strong { font: 800 23px/1.1 var(--font-serif); }.contact-details p { margin: 10px 0 0; color: var(--copy-muted); font-size: 17px; line-height: 1.7; }
.contact-social { padding: clamp(90px, 12vw, 180px) clamp(20px, 7vw, 120px) !important; background: linear-gradient(115deg, var(--luxury-brown), var(--luxury-espresso)) !important; color: white; }.contact-social .reveal { max-width: 930px; }.contact-social .eyebrow { color: var(--luxury-champagne); }.contact-social h2 { margin: 0 0 17px; font: 800 clamp(54px, 6vw, 96px)/.88 var(--font-serif); }.contact-social > .reveal > p:not(.eyebrow) { max-width: 550px; color: rgba(255,255,255,.7); line-height: 1.7; font-size: 17px; }.contact-social-links { display: flex; flex-wrap: wrap; gap: 9px; margin-top: 34px; }.contact-social-links a { min-height: 56px; padding: 0 21px; display: inline-flex; gap: 10px; align-items: center; border: 1px solid rgba(230,216,197,.42); color: white; font-size: 17px; text-transform: none; letter-spacing: .04em; transition: background 160ms var(--ease-out), color 160ms var(--ease-out); }.contact-social-links a:hover { background: var(--luxury-champagne); color: var(--luxury-ink); }

@media (max-width: 860px) { .shop-product-panel { width: min(640px, 100%); grid-template-columns: 1fr; }.panel-product-image { position: relative; height: min(56vh, 520px); min-height: 340px; }.panel-product-content { padding: 34px 24px 52px; padding-bottom: 80px; }.contact-content { grid-template-columns: 1fr; gap: 56px; }.contact-hero, .contact-content, .contact-social { padding-left: 24px !important; padding-right: 24px !important; } .shop-product-panel { width: 100%; } .cart-panel-item { grid-template-columns: 90px 1fr; } .cart-panel-image img { width: 90px; height: 108px; } .cart-panel-actions { grid-column: 2; flex-direction: row; align-items: center; } }
@media (max-width: 560px) { .shop-product-panel, .shop-cart-panel { width: 100%; }.panel-product-image { height: 385px; min-height: 0; }.panel-product-content h2, .shop-cart-panel h2 { font-size: 52px; }.panel-product-content { padding-left: 20px; padding-right: 20px; }.panel-heading-row { padding: 30px 20px 22px; }.cart-panel-items { padding: 0 20px; }.cart-panel-item { grid-template-columns: 78px 1fr; gap: 12px; }.cart-panel-image img { width: 78px; height: 96px; }.cart-panel-actions { grid-column: 2; flex-direction: row; align-items: center; justify-content: space-between; min-width: 0; }.cart-panel-summary { margin: 24px 20px 35px; padding: 21px; }.contact-hero h1 { font-size: clamp(59px, 17vw, 82px); }.contact-primary h2 { font-size: 54px; }.contact-actions a { min-height: 86px; padding: 16px; }.contact-details .cd-item { padding: 23px; }.contact-social h2 { font-size: 58px; }.toolbar-meta { gap: 14px; }.toolbar-meta span { display: none; }.finish-list { grid-template-columns: repeat(2, 1fr); }.contact-actions strong, .contact-details strong { font-size: 21px; } }

/* Contact form */
.contact-form-layout { display: grid; grid-template-columns: minmax(0, .8fr) minmax(420px, 1.2fr); column-gap: clamp(48px, 7vw, 110px); align-items: start; }
.contact-form-intro h2 { font-size: clamp(48px, 5.2vw, 84px); margin: 10px 0 20px; }
.contact-form-intro > p:not(.eyebrow) { color: var(--copy-muted); font-size: 17px; line-height: 1.75; }
.contact-direct-links { display: flex; flex-direction: column; gap: 14px; margin-top: 36px; padding-top: 28px; border-top: 1px solid var(--luxury-rule); }
.contact-direct-links a { display: inline-flex; align-items: center; gap: 12px; color: var(--luxury-ink); font-size: 17px; font-weight: 600; }
.contact-direct-links a:hover { color: var(--luxury-brown); }
.contact-direct-links svg { color: var(--luxury-brass); }
.contact-form-card { background: #fbf8f3; border: 1px solid var(--luxury-rule); border-top: 3px solid var(--luxury-brass); padding: clamp(28px, 5vw, 60px); }
.enquiry-form label { display: flex; flex-direction: column; gap: 8px; margin-bottom: 20px; font-size: 17px; font-weight: 600; color: var(--luxury-ink); }
.enquiry-form input, .enquiry-form select, .enquiry-form textarea { width: 100% !important; border: 1px solid rgba(182, 151, 112, .45) !important; background: white !important; padding: 15px 17px !important; font-size: 17px; color: var(--luxury-ink) !important; font-family: var(--font-sans); box-sizing: border-box; }
/* DEVIATION/FIX (2026-09-19): Divi's own compound selector
   (input.text, input.title, input[type="email"], input[type="password"],
   input[type="tel"], input[type="text"], select, textarea) sets
   background-color/border/padding/color at equal specificity, and was
   silently winning on any input with an EXPLICIT type attribute
   (email/tel) while inputs with no type attribute (first_name/last_name,
   which default to text without the literal attribute) escaped it —
   explaining why some contact-form fields rendered at 34px tall with 2px
   padding while others rendered correctly at 60px. Same "Divi's own CSS
   wins the cascade tie" bug class documented repeatedly on this project;
   see DECISIONS.md. */
.enquiry-form input:focus, .enquiry-form select:focus, .enquiry-form textarea:focus { border-color: var(--luxury-brass); outline: 2px solid rgba(182, 151, 112, .25); }
.form-grid { display: grid; gap: 15px; }.form-grid.two { grid-template-columns: 1fr 1fr; }
.consent-field { flex-direction: row !important; align-items: flex-start; gap: 12px; margin: 8px 0 26px; font-weight: 500; font-size: 17px; color: var(--copy-muted); }
.consent-field input { width: 22px; height: 22px; margin-top: 4px; accent-color: var(--luxury-brown); }
.enquiry-success { padding: 40px 10px; display: flex; flex-direction: column; align-items: flex-start; gap: 14px; }
.enquiry-success svg { color: var(--luxury-sage); }
.enquiry-success h2 { margin: 0; font-size: clamp(38px, 4vw, 56px); }
.enquiry-success p { margin: 0 0 16px; color: var(--copy-muted); line-height: 1.7; font-size: 17px; }
.form-error { color: #8e2b20; font-size: 17px; margin-bottom: 18px; font-weight: 600; }
.contact-details-band { background: var(--luxury-ivory) !important; padding: 0 clamp(20px, 7vw, 120px) clamp(70px, 8vw, 120px) !important; }

@media (max-width: 860px) {
  .contact-form-layout { grid-template-columns: 1fr; gap: 40px; }
  .contact-form-card { padding: 28px 22px; }
  .contact-details-band { padding-left: 24px !important; padding-right: 24px !important; }
}

/* Utility used by empty product grids on the Shop page */
.three-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }

/* Terms & Conditions page (added 2026-09-21) — simple text-hero + long-form
   legal body, deliberately NOT using the marketing hero/heading sizes used
   elsewhere (clamp(54px+...)) since this is a document to read, not a
   landing section. */
.terms-hero { padding-bottom: 10px !important; }
.terms-hero h1 { font-size: clamp(38px, 5vw, 60px); line-height: 1.05; margin: 18px 0 20px; }
.terms-hero .lede { max-width: 640px; color: var(--copy-muted); line-height: 1.7; font-size: 16px; }
.terms-body { padding-top: 10px !important; }
.legal-content { max-width: 760px; margin: 0 auto; }
.legal-content h2 { font-size: clamp(26px, 3vw, 34px); line-height: 1.2; margin: 48px 0 18px; }
.legal-content h2:first-child { margin-top: 0; }
.legal-content h3 { font-size: 18px; font-weight: 700; letter-spacing: -.01em; margin: 26px 0 8px; }
.legal-content p { color: var(--copy-muted); line-height: 1.75; font-size: 15px; margin: 0 0 4px; }
.legal-content a { text-decoration: underline; text-underline-offset: 3px; }
.legal-updated { margin-top: 40px !important; padding-top: 20px; border-top: 1px solid var(--border-soft); font-size: 13px !important; font-style: italic; }

/* Cookie consent banner (added 2026-09-21, POPIA/cookie-policy requirement)
   — bottom-fixed bar shown once per browser until accepted (localStorage
   flag, see initCookieConsent() in deeds-pine.js). Nudges the WhatsApp
   float button up via .has-cookie-banner on <body> so the two fixed
   elements never visually overlap. */
.cookie-consent-banner { position: fixed; left: 0; right: 0; bottom: 0; z-index: 60; display: none; align-items: center; justify-content: space-between; gap: 24px; flex-wrap: wrap; background: var(--espresso); color: rgba(255,255,255,.88); padding: 20px clamp(20px, 4vw, 48px); box-shadow: 0 -12px 32px rgba(0,0,0,.22); }
.cookie-consent-banner.is-visible { display: flex; }
.cookie-consent-banner p { margin: 0; font-size: 13px; line-height: 1.6; max-width: 720px; }
.cookie-consent-banner a { color: white !important; text-decoration: underline; text-underline-offset: 3px; }
.cookie-consent-banner .button-primary { flex-shrink: 0; }
body.has-cookie-banner .whatsapp-float { bottom: 104px; }
@media (max-width: 640px) {
  .cookie-consent-banner { flex-direction: column; align-items: flex-start; padding: 18px 20px; }
  body.has-cookie-banner .whatsapp-float { bottom: 154px; }
}
