/*
 * be.Bold — shell.css
 * ===================
 * Tokens, resets, type helpers and site chrome. Loaded on every page.
 *
 * ⚑ SCAFFOLD STATE. This file was extracted from beboldv3/homepage.html by taking whole banner
 * sections: tokens, type helpers, announcement bar, header, footer, mobile drawer, reveal and
 * responsive, plus the .btn / .sect / .wrap component blocks that the design happens to define
 * inside its hero and generic-section banners.
 *
 * Still to do in the de-inline + split phase:
 *   - the `responsive` block below is the homepage's ENTIRE media-query stack. Its chrome queries
 *     belong here; the hero / collection / philosophy / FAQ / Instagram queries must move out to
 *     the page files. They are inert until then (those classes are not on the page), so this is
 *     safe but untidy.
 *   - run the shared-rule analysis across all 7 pages and lift the ~39% of lines that repeat on
 *     six or more of them into this file.
 *
 * Do not hand-edit rules here to fix one page. Page-specific CSS goes in assets/css/pages/<slug>.css.
 */

/* ============ tokens ============ */
:root{
  /* secondary — British Racing Green */
  --green:#004225;
  --green-deep:#00331C;
  --green-mid:#0A5533;
  /* main */
  --cream:#EAE2D8;
  --cream-alt:#E1D8CB;
  --sand-hi:#F3EDE5;
  --beige:#DFD5C7;
  /* accent */
  --gold:#A88240;
  /* CTA button colour — swap these two to retheme every button on the page */
  --btn-bg:#004225;
  --btn-fg:#EAE2D8;
  --btn-hover-fg:#004225;   /* button text once the fill drops away on hover */
  --gold-soft:#C6A467;
  --ink:#26241F;
  --muted:#5F5B4E;
  --hair:rgba(0,66,37,.16);
  /* The one non-brand colour: form and notice errors. It was a bare #8C2F2F inside
   * .woocommerce-error until 9 Sep 2026, when the invalid-field states needed the same tone
   * in four more places. */
  --error:#8C2F2F;
  --error-tint:rgba(140,47,47,.05);
  --hair-light:rgba(234,226,216,.26);
  --hdr-h:74px;
  --pad:clamp(20px,4.6vw,68px);
  --gap:clamp(24px,3vw,48px);
  /* The minimum hit area for anything you tap. WCAG 2.2 AA (2.5.8) floors it at 24x24; 44x44 is
     what Apple and Google both advise, and what a thumb actually needs. See the header tools. */
  --tap:44px;
}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{
  margin:0;background:var(--cream);color:var(--ink);
  font-family:'Poppins',system-ui,-apple-system,'Segoe UI',sans-serif;
  font-weight:300;font-size:16px;line-height:1.65;
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}
img,svg{display:block;max-width:100%}
a{color:inherit;text-decoration:none}
button,input{font:inherit;color:inherit}
:focus-visible{outline:2px solid var(--gold);outline-offset:3px}

/* ============ type helpers ============ */
.eyebrow{
  font-size:clamp(.6rem,.72vw,.7rem);letter-spacing:.24em;text-transform:uppercase;
  font-weight:400;color:var(--muted);line-height:1;margin:0;
}
.eyebrow--light{color:var(--gold-soft)}
.dsp{
  font-family:'Poppins',system-ui,-apple-system,'Segoe UI',sans-serif;font-weight:500;
  color:var(--green);letter-spacing:-.005em;line-height:1.12;margin:0;
}
.h2{font-size:clamp(1.54rem,2.53vw,2.41rem)}
.rule{width:46px;height:2px;background:var(--gold);border:0;margin:22px 0 0}
.rule--center{margin-left:auto;margin-right:auto}
.philo-copy .rule{margin:24px 0}
.body-sm{font-size:clamp(.88rem,1.1vw,1rem);color:var(--muted);line-height:1.85;margin:0}
.lnk{
  display:inline-flex;align-items:center;gap:12px;
  font-size:.68rem;letter-spacing:.2em;text-transform:uppercase;color:var(--green);
  padding-bottom:3px;border-bottom:1px solid transparent;transition:border-color .3s;
}
.lnk .ar{width:26px;height:1px;background:currentColor;position:relative;transition:width .3s}
.lnk .ar::after{content:"";position:absolute;right:0;top:-2.5px;width:5px;height:5px;
  border-top:1px solid currentColor;border-right:1px solid currentColor;transform:rotate(45deg)}
.lnk:hover{border-color:currentColor}
.lnk:hover .ar{width:36px}

/* ============ long-form editor content ============ */

/*
 * The pages with no design template — Shipping & Returns, Terms of Use, Privacy Policy — render
 * their EDITOR content through page.php into `.page-body`. That is deliberate: policy copy changes
 * (shipping rates especially) and the client must be able to edit it without a developer.
 *
 * Until now nothing styled that content, so a client-entered <h2> or <ul> came out in the browser's
 * defaults — Times-ish bold headings and disc bullets — on an otherwise fully typeset site.
 *
 * ⚑ Scoped `body:not(.woocommerce-page)`, and that guard is load-bearing. page.php is ALSO the
 * template behind cart, checkout, the account area and order-received, whose markup is full of <p>,
 * <h2>, <ul> and <table> that woo.css styles deliberately. Without the guard these prose rules
 * would reach into all of it — and several would win, because a bare `.page-body p` beats nothing.
 */
body:not(.woocommerce-page) .page-body{
  /* A measure, not the 1560px wrap: policy copy is read, and 74ch is where a line stays scannable. */
  max-width:74ch;
  /* Clears page.php's <hr class="rule">, which sits OUTSIDE this box — without it the first
   * heading prints on top of the gold rule. */
  margin-top:clamp(30px,3.4vw,46px);
  font-size:clamp(.92rem,1.05vw,1rem);line-height:1.9;color:var(--muted);
}
body:not(.woocommerce-page) .page-body>:first-child{margin-top:0;padding-top:0;border-top:0}
body:not(.woocommerce-page) .page-body p{margin:0 0 1.15em}
body:not(.woocommerce-page) .page-body>*:last-child{margin-bottom:0}

/*
 * A hairline above each top-level section, which is what separates Shipping / Returns / Exchanges
 * on a long page without adding a second navigation. Suppressed on the first by the :first-child
 * rule above, so it never lands straight under the page's gold rule.
 */
body:not(.woocommerce-page) .page-body h2{
  font-family:'Poppins',system-ui,-apple-system,'Segoe UI',sans-serif;font-weight:500;
  font-size:clamp(1.22rem,1.75vw,1.58rem);line-height:1.2;letter-spacing:-.005em;
  color:var(--green);
  margin:clamp(40px,4.6vw,64px) 0 0;padding-top:clamp(26px,3vw,38px);
  border-top:1px solid var(--hair);
}
body:not(.woocommerce-page) .page-body h2+*{margin-top:clamp(14px,1.8vw,22px)}
body:not(.woocommerce-page) .page-body h3{
  font-family:'Poppins',system-ui,-apple-system,'Segoe UI',sans-serif;font-weight:500;
  font-size:clamp(.98rem,1.15vw,1.08rem);line-height:1.4;color:var(--ink);
  margin:clamp(24px,2.8vw,36px) 0 .55em;
}

/* A gold dash rather than a disc — the same accent as the section rules, and it stops a policy
 * page reading like a word-processor document. */
body:not(.woocommerce-page) .page-body ul{list-style:none;margin:0 0 1.15em;padding:0}
body:not(.woocommerce-page) .page-body ul li{position:relative;padding-left:22px;margin:0 0 .55em}
body:not(.woocommerce-page) .page-body ul li::before{
  content:"";position:absolute;left:0;top:.92em;width:9px;height:1px;background:var(--gold);
}
body:not(.woocommerce-page) .page-body ol{margin:0 0 1.15em;padding-left:22px}
body:not(.woocommerce-page) .page-body li:last-child{margin-bottom:0}

body:not(.woocommerce-page) .page-body strong{color:var(--ink);font-weight:500}
body:not(.woocommerce-page) .page-body a{color:var(--green);border-bottom:1px solid var(--hair)}
body:not(.woocommerce-page) .page-body a:hover{border-bottom-color:currentColor}

/*
 * A rate card. The shipping fees are tabular data — destination against price — and a table answers
 * "what will this cost me" far faster than a bulleted list of dashes. Kept as a Table block so it
 * stays editable, and narrow so it does not stretch a two-column table across the measure.
 */
body:not(.woocommerce-page) .page-body figure.wp-block-table{margin:0 0 1.3em;max-width:440px}
body:not(.woocommerce-page) .page-body table{width:100%;border-collapse:collapse;border:0}
/*
 * ⚑ WordPress draws a full 1px box on every cell of a Table block, plus a 3px rule under the
 * thead. It comes from the INLINED per-block style (`<style id="wp-block-table-inline-css">`), not
 * from wp-block-library — functions.php dequeues that monolithic file, but core still inlines the
 * styles for whichever blocks a page actually uses. Which also means blocks the client adds later
 * arrive with their own base styles, and those may need the same treatment.
 *
 * Only the horizontal rules are wanted here, so the box is cleared before they are put back.
 */
body:not(.woocommerce-page) .page-body table th,
body:not(.woocommerce-page) .page-body table td{border:0}
body:not(.woocommerce-page) .page-body table th{
  padding:0 0 10px;border-bottom:1px solid var(--hair);text-align:left;
  font-size:.6rem;letter-spacing:.18em;text-transform:uppercase;font-weight:700;color:var(--ink);
}
body:not(.woocommerce-page) .page-body table td{
  padding:12px 0;border-bottom:1px solid var(--hair);
  font-size:.95rem;color:var(--ink);
}
body:not(.woocommerce-page) .page-body table th:last-child,
body:not(.woocommerce-page) .page-body table td:last-child{
  text-align:right;white-space:nowrap;width:1%;padding-left:20px;
}

/* ============ buttons ============ */
.btn{
  display:inline-flex;align-items:center;gap:26px;background:var(--btn-bg);color:var(--btn-fg);
  padding:15px 22px;font-size:.66rem;letter-spacing:.2em;text-transform:uppercase;
  border:1px solid var(--btn-bg);border-radius:6px;transition:background .35s,color .35s;
}
.btn .ar{width:26px;height:1px;background:currentColor;position:relative;transition:width .3s}
.btn .ar::after{content:"";position:absolute;right:0;top:-2.5px;width:5px;height:5px;
  border-top:1px solid currentColor;border-right:1px solid currentColor;transform:rotate(45deg)}
.btn:hover{background:transparent;color:var(--btn-hover-fg)}
.btn:hover .ar{width:34px}
.btn--bold{font-weight:700}

/* ============ section + wrap ============ */
.sect{padding:clamp(38px,4.2vw,60px) var(--pad)}
.sect--tight{padding-top:clamp(30px,3.4vw,46px);padding-bottom:clamp(30px,3.4vw,46px)}
.wrap{max-width:1560px;margin:0 auto}

/* ============ announcement bar ============ */
.abar{background:var(--green);color:var(--cream);height:25px;display:flex;align-items:center;
  padding:0 var(--pad);position:relative}
.abar-msg{position:absolute;left:50%;transform:translateX(-50%);white-space:nowrap;
  font-size:10.96px;font-weight:700;letter-spacing:.3px}
.abar-utils{margin-left:auto;display:flex;align-items:center;gap:10px;
  font-size:10px;font-weight:400;letter-spacing:.13em;text-transform:uppercase}
.abar-utils a{color:rgba(234,226,216,.82)}
.abar-utils a:hover,.abar-utils a[aria-current]{color:var(--sand-hi)}
.abar-utils i{font-style:normal;color:rgba(234,226,216,.4)}

/* ============ header ============ */
.hdr{position:sticky;top:0;z-index:60;background:transparent;
  border-bottom:1px solid transparent;
  display:flex;align-items:center;gap:clamp(18px,3.2vw,58px);
  padding:0 var(--pad);height:var(--hdr-h);
  transition:background .4s ease,border-color .4s ease,box-shadow .4s ease}
/* legibility scrim while the header floats over the hero */
.hdr::before{content:"";position:absolute;left:0;right:0;top:0;height:150%;pointer-events:none;
  background:linear-gradient(180deg,rgba(234,226,216,.82) 0%,rgba(234,226,216,.45) 55%,rgba(234,226,216,0) 100%);
  transition:opacity .4s ease}
.hdr>*{position:relative}
.hdr.is-stuck{background:var(--cream);border-bottom-color:var(--hair);
  box-shadow:0 2px 20px rgba(0,40,22,.09)}
.hdr.is-stuck::before{opacity:0}
/*
 * ⚑ TAP TARGETS, 14 Sep 2026. --tap (the 44x44 box) is a :root token — .hdr-search and .drawer are
 * SIBLINGS of <header>, not children of it, so a declaration here would not reach them, and the
 * search panel's close button silently fell back to `width:auto` and got SMALLER when it was.
 * --tap-icon is the header's own glyph size and stays here: .hdr-cart-count derives its offsets
 * from it, because the badge hangs off the ICON's corner, not the box's.
 */
.hdr{--tap-icon:19px}

/* min-height, not height: the logo is 22-25px, and a 22px-tall link is a 22px-tall target. */
.logo-link{flex:0 0 auto;display:flex;align-items:center;min-height:var(--tap);line-height:0}
.logo{height:25px;width:auto}

.mainnav{display:flex;align-items:stretch;height:var(--hdr-h);margin:0;padding:0;list-style:none}
.mainnav>li{position:relative;display:flex;align-items:center}
.mainnav>li>a{display:flex;align-items:center;gap:10px;height:100%;position:relative;
  padding:0 clamp(11px,1.2vw,19px);
  font-size:.82rem;font-weight:600;letter-spacing:.1em;text-transform:uppercase;
  color:var(--ink);transition:color .3s}
.mainnav>li:hover>a,.mainnav>li:focus-within>a{color:var(--green)}
/* The design marks the current top-level nav item; see bebold_aria_current(). */
.mainnav>li>a[aria-current]{color:var(--green)}
.caret{width:6px;height:6px;border-right:1.2px solid currentColor;border-bottom:1.2px solid currentColor;
  transform:rotate(45deg) translate(-2px,-2px);opacity:.45;
  transition:transform .3s,opacity .3s}
.mainnav>li:hover .caret{opacity:.95;transform:rotate(225deg) translate(-1px,-1px)}

.submenu{position:absolute;top:100%;left:0;min-width:264px;margin:0;padding:14px 0;list-style:none;
  background:var(--sand-hi);box-shadow:0 18px 44px rgba(0,40,22,.16);border-radius:8px;
  opacity:0;visibility:hidden;transform:translateY(8px);
  transition:opacity .28s,transform .28s,visibility .28s}
.mainnav>li:hover>.submenu,.mainnav>li:focus-within>.submenu{opacity:1;visibility:visible;transform:none}
.submenu a{display:block;position:relative;padding:10px 24px;font-size:clamp(.76rem,.95vw,.87rem);font-weight:300;
  letter-spacing:.012em;color:var(--muted);transition:color .28s,padding-left .28s}
.submenu a:hover{color:var(--green);padding-left:30px}

/*
 * The cart and account icons became anchors when WooCommerce arrived (they were inert <button>s in
 * the design). .hdr-tool is listed alongside `button` in each rule rather than replacing it, so
 * both elements get the identical box — the header's verified geometry does not move.
 */
/*
 * ⚑ The design's 2px padding made these 23x23 (and the burger 24x18) — under WCAG 2.2 AA's 24x24
 * floor, on the three controls a phone shopper uses most. They are 44x44 now, AND THE ICONS DO NOT
 * MOVE, which is why this is a padding change and not a width/height one:
 *
 *   · Padding, because the box has to grow without touching `display`. `.hdr-tools button` is
 *     (0,1,1) and `.burger{display:none}` is (0,1,0), so a `display:grid` in the shared rule below
 *     would out-specify it and put a burger in the DESKTOP header.
 *   · gap:2px, because the design's pitch between icons is 46px (a 23px box plus a 23px gap) and
 *     44 + 2 restores exactly that. Every icon keeps its column.
 *   · margin-right, because the row must still hang on the icons' optical right edge rather than
 *     on the new boxes'. The last box now overhangs the header's padding by 10px — deliberately:
 *     it is invisible (nothing here paints a background) and it makes the burger easier to hit at
 *     the screen edge, which is where a thumb actually lands.
 *
 * Measured against the pre-change header at 375px: every icon lands within 0.5px of where it was,
 * horizontally and vertically. The 0.5px is the burger's 20px glyph being one pixel wider than the
 * other three; correcting it would cost more than it buys.
 */
.hdr-tools{margin-left:auto;display:flex;align-items:center;gap:2px;margin-right:-10px}
.hdr-tools button,.hdr-tools .hdr-tool{
  background:none;border:0;cursor:pointer;color:var(--ink);transition:color .25s;
  padding:calc((var(--tap) - var(--tap-icon)) / 2);
}
.hdr-tools button:hover,.hdr-tools .hdr-tool:hover{color:var(--green)}
.hdr-tools button:not(.burger) svg,.hdr-tools .hdr-tool svg{width:19px;height:19px}
.burger{display:none}
/* The burger's bars are 20x14, not 19x19, so it needs its own padding to reach the same 44x44.
   Two classes deep to beat `.hdr-tools button` (0,1,1) above, which would otherwise make it 45x39. */
.hdr-tools .burger{padding:15px 12px}

/*
 * "HELLO <NAME>" beside the account icon once someone is signed in — client review, 15 Sep 2026.
 * It is inside the same <a>, so it inherits the tool's colour and hover; only the box changes.
 *
 * `gap` on the link rather than a margin on the span: the icon is an inline SVG and the greeting a
 * span, and a margin between them would also apply when the span is not rendered — which is every
 * logged-out visitor, i.e. almost all of them.
 */
.hdr-account--named{display:flex;align-items:center;gap:7px}
.hdr-account-name{
  font-size:.7rem;letter-spacing:.1em;text-transform:uppercase;white-space:nowrap;
  display:flex;gap:.35em;align-items:baseline;min-width:0;
}
/*
 * ⚑ THE CAP IS ON THE NAME, NOT ON THE SENTENCE, and the difference is most of the name.
 * `max-width:11ch` used to sit on the whole "Hello …" span: `ch` is the width of a zero, so 11ch
 * is 88px here — and "HELLO " alone measures 37px of it at this size, with uppercase and
 * letter-spacing. The name was left 51px, which is about three letters. A twelve-character login
 * rendered as "HELLO BEB…".
 *
 * 120px, measured against the space that actually exists: the gap between the nav and the tool row
 * is 183px at 1025px — the narrowest width this is shown at — rising to 463px at 1440. 37 + 120
 * leaves 26px clear at the tightest point, so the header cannot be pushed out of shape by a long
 * name, and anything longer ellipsises rather than shoving the burger off the edge.
 *
 * A pixel value rather than `ch` on purpose: `ch` measures a digit, and this text is uppercase and
 * letter-spaced, so `ch` under-counts it by about a third — which is what made the first number
 * wrong in a way that looked reasonable.
 */
.hdr-account-who{
  display:inline-block;max-width:120px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}

/*
 * ⛑ HIDDEN ON THE MOBILE HEADER. At 375px the row already carries search, cart, wishlist,
 * account and the burger inside one var(--pad) gutter; a name of any length pushes the burger past
 * the edge. 1024px is the same boundary the rest of the header uses.
 *
 * `display:none`, not visibility or a clip: the greeting is decoration here. It carries
 * aria-hidden in the markup because the link's aria-label already says the same words, so removing
 * it costs a screen reader nothing — the name is still announced, from the label.
 */
@media(max-width:1024px){
  .hdr-account-name{display:none}
  .hdr-account--named{gap:0}
}

/* ============ search ============ */

/*
 * Added 9 Sep 2026 with the search feature. The header's magnifying glass was an inert <button>
 * from the design until then — the last placeholder control, and the one that made the site look
 * as though it had search when it had none.
 *
 * The panel is `hidden` in the markup and revealed by site.js. `[hidden]` is honoured by the
 * browser, so no CSS is needed to hide it — but display is set explicitly when shown, because
 * `hidden` only wins against `display:block` on a UA stylesheet, not against a rule of ours.
 */
/*
 * A compact popover under the search icon, not a full-bleed bar. The fixed layer spans the window
 * but is TRANSPARENT and `pointer-events:none`, so it only serves to hold the panel in place and a
 * click beside the panel still reaches the page (the outside-click close in site.js sees it either
 * way). The panel itself restores pointer events.
 */
.hdr-search{position:fixed;top:var(--hdr-h);left:0;right:0;z-index:70;pointer-events:none}
.hdr-search-inner{display:flex;justify-content:flex-end;padding:10px var(--pad)}
.hdr-search-panel{
  pointer-events:auto;position:relative;
  display:flex;align-items:center;gap:10px;
  width:min(430px,100%);
  background:var(--cream);border:1px solid var(--hair);border-radius:5px;
  box-shadow:0 16px 38px rgba(0,40,22,.14);
  padding:10px 12px;
}
/*
 * 18x24 before — the narrowest control on the site, and the only way out of the panel besides the
 * Escape key. A 44x44 grid box with the glyph centred; the negative margin keeps the x tucked into
 * the panel's corner instead of floating 13px in from it, and the growth comes out of the input,
 * which is flex:1 and has room (218px -> 192px at 375). The panel's height is set by the 50px
 * input, so a 44px button does not change it.
 */
.hdr-search-close{
  flex:none;background:none;border:0;padding:0;cursor:pointer;
  display:grid;place-items:center;width:var(--tap);height:var(--tap);margin-right:-10px;
  font-size:1.5rem;line-height:1;color:var(--green);
}

/* The form itself, shared by the header panel and the results page. */
.bb-search{display:flex;flex:1;min-width:0;max-width:620px}
.bb-search input[type="search"]{
  flex:1;min-width:0;
  background:transparent;border:1px solid var(--hair);border-right:0;border-radius:4px 0 0 4px;
  padding:12px 15px;font-size:.92rem;color:var(--ink);
  -webkit-appearance:none;appearance:none;
}
.bb-search input[type="search"]::placeholder{color:var(--muted);opacity:.75}
.bb-search input[type="search"]:focus{outline:0;border-color:var(--green)}
/* Safari draws its own clear button, which sits on top of the border radius. */
.bb-search input[type="search"]::-webkit-search-decoration,
.bb-search input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}
.bb-search button{
  flex:none;border:1px solid var(--green);border-radius:0 4px 4px 0;
  background:var(--btn-bg);color:var(--btn-fg);cursor:pointer;
  padding:12px 22px;font-size:.62rem;letter-spacing:.17em;text-transform:uppercase;
  transition:background .3s,color .3s;
}
.bb-search button:hover{background:transparent;color:var(--btn-hover-fg)}

/* ---- type-ahead ---- */
/*
 * The dropdown under the header field. `.bb-search` is the positioning context, so the panel does
 * not need to know the header's height.
 *
 * Hidden with the `hidden` attribute rather than a class, which is what lets the ARIA relationship
 * be static: the listbox exists on first paint for `aria-controls` to point at, and assistive tech
 * is told it is absent rather than being told nothing.
 */
.bb-search{position:relative}
.bb-suggest{
  position:absolute;top:100%;left:0;right:0;z-index:5;
  margin-top:6px;max-height:min(60vh,420px);overflow-y:auto;
  background:var(--cream);border:1px solid var(--hair);border-radius:4px;
  box-shadow:0 14px 34px rgba(0,40,22,.12);
}
/*
 * In the header the dropdown spans the whole PANEL rather than just the field, so titles have the
 * full width to sit in. That means the panel has to be the offset parent, so `.bb-search` gives up
 * `position:relative` here — on the results page it keeps it, because there the form IS the box.
 */
.hdr-search .bb-search{position:static}
.hdr-search .bb-suggest{left:0;right:0;top:100%;margin-top:11px}

.bb-suggest-item{
  display:flex;align-items:baseline;gap:12px;
  padding:11px 15px;border-bottom:1px solid var(--hair);
  color:var(--ink);
}
.bb-suggest-item:last-of-type{border-bottom:0}
/* One highlight for hover, focus and keyboard, so mouse and arrow keys look identical. */
.bb-suggest-item:hover,
.bb-suggest-item:focus,
.bb-suggest-item.is-active{background:var(--sand-hi);outline:none}
.bb-suggest-label{
  flex:none;min-width:52px;
  font-size:.56rem;letter-spacing:.16em;text-transform:uppercase;color:var(--muted);
}
.bb-suggest-title{flex:1;min-width:0;font-size:.92rem;line-height:1.4;color:var(--green)}
.bb-suggest-price{flex:none;font-size:.86rem;color:var(--ink)}

.bb-suggest-none{
  margin:0;padding:14px 15px;font-size:.88rem;color:var(--muted);
}
/*
 * ⚑ Two classes deep on purpose. `.bb-suggest-all` alone LOSES to `.bb-search button` — equal
 * class count, and that rule has a type selector — so the row rendered as a full-width dark green
 * CTA, louder than the results it sits under. Naming the parent wins outright rather than by file
 * order. Sixth specificity collision on this project.
 */
.bb-suggest .bb-suggest-all{
  display:block;width:100%;border:0;border-top:1px solid var(--hair);border-radius:0;
  background:var(--sand-hi);color:var(--green);cursor:pointer;
  padding:11px 15px;text-align:left;
  font-size:.6rem;letter-spacing:.17em;text-transform:uppercase;
}
.bb-suggest .bb-suggest-all:hover{background:var(--cream-alt);color:var(--green)}

/* ---- results ---- */
/*
 * ⚑ EVERY CLASS HERE IS `bb-` PREFIXED, and that is not house style — it is a bug fix.
 *
 * The results list was `.search-results` first, which is the obvious name. WordPress puts
 * `search-results` on the BODY element of a search results page, so `.search-results{max-width:74ch}`
 * applied to the whole document: header, content and footer were squeezed into 729px of a 1440px
 * viewport, with the right half of every search page empty. Measured `body` computed max-width
 * 729.344px — which is 74ch, the giveaway.
 *
 * WordPress body classes to avoid as component names: search, search-results, search-no-results,
 * error404, home, blog, single, page, archive, paged, logged-in, admin-bar, and every
 * `page-id-N` / `postid-N` / `category-*` / `tag-*` / `term-*` variant.
 */
.bb-search-head{margin:clamp(26px,3vw,38px) 0 clamp(24px,3vw,34px)}
.bb-search--page{max-width:520px}
.bb-search-count{margin:16px 0 0;font-size:.88rem;color:var(--muted)}
.bb-search-count strong{color:var(--ink);font-weight:500}

.bb-results{list-style:none;margin:0;padding:0;max-width:74ch}
.bb-result{padding:clamp(20px,2.4vw,26px) 0;border-top:1px solid var(--hair)}
.bb-result:last-child{border-bottom:1px solid var(--hair)}
.bb-result .eyebrow{margin:0 0 9px}
.bb-result-title{
  margin:0;font-family:'Poppins',system-ui,-apple-system,'Segoe UI',sans-serif;font-weight:500;
  font-size:clamp(1.06rem,1.4vw,1.24rem);line-height:1.3;letter-spacing:-.005em;
}
.bb-result-title a{color:var(--green)}
.bb-result-title a:hover{text-decoration:underline;text-underline-offset:3px}
.bb-result-meta{margin:8px 0 0;font-size:.95rem;color:var(--ink)}
.bb-result-excerpt{margin:8px 0 0;font-size:.9rem;line-height:1.85;color:var(--muted)}

.bb-search-empty{margin:0;font-size:clamp(.95rem,1.2vw,1.05rem);line-height:1.85;color:var(--muted)}
.bb-search-empty strong{color:var(--ink);font-weight:500}
.bb-search-empty-help{margin:12px 0 clamp(22px,2.6vw,30px);font-size:.88rem;line-height:1.85;color:var(--muted)}

@media(max-width:600px){
  /* The label is the widest part of the button, and the panel is narrow here. */
  .bb-search button{padding:12px 14px;font-size:.56rem;letter-spacing:.1em}
  .hdr-search-panel{gap:8px;padding:9px 10px}
}

/* ============ footer ============ */
.foot{background:var(--green);color:var(--cream);padding:clamp(46px,5.2vw,72px) var(--pad) 0}
.foot-top{display:grid;grid-template-columns:.8fr 1fr 1.7fr;gap:clamp(30px,4vw,64px);
  align-items:start;padding-bottom:clamp(34px,4vw,54px)}
.foot h4{font-size:.68rem;letter-spacing:.2em;text-transform:uppercase;font-weight:400;
  color:var(--cream);margin:0 0 16px}
.foot p{font-size:.71rem;line-height:1.8;color:rgba(234,226,216,.62);margin:0 0 20px;max-width:32ch}
.sub-form{display:flex;max-width:330px}
.sub-form input{flex:1;background:transparent;border:1px solid var(--hair-light);border-right:0;border-radius:6px 0 0 6px;
  padding:11px 14px;font-size:.62rem;color:var(--cream)}
.sub-form input::placeholder{color:rgba(234,226,216,.42)}
.sub-form button{border-radius:0 6px 6px 0;border:1px solid var(--hair-light);background:rgba(234,226,216,.1);
  padding:11px 18px;font-size:.62rem;letter-spacing:.17em;text-transform:uppercase;cursor:pointer;
  transition:background .3s,color .3s}
.sub-form button:hover{background:var(--cream);color:var(--green)}
/*
 * ⛑ THE CAPTCHA GOES ON ITS OWN LINE, AND WITHOUT THIS THE WHOLE PAGE SCROLLS SIDEWAYS.
 * Reported 18 Sep 2026 as "the mobile layout looks off now, there's a empty spacing on the right
 * side" -- the signature of a document wider than the viewport: the background paints the full
 * scroll width while everything sized 100% stops at the narrower initial containing block.
 *
 * ⚠ IT APPEARED THE DAY THE MAILCHIMP KEYS WENT IN, AND NOTHING ABOUT THE LAYOUT CHANGED.
 * bebold_recaptcha_widget() only prints inside this form once a mailing provider is connected --
 * see template-parts/chrome/footer.php -- so this row had carried two items through the whole
 * build and silently became three. The form is `display:flex` with the default `nowrap`, so the
 * input, the button and Google's fixed 304px widget were laid out on ONE line whose minimum width
 * is about 583px. Measured by injecting the widget into the built page: the layout viewport went
 * from 390 to 583 on the spot.
 *
 * wrap is the fix. The input and the button keep line one -- they are a joined pair, with the
 * radii to prove it -- and the widget takes line two, where the form's 330px is ample for 304.
 */
.sub-form{flex-wrap:wrap}
/* min-width:0 because a flex item will not shrink below its content's min-content width, and
   that content is a 304px widget -- without it the container stays 304 inside a 284px form on
   a 320px phone and leans on an ancestor to clip it. */
/*
 * ⚑ `order` IS LOAD-BEARING, AND ITS ABSENCE STRANDED THE SUBSCRIBE BUTTON ON A THIRD LINE.
 *
 * Reported 19 Sep 2026 as the sign-up looking "a bit off". It was not the widget's size. The
 * MARKUP order is input, captcha, button -- the captcha is printed between them, because a
 * keyboard should reach it before the thing it gates. With `flex:0 0 100%` the captcha cannot
 * share line one, so it wrapped, and the button, coming after it, wrapped again onto line THREE.
 * The input then grew to fill line one on its own, which is why the joined pill these radii are
 * drawn for had quietly come apart: field on one line, white card on the next, a small orphaned
 * button under that.
 *
 * `order:1` moves only the PAINTED position, so the pill is whole again and the widget sits
 * beneath it, while the tab order still runs email -> captcha -> Subscribe. That is the trade:
 * focus moves down a line and back up, which is the lesser of the two, because the alternative is
 * a keyboard user reaching Subscribe before the captcha they are required to complete.
 */
.sub-form .bb-recaptcha{flex:0 0 100%;min-width:0;margin:14px 0 0;overflow:hidden;order:1}
/*
 * ⚠ BELOW 344px EVEN ITS OWN LINE IS NOT WIDE ENOUGH, and transform alone does NOT fix that.
 * Measured: the form is 304px at a 344px viewport and 280px at 320px, against a widget that is
 * always 304. Scaling shrinks what is DRAWN and leaves the layout box at 304 -- the point
 * woo.css's own captcha block makes about the account panels -- so the box would still push the
 * document wide. `overflow:hidden` on the container is what actually contains it; the scale is
 * what stops that containment clipping Google's branding.
 *
 * Safe with the challenge: the image puzzle opens in its own viewport-fixed overlay appended to
 * the body, not inside this box.
 */
@media (max-width:343px){
  .sub-form .bb-recaptcha .g-recaptcha{transform:scale(.9);transform-origin:0 0}
}
/*
 * ⚑ GOOGLE'S FLOATING BADGE IS HIDDEN, AND THAT CARRIES AN OBLIGATION.
 *
 * The invisible captcha has no body in the form; instead api.js pins a badge to the bottom-right
 * of the VIEWPORT, on every page, because this form is in the footer of every page. That is worse
 * than the box it replaced — it floats over the design and follows the reader down the page.
 *
 * Google permits hiding it only if the reCAPTCHA branding appears in the user flow instead, which
 * is what `.sub-legal` under the form is for. The two must not be separated: delete that line and
 * this rule stops being allowed.
 *
 * visibility rather than display, because display:none on the badge has been known to stop the
 * challenge opening in some builds, and nothing here needs the layout box reclaimed — it is fixed
 * positioned and takes no space either way.
 */
.grecaptcha-badge{visibility:hidden}
.sub-invisible{display:none}
.sub-legal{
  font-size:.58rem;line-height:1.7;letter-spacing:.02em;
  color:rgba(234,226,216,.42);margin:12px 0 0;max-width:330px;
}
.sub-legal a{color:rgba(234,226,216,.62);text-decoration:underline;text-underline-offset:2px}
.sub-legal a:hover{color:var(--cream)}

/*
 * The sign-up's reply, added 17 Sep 2026 with the Mailchimp plugin. `.sub-note` had no rule of its
 * own at all and simply inherited the footer's paragraph styling — fine while it carried one fixed
 * sentence, and not fine now that site.js REPLACES its text for every outcome: subscribed, already
 * subscribed, captcha missing, provider unreachable. One rule dresses them all.
 */
.sub-note{margin:14px 0 0;max-width:330px;font-size:.78rem;line-height:1.7;color:rgba(234,226,216,.74)}
.sub-note a{color:var(--cream);text-decoration:underline;text-underline-offset:3px}
/*
 * ⚑ NOT var(--error). That is #8C2F2F, picked to sit on cream, and on the footer's British Racing
 * Green it is almost unreadable — a warning nobody can read is worse than no warning. This is the
 * one place on the site that needs a light error tone, and it is measured against #004225 rather
 * than eyeballed.
 */
.sub-note.is-error{color:#F0C4B8}
.foot-mark{text-align:center}
.foot-mark img{height:38px;width:auto;margin:0 auto}
.foot-mark hr{width:52px;height:1px;background:var(--gold-soft);border:0;margin:16px auto}
.foot-mark small{display:block;font-size:.66rem;letter-spacing:.19em;text-transform:uppercase;
  color:rgba(234,226,216,.6);line-height:1.9}
.foot-cols{display:grid;grid-template-columns:repeat(2,1fr);gap:clamp(16px,2vw,30px)}
.foot-cols ul{list-style:none;margin:0;padding:0}
.foot-cols li{margin-bottom:9px}
.foot-cols a{font-size:.69rem;color:rgba(234,226,216,.66);transition:color .25s}
.foot-cols a:hover{color:var(--cream)}
.foot-bot{border-top:1px solid var(--hair-light);padding:18px 0 22px;
  display:flex;flex-wrap:wrap;gap:16px;align-items:center;justify-content:space-between}
.foot-bot small,.foot-bot a{font-size:.61rem;color:rgba(234,226,216,.56)}
.foot-bot a:hover{color:var(--cream)}
.foot-bot nav{display:flex;gap:26px}
.socials{display:flex;gap:14px}
.socials a{display:grid;place-items:center;width:26px;height:26px;border-radius:50%;
  border:1px solid var(--hair-light);color:rgba(234,226,216,.7);transition:.25s}
.socials a:hover{background:var(--cream);color:var(--green);border-color:var(--cream)}

/* ============ mobile drawer ============ */
/*
 * ⛑ FULL SCREEN AGAIN -- AND THIS HAS NOW BEEN ASKED FOR BOTH WAYS. 17 Sep 2026: "can the
 * pop up menu not cover the whole screen", so it became a 330px panel over a scrim with the page
 * showing beside it. 18 Sep 2026: "can you revert the mobile menu to cover full screen when
 * clicked". Both are reasonable readings of the same design and the client has seen both on a
 * phone, which is the only way that question gets settled.
 *
 * ⚑ SO THE STRUCTURE STAYS AND ONE RULE DECIDES. The scrim and the panel are still in the
 * markup; `.drawer-panel` is either a sheet down one side or the whole viewport, and flipping back
 * is that rule plus un-hiding the scrim -- the values are kept in the comment above it for exactly
 * that. Rebuilding the markup each time this changes its mind is how the two versions drift and
 * how the close-on-scrim behaviour gets lost and rewritten.
 *
 * ⚠ THE SCRIM IS DORMANT, NOT DEAD, and that is the one thing here worth being explicit
 * about. Full screen there is no "beside" to tap, so it renders not at all rather than sitting
 * invisible under an opaque sheet swallowing taps. site.js still binds its close handler and that
 * handler cannot fire. Left in place deliberately because this element has changed twice in a day;
 * if it settles, the handler and the div go together.
 *
 * .drawer is the full-viewport LAYER (scrim + panel) and .drawer-panel is the cream sheet. Every
 * rule below is unchanged: they were all written as `.drawer something`, so they still match
 * through the wrapper.
 *
 * ⚑ VISIBILITY, NOT DISPLAY -- and the delay is load-bearing. The panel has to slide OUT before
 * the layer is taken away, so the closing transition waits the .4s the slide takes and the opening
 * one does not. Without the layer being hidden at all, a closed drawer would leave a viewport-sized
 * invisible box over the page swallowing every tap.
 */
.drawer{position:fixed;inset:0;z-index:80;visibility:hidden;transition:visibility 0s .4s}
.drawer.open{visibility:visible;transition:visibility 0s}
/* Dormant while the panel is full screen. The side-panel version of this rule and the one below is
   in git at 08b8f21, which is where it belongs -- pasting old CSS into a comment means an assertion
   that the old value is gone matches the comment saying so, which this suite has been caught by
   three times. */
.drawer-scrim{display:none}
/*
 * ⚠ --pad IS NO LONGER PINNED, AND THAT IS PART OF THE REVERT. It was held at 22px because
 * the token is clamp(20px,4.6vw,68px) -- a VIEWPORT width -- and giving a 330px sheet 41px of
 * gutter down each side spent a third of it on margins. Full screen the panel IS the viewport, so
 * that reasoning turns around and the token is right again: 20px on a phone, 41px at the 900px top
 * of the burger's range, which is what the menu had before 17 Sep.
 *
 * The border and the shadow go with it. Both existed to lift a sheet off the page behind it, and
 * there is no page behind it now.
 *
 * ⚠ `git show 08b8f21` IS THE SIDE-PANEL VERSION, and that is deliberately the only copy of it.
 */
.drawer-panel{
  position:absolute;inset:0;
  display:flex;flex-direction:column;overflow-y:auto;
  background:var(--cream);
  transform:translateX(100%);transition:transform .4s cubic-bezier(.3,.8,.3,1)}
.drawer.open .drawer-panel{transform:none}
/* Someone who asked not to be animated gets the panel without the slide, not without the panel.
   The layer's delay goes too, or it would linger .4s waiting for a slide that never runs. */
@media(prefers-reduced-motion:reduce){
  .drawer,.drawer.open,.drawer-scrim,.drawer-panel{transition:none}
}
.drawer-top{display:flex;align-items:center;justify-content:space-between;
  padding:0 var(--pad);height:62px;border-bottom:1px solid var(--hair);flex:0 0 auto}
/* 28x29 before. .drawer-top holds only the logo and this close, so the bare `button` is safe.
   The drawer-top is 62px tall, so a 44px box fits without changing the bar's height. */
.drawer-top button{background:none;border:0;font-size:1.7rem;line-height:1;cursor:pointer;color:var(--green);
  display:grid;place-items:center;width:var(--tap);height:var(--tap);padding:0;margin-right:-8px}
.drawer nav{padding:8px var(--pad) 40px}
.drawer .lvl1{list-style:none;margin:0;padding:0}
.drawer .lvl1>li{border-bottom:1px solid var(--hair)}
.drawer .lvl1>li>a,.drawer .acc{display:flex;width:100%;align-items:center;justify-content:space-between;
  gap:12px;padding:17px 2px;font-weight:400;font-family:'Poppins',system-ui,-apple-system,'Segoe UI',sans-serif;font-size:.95rem;color:var(--green);
  background:none;border:0;text-align:left;cursor:pointer}
.drawer .acc .caret{opacity:.5}
.drawer .acc[aria-expanded="true"] .caret{transform:rotate(225deg) translate(-1px,-1px)}
.drawer .lvl2{list-style:none;margin:0;padding:0;max-height:0;overflow:hidden;transition:max-height .35s ease}
/*
 * ⚑ 330px WAS A COUNTED HEIGHT, AND THE MENU IS THE CLIENT'S NOW. Five items fit; a sixth bag or
 * a section the client adds themselves would have been silently clipped, with no scrollbar to show
 * it — the submenu simply ended. site.js §1 sets --lvl2-h from the list's own scrollHeight on
 * open, so the cap follows the content whatever length it grows to.
 *
 * The literal stays as the fallback for the no-JavaScript case, where the accordion cannot open
 * anyway, and as the value the transition animates from.
 */
.drawer .acc[aria-expanded="true"]+.lvl2{max-height:var(--lvl2-h,330px)}
/* 40.7px tall on its own padding — over WCAG's 24 floor, under the 44 the rest of this header now
   meets. min-height rather than more padding, so the indent and the row's rhythm are untouched and
   it survives a font-size change. The lvl2 max-height above has room: 5 rows at 44 is 229 of 330. */
.drawer .lvl2 a{display:flex;align-items:center;min-height:var(--tap);
  padding:11px 2px 11px 16px;font-size:.71rem;color:var(--muted)}
.drawer .lvl2 li:last-child a{padding-bottom:20px}

/* ============ reveal ============ */
.rv{opacity:0;transform:translateY(20px);transition:opacity .9s ease,transform .9s cubic-bezier(.2,.7,.3,1)}
.rv.in{opacity:1;transform:none}



/* ============ inner-page shell (added with the Care Guide port) ============ */
/*
 * The hero, the shop band and the centred-block helper are shared: the hero and .ctr by all six
 * inner pages, the shop band by the homepage too. Per-page hero tuning (height, crop, fade) stays
 * in the page file — every page tunes those differently.
 */
.hero{position:relative;margin-top:calc(-1 * var(--hdr-h));min-height:min(86vh,720px);display:flex;align-items:center;isolation:isolate}
/*
 * ⚑ THE HORIZONTAL NUMBER IS A CROP DECISION, NOT A NUDGE. The photograph is 1900x814 (2.334:1)
 * and the hero frame is 2:1 at 1440x720, so about 14% of the width is always thrown away — and
 * object-position picks WHICH 14%. The photograph is composed with the sunlit haze on the left
 * (nothing in it) and the four bags from 49% to 98%, so every point you move left buys clean
 * ground for the headline and costs a bag on the right.
 *
 * 45% is where that trade stops paying: the first three bags survive it at every common desktop
 * width down to 1280, and below 45% the third bag starts being cut at 1280. Above it the copy
 * sits over the hillside. 62% — the old value — put the standfirst on the bright flare.
 *
 * Note there is nothing to decide above ~1680px: the frame is wider than 2.334:1 there, the whole
 * photograph fits, and this number stops having any effect at all.
 */
.hero-img{position:absolute;inset:0;z-index:-2;width:100%;height:100%;object-fit:cover;object-position:45% 68%}
.hero-fade{position:absolute;inset:0;z-index:-1;background:linear-gradient(100deg,rgba(234,226,216,.55) 0%,rgba(234,226,216,.32) 30%,rgba(234,226,216,.06) 48%,rgba(234,226,216,0) 60%)}
.hero-inner{padding:0 var(--pad);max-width:820px}
.hero h1{font-family:'Poppins',system-ui,-apple-system,'Segoe UI',sans-serif;font-weight:400;color:var(--green);font-size:clamp(1.16rem,4.65vw,2.99rem);line-height:1.1;letter-spacing:-.012em;margin:0 0 26px}
.hero h1 span{display:block;white-space:nowrap}
.hero-inner .rule{margin-bottom:22px}
.hero p{font-size:clamp(.88rem,1.1vw,1rem);color:#3D3A32;line-height:1.85;margin:0 0 38px;max-width:53ch}
.shopband-inner{position:relative;max-width:1560px;margin:0 auto;border-radius:6px;overflow:hidden}
.shopband-media{margin:0;line-height:0}
.shopband-media img{display:block;width:100%;height:auto}
.shopband-copy{position:absolute;top:50%;transform:translateY(-50%);right:clamp(30px,5.2vw,92px);width:min(40%,410px);z-index:2}
.shopband-copy .dsp{margin:0;text-wrap:balance}
.shopband-copy .rule{margin:18px 0 0}
/*
 * ⛑ --ink, NOT --muted, AND THE PHOTOGRAPH IS WHY. The band's plate changed on 18 Sep 2026 to
 * four bags against a sunlit plaster wall, and the copy sits on that wall rather than on the pale
 * travertine it used to. Measured on the rendered page, sampling the wall behind the copy and
 * taking the 5th percentile (#C4A384) so a dark patch is not averaged away:
 *
 *     --muted #5F5B4E   2.88:1   FAILS AA for body text (4.5 needed)
 *     --ink   #26241F   6.58:1   passes
 *
 * The heading was never at risk: --green on the same wall is 4.94:1 against the 3:1 large-text
 * threshold. Only the paragraph moved, and it moved to a colour the site already uses for body
 * copy rather than to a new one.
 *
 * ⚠ Re-measure if the plate changes again. A warmer or busier wall behind the right-hand third
 * is the thing that breaks this, and it breaks silently — the text stays exactly where it was.
 */
.shopband-copy p{font-size:clamp(.88rem,1.1vw,1rem);line-height:1.8;color:var(--ink);margin:20px 0 28px;max-width:34ch}
.submenu a[aria-current]{color:var(--green)}
.ctr{text-align:center;max-width:min(96%,1060px);margin:0 auto}
.ctr .rule{margin:clamp(20px,2.4vw,30px) auto 0}

/*
 * ⚑ Everything below the responsive banner is media queries. Base rules MUST go above it —
 * appended at the end they out-order those queries at equal specificity and silently kill the
 * mobile layout. That is exactly how the shop band lost its stacking on the first Care Guide port.
 */

/* ============ accessibility helpers (new — not in the design files) ============ */
.screen-reader-text{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip-path:inset(50%);white-space:nowrap;border:0;
}
.skip-link:focus{
  position:fixed;top:10px;left:10px;z-index:999;width:auto;height:auto;clip-path:none;
  margin:0;padding:12px 18px;background:var(--green);color:var(--cream);
  font-size:.7rem;letter-spacing:.18em;text-transform:uppercase;border-radius:6px;
}

/* ============ shared section patterns (added with the Our Material port) ============ */
/*
 * Lifted out of our-material.html because a second, third or fourth page needs each of these:
 *   .split*        the image-beside-copy section — Our Material, What Sets Us Apart,
 *                  Founder's Story, A Commitment to Sustainability
 *   .statement*    the centred pull-quote band, in three variants
 *   .sect-head*    centred eyebrow + heading + rule above a section
 *   .src-note      the small italic source credit under a figure row
 *   .mat-stats /   the icon + figure + label row — Our Material and the homepage
 *   .mstat*
 * Per-page tuning of these stays in the page file.
 */
.split{display:grid;grid-template-columns:1fr 1fr;align-items:stretch}
.split figure{margin:0;min-height:clamp(300px,40vw,560px);overflow:hidden}
.split figure svg{width:100%;height:100%}
.split-copy{display:flex;flex-direction:column;justify-content:center;padding:clamp(40px,5.4vw,86px) clamp(24px,4.6vw,80px)}
.split-copy .body-sm{margin-top:26px;max-width:42ch}
.mat-stats{display:grid;grid-template-columns:repeat(5,1fr);padding:clamp(26px,3vw,44px) var(--pad) clamp(34px,4vw,58px)}
.mstat{display:flex;align-items:center;gap:clamp(14px,1.7vw,22px);padding:4px clamp(12px,1.6vw,26px)}
.mstat+.mstat{border-left:1px solid var(--hair)}
.mstat .ico{width:clamp(56px,5.8vw,78px);height:clamp(56px,5.8vw,78px);flex:0 0 auto;object-fit:contain}
.mstat-num{display:block;font-family:'Poppins',system-ui,sans-serif;font-weight:600;font-size:clamp(1.75rem,2.7vw,2.5rem);color:var(--green);line-height:1;letter-spacing:.01em}
.mstat-pre{display:block;font-family:'Poppins',sans-serif;font-size:.6rem;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--green);line-height:1;margin-bottom:4px}
.mstat-lbl{display:block;font-size:.68rem;letter-spacing:.15em;text-transform:uppercase;color:var(--green);line-height:1.5;margin-top:5px}
.mstat-lbl--solo{margin-top:0}
.statement{padding:clamp(30px,3.8vw,56px) var(--pad);text-align:center}
.statement .wrap{max-width:940px}
.statement .dsp{font-size:clamp(1.33rem,2.41vw,2.24rem);line-height:1.3;font-weight:500}
.statement .eyebrow{margin:0 0 18px}
.statement .rule{margin:28px auto 0}
.statement--hi{background:var(--sand-hi)}
.statement--bridge .dsp{font-size:clamp(.91rem,1.45vw,1.29rem);line-height:1.55;color:var(--green)}
.split-copy .btn{align-self:flex-start;margin-top:clamp(24px,3vw,34px)}
.split-copy .eyebrow{margin:0 0 clamp(10px,1.2vw,14px)}
.split figure img{width:100%;height:100%;object-fit:cover;display:block}
.sect-head{text-align:center;max-width:760px;margin:0 auto}
.sect-head .eyebrow{margin:0 0 14px}
.sect-head .rule{margin:22px auto 0}
.src-note{font-size:.6rem;font-style:italic;color:var(--muted);opacity:.82;margin:clamp(14px,1.6vw,20px) 0 0;text-align:center}
/* ============ story sections (added with the Founder's Story port) ============ */
/*
 * The illustrated story split and its photo variant, shared by Founder's Story and What Sets Us
 * Apart. Every rule here was verified byte-identical in BOTH design files before being promoted —
 * the check that .statement needed and did not get.
 *
 * Two rules deliberately stayed behind in the page files because they differ per page:
 *   .uspx                             Founder's Story adds its own padding-top
 *   .wrap.memrow .story__media img    a different object-position on each page
 * The base of .uspx is here; only its padding-top is page-local. Note that
 * tools/check-shell-leaks.py could NOT have caught that one — a longhand with no shorthand beside
 * it looks like ordinary CSS, which is why the two design files get compared directly.
 */
.story{display:grid;grid-template-columns:1fr 1fr;align-items:center;min-height:0}
.story__media{align-self:stretch;display:flex;align-items:center;justify-content:center;padding:clamp(8px,1.2vw,22px)}
.story__media img{width:100%;height:auto;max-height:clamp(270px,29vw,390px);object-fit:contain;display:block}
.story__copy{padding:clamp(18px,2.4vw,38px) clamp(24px,4.6vw,78px)}
.story__copy .inner{max-width:60ch}
.story__copy .dsp{margin-top:4px}
.story__copy .rule{margin-top:20px}
.story__copy .body-sm{margin-top:24px}
.story__copy .body-sm+.body-sm{margin-top:16px}
@media(min-width:901px){
  .story.rev .story__media{order:1}
  .story.rev .story__copy{order:0}
}
@media(max-width:900px){
  .story{grid-template-columns:1fr;min-height:0}
  .story__media{order:-1;padding:clamp(20px,6vw,38px) var(--pad) 0}
  .story__copy{padding:clamp(22px,6vw,38px) var(--pad) clamp(34px,8vw,50px)}
}
.subhead{font-family:'Poppins',system-ui,-apple-system,'Segoe UI',sans-serif;font-style:italic;font-weight:400;color:var(--muted);font-size:clamp(.85rem,1.12vw,1.06rem);line-height:1.4;margin:9px 0 0}
.uspx .dsp{font-size:clamp(1.66rem,3.07vw,2.74rem);margin:0}
.uspx .rule{margin:22px auto 0}
.sect:has(> .wrap.story){padding-top:clamp(14px,1.8vw,26px);padding-bottom:clamp(14px,1.8vw,26px)}
.wrap.story{max-width:1160px;gap:clamp(26px,3.4vw,54px);align-items:center}
.wrap.story .story__copy{padding:clamp(4px,.8vw,12px) 0}
.story-h{font-size:clamp(1.24rem,1.91vw,1.74rem);line-height:1.16;margin:0;color:var(--ink)}
.wrap.memrow .story__copy .inner{max-width:none}
.story__copy .subhead{margin-top:9px}
.story__copy .story-h+.rule{margin-top:18px}
.uspx{text-align:center;padding-bottom:clamp(6px,1vw,14px)}
.sg-tight{padding-top:clamp(12px,1.6vw,24px);padding-bottom:clamp(12px,1.6vw,24px)}
.wrap.alt-culture{max-width:1300px}
.wrap.alt-culture .story__copy .inner{max-width:none}
.wrap.alt-culture .story__media{padding:0;align-self:center;aspect-ratio:3/2;overflow:hidden;border-radius:5px}
.wrap.alt-culture .story__media img{width:100%;height:100%;max-height:none;min-height:0;object-fit:cover;object-position:center}
.story--photo .story__media{padding:0;align-self:center;aspect-ratio:3/2;overflow:hidden;border-radius:5px}
.story--photo .story__media img{width:100%;height:100%;max-height:none;min-height:0;object-fit:cover;display:block}
@media(max-width:900px){
  .wrap.story{gap:clamp(18px,5vw,28px)}
}

/* ============ why band (added with the What Sets Us Apart port) ============ */
/*
 * The three-principle band, shared with the homepage. Verified against homepage.html with
 * tools/compare-design-rules.py: 17 of the 18 shared rules were byte-identical, the exception
 * being .why-item h3, where this page adds a max-width. That one stayed in the page file.
 *
 * `.wrap.in .why-item` is the band's staggered fade-in, and .in is added by site.js at runtime.
 * The extractor used to drop it for that reason, leaving the three principles at opacity:0 on an
 * otherwise pixel-perfect page; RUNTIME_CLASSES in tools/extract-page-css.py now prevents that.
 *
 * The three .ico-* engravings are CSS MASK images, base64 in the design. They point at the
 * extracted files in assets/img/icons/ — a CSS mask cannot come from the media library, because
 * its URL differs between local, staging and production.
 */
.why{background:#EAE2D8;padding-top:clamp(20px,2.2vw,32px);padding-bottom:clamp(20px,2.2vw,32px)}
.why-head{text-align:center;margin-bottom:clamp(30px,3.6vw,50px)}
.why-grid{display:grid;grid-template-columns:repeat(3,1fr)}
a.why-item{display:block;text-decoration:none;color:inherit;cursor:pointer}
a.why-item:focus-visible{outline:2px solid var(--gold);outline-offset:6px}
.why-item{text-align:center;padding:0 clamp(18px,3.4vw,54px);opacity:0;transition:opacity .75s ease}
.why-item+.why-item{border-left:1px solid var(--hair)}
.why-item .ico{width:92px;height:78px;margin:0 auto 18px;background-color:var(--green);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-position:center;mask-position:center;-webkit-mask-size:contain;mask-size:contain;transition:transform .55s cubic-bezier(.2,.7,.3,1),background-color .45s ease}
.ico-olive{-webkit-mask-image:url(../img/icons/why-olive.png);mask-image:url(../img/icons/why-olive.png)}
.ico-puff{-webkit-mask-image:url(../img/icons/why-puff.png);mask-image:url(../img/icons/why-puff.png)}
.ico-craft{-webkit-mask-image:url(../img/icons/why-craft.png);mask-image:url(../img/icons/why-craft.png)}
.why-item p{font-size:clamp(.88rem,1.1vw,1rem);line-height:1.85;color:var(--muted);margin:0 auto;max-width:27ch}
.wrap.in .why-item{opacity:1}
.why-grid .why-item:nth-child(2){transition-delay:.14s}
.why-grid .why-item:nth-child(3){transition-delay:.28s}
.why-item h3::after{content:"";position:absolute;left:50%;bottom:-7px;width:0;height:1px;background:var(--gold);transform:translateX(-50%);transition:width .45s cubic-bezier(.3,.8,.3,1)}
.why-item:hover .ico{transform:translateY(-7px);background-color:var(--gold)}
.why-item:hover h3::after{width:30px}
.link-row{display:flex;flex-wrap:wrap;gap:clamp(20px,3vw,48px);justify-content:center;margin-top:clamp(26px,3vw,40px)}

/*
 * ⚑ The responsive block MUST stay last in this file.
 *
 * Its rules are single-class selectors that override single-class base rules — .split becoming one
 * column at 900px, for instance. Same specificity, so source order decides. Appending a new
 * component block after it silently kills those overrides: adding the shared .split base with the
 * Our Material port did exactly that, and Our Material stopped stacking on tablet while the
 * desktop view stayed pixel-perfect, which is a horrible way to find out.
 *
 * New sections go ABOVE this comment.
 */

/* ============ cart toasts (added with the WooCommerce port) ============
 *
 * In shell.css and not woo.css for the same reason as the bag count: a cart notice can appear on
 * ANY page — adding from the homepage collection band raises one — and woo.css only loads on the
 * shop screens.
 *
 * Only success notices become toasts (see site.js section 4). Errors and info notices keep their
 * inline treatment in woo.css.
 */
.toasts{
  /*
   * Clear of the header in BOTH its states. At the top of the page the announcement bar (25px) is
   * still on screen and pushes the header down to y=99; once scrolled it sticks at y=hdr-h. The
   * larger offset is the one that clears the first case, and it simply leaves a wider gap in the
   * second.
   */
  position:fixed;z-index:70;top:calc(var(--hdr-h) + 36px);right:var(--pad);
  display:flex;flex-direction:column;gap:10px;
  width:min(360px,calc(100vw - 2 * var(--pad)));
  pointer-events:none;   /* the strip never blocks the page; each toast re-enables itself */
}
.toast{
  pointer-events:auto;
  display:flex;align-items:flex-start;gap:12px;
  background:var(--sand-hi);color:var(--ink);
  border:1px solid var(--hair);border-top:2px solid var(--gold);border-radius:3px;
  box-shadow:0 14px 34px rgba(0,40,22,.14);
  padding:15px 16px;font-size:.86rem;line-height:1.6;
  /*
   * There is deliberately NO entrance animation. Only the exit is animated.
   *
   * Every way of fading a toast IN starts it at opacity 0 and relies on something — rAF, a class
   * flip, an animation's fill mode — to move it to 1. Each of those can fail to run, and when one
   * does the toast is silently invisible for its whole life: the notice never reaches the visitor
   * and nothing looks broken. Appearing instantly and fading out is worth far more than a 280ms
   * flourish that can swallow the message.
   */
  transition:opacity .28s ease,transform .28s ease;
}
.toast.is-out{opacity:0;transform:translateY(-8px)}
.toast-body{flex:1 1 auto;min-width:0}
/*
 * WooCommerce's "View cart" arrives as <a class="button wc-forward">. It is not inside
 * .woocommerce, so woo.css's button skin cannot reach it — which is what we want here: in a toast
 * it should read as a link, not a second call to action.
 */
.toast-body a{
  display:inline-block;margin-top:8px;color:var(--green);font-weight:500;
  font-size:.72rem;letter-spacing:.14em;text-transform:uppercase;
  border-bottom:1px solid var(--gold);padding-bottom:3px;
}
.toast-close{
  flex:0 0 auto;background:none;border:0;padding:2px;margin:-2px -2px 0 0;
  color:var(--muted);cursor:pointer;transition:color .25s;
}
.toast-close:hover{color:var(--green)}
.toast-close svg{width:15px;height:15px}

/* The wrapper is left behind empty once its message has been lifted into a toast. */
.woocommerce-notices-wrapper:empty{display:none}

@media(prefers-reduced-motion:reduce){
  .toast{animation:none;transition:none}
}

/* ============ header bag count (added with the WooCommerce port) ============
 *
 * This lives in shell.css, NOT woo.css, because the header renders on every page while woo.css
 * only loads on shop screens. Put here it stays invisible at zero everywhere; put in woo.css a
 * bare "0" appears in the header of all six design pages.
 */
.hdr-cart,.hdr-wish{position:relative}
/*
 * The offsets are derived, not literal. The badge hangs 7px above and 10px to the right of the
 * BAG ICON's top-right corner — it read as the bag's own badge at the design's 23px box, and it
 * has to keep doing so now the box is 44px and the icon sits 12.5px inside it. Hard-coded -5/-8
 * would have flung it to the corner of the new box, clear of the bag it belongs to.
 *
 * The wishlist heart takes the same rule rather than its own copy (client review, 15 Sep 2026:
 * the count should read "similar to the shopping cart"). One selector list, so the two badges
 * cannot drift apart — the header's geometry is verified against the design and a second set of
 * literals here is exactly how that verification goes stale.
 */
.hdr-cart-count,.hdr-wish-count{
  position:absolute;
  top:calc((var(--tap) - var(--tap-icon)) / 2 - 7px);
  right:calc((var(--tap) - var(--tap-icon)) / 2 - 10px);
  min-width:15px;height:15px;padding:0 4px;
  display:grid;place-items:center;border-radius:8px;
  background:var(--green);color:var(--cream);
  font-size:9px;font-weight:600;line-height:1;letter-spacing:0;
}
.hdr-cart-count.is-empty,.hdr-wish-count.is-empty{display:none}

/* ============ product card (added with the WooCommerce port) ============
 *
 * Verbatim from design/homepage.html's "framed product tile" block. It lives here rather than in
 * a page file because two places render it: the shop loop (WooCommerce) and the homepage's
 * collection band. The design's carousel chrome (.coll-*) stays with the homepage — only the tile
 * itself is shared.
 *
 * The front/back cross-fade maps onto WooCommerce cleanly: .media-front is the featured image,
 * .media-back is the first gallery image.
 */
.card{background:var(--sand-hi);border:1px solid var(--hair);border-radius:3px;overflow:hidden;
  transition:box-shadow .35s ease,border-color .35s ease}
.card:hover{box-shadow:0 14px 34px rgba(0,40,22,.10)}
/*
 * ⚑ SQUARE, not the 4:3 this started as — because a 4:3 frame cannot contain the product.
 *
 * The client's photography is 3:4 portrait throughout, and a 4:3 window shows only 56% of a 3:4
 * image's height. On a handbag that is not enough: the bag and its handle together fill the frame,
 * so the card cropped every bag's HANDLE off at the top while leaving the body intact — which is
 * subtle enough that it survived a first review.
 *
 * Repositioning the crop cannot fix it. `object-position` was measured, not guessed: the product is
 * already vertically centred in every frame, and shifting the window to catch the handle only moves
 * the cut to the base. Even the best per-product offset left the bag touching both edges with no
 * breathing room, and it would need re-deriving for every future photograph.
 *
 * 1:1 shows 75% of the height, which contains all four bags with margin at the DEFAULT centre crop
 * — no per-product offsets, and it keeps working for the next shoot. Square product cards are also
 * the ordinary e-commerce shape for bags.
 *
 * This is a proportion change on the shop grid, "More from the collection" AND the homepage
 * collection band, since all three share this component. That is deliberate: the alternative was
 * showing the client's bags with their handles cut off.
 */
.card-media{position:relative;margin:0;overflow:hidden;background:var(--cream-alt);aspect-ratio:1}
.card-media img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block;
  transition:opacity .55s ease,transform 1.1s cubic-bezier(.2,.7,.3,1);backface-visibility:hidden}
.card-media .media-back{opacity:0}
.card:hover .media-front{opacity:0}
.card:hover .media-back{opacity:1}
/*
 * ⚑ 1.03, reduced from 1.05. The hover zoom crops the image it is applied to — 5% takes 2.4% off
 * EVERY edge — and that turned out to be what was cutting the bag on the hover frame, not the
 * square crop: the client's KTP model shots place the wide tote within ~2% of the frame edge, so
 * the zoom clipped it while the resting image was fine. 3% halves the loss and still reads as a
 * lift.
 *
 * Worth remembering when choosing card imagery: anything within ~1.5% of a frame edge will be
 * trimmed on hover, and it only shows on hover, so a static screenshot will not reveal it.
 */
.card:hover .card-media img{transform:scale(1.03)}
/* ---- out of stock ---- */
/*
 * ⚑ IN shell.css, NOT woo.css, and that is the whole point of this note. woo.css is enqueued only
 * on shop screens, and the homepage's collection band is not one — it renders product cards on an
 * ordinary ACF page. Put in woo.css, the badge and the quieted button appeared on /shop/ and on
 * "More from the collection" and were SILENTLY ABSENT from the homepage, with the markup present
 * and unstyled. The cart drawer lives here for exactly the same reason.
 *
 * Before this, a sold-out card said nothing at all: WooCommerce swapped the label to "Read more"
 * and left it in the same filled green as every "Add to cart" beside it.
 *
 * Three classes deep (`.card .add-cart.add-cart--soldout`) so it beats `.card .add-cart` outright
 * rather than by file order.
 */
.card .add-cart.add-cart--soldout{
  background:transparent;color:var(--green);border:1px solid rgba(0,66,37,.3);
}
.card .add-cart.add-cart--soldout:hover{
  background:var(--green);color:var(--btn-fg);border-color:var(--green);
}

/*
 * The badge. `.card-media` is already `position:relative`, so this needs no positioning context of
 * its own. Cream on the photograph rather than a loud red: it states a fact, it is not a warning,
 * and it sits over the client's photography.
 */
.card-flag{
  position:absolute;top:12px;left:12px;z-index:2;
  padding:5px 11px 4px;border-radius:100px;
  background:var(--cream);border:1px solid var(--hair);color:var(--ink);
  font-family:'Poppins',system-ui,sans-serif;font-weight:400;
  font-size:.55rem;letter-spacing:.16em;text-transform:uppercase;line-height:1.6;
  white-space:nowrap;
}
/* The media zooms on hover; without this the badge drifts with it. */
.card:hover .card-flag{transform:none}

/* card body: product details on the left, permanent Add-to-cart button on the right */
.card-info{display:flex;align-items:center;justify-content:space-between;gap:18px;padding:18px 20px 20px}
.card-text{min-width:0}
.card h3{font-family:'Poppins',system-ui,-apple-system,'Segoe UI',sans-serif;font-weight:500;font-size:1.33rem;color:var(--green);
  margin:0 0 9px}
.card .sub{font-size:.78rem;letter-spacing:.17em;text-transform:uppercase;color:var(--muted);margin:0}
.card .price{font-size:1.12rem;color:var(--ink);margin:11px 0 0;letter-spacing:.02em}
.card .add-cart{flex:0 0 auto;cursor:pointer;font-family:'Poppins',sans-serif;white-space:nowrap;
  padding:14px 22px;font-size:.64rem;font-weight:700;gap:0}


/* ============ cart drawer ============ */

/*
 * NOT from the design — added 7 Sep 2026 from the client's reference: the cart slides in from the
 * right over a dimmed page whenever something is added.
 *
 * ⚑ IN shell.css ON PURPOSE. woo.css only loads on shop screens, and the homepage collection band
 * has Add to cart buttons — so a drawer styled in woo.css would slide in unstyled on the homepage.
 * Same reason the header bag badge and the toasts live here. That also means the two buttons inside
 * it need their own button treatment here; they cannot lean on woo.css's.
 *
 * The markup inside .widget_shopping_cart_content is WooCommerce's mini-cart template, replaced
 * wholesale by its own fragment on every cart change — so everything below is written against
 * WooCommerce's class names and must not assume any element survives a refresh.
 */
.cart-drawer{position:fixed;inset:0;z-index:120}
.cart-drawer[hidden]{display:none}

.cart-drawer-scrim{
  position:absolute;inset:0;background:rgba(0,26,14,.5);
  opacity:0;transition:opacity .32s ease;
}
.cart-drawer.is-open .cart-drawer-scrim{opacity:1}

.cart-drawer-panel{
  position:absolute;top:0;right:0;bottom:0;
  width:min(420px,100%);display:flex;flex-direction:column;
  background:var(--cream);border-left:1px solid var(--hair);
  box-shadow:-18px 0 46px rgba(0,40,22,.16);
  transform:translateX(100%);transition:transform .32s cubic-bezier(.2,.7,.3,1);
}
.cart-drawer.is-open .cart-drawer-panel{transform:translateX(0)}
/* Someone who asked not to be animated gets the panel without the slide, not without the panel. */
@media(prefers-reduced-motion:reduce){
  .cart-drawer-scrim,.cart-drawer-panel{transition:none}
}

/* ---- head ---- */
.cart-drawer-head{
  display:flex;align-items:center;justify-content:space-between;gap:16px;flex:0 0 auto;
  padding:20px clamp(18px,2.2vw,26px);border-bottom:1px solid var(--hair);
}
.cart-drawer-title{
  font-family:'Poppins',system-ui,sans-serif;font-weight:500;color:var(--green);
  font-size:1.02rem;line-height:1.2;margin:0;
}
.cart-drawer-close{
  display:inline-flex;align-items:center;gap:8px;background:transparent;border:0;padding:4px;
  cursor:pointer;font-size:.66rem;letter-spacing:.16em;text-transform:uppercase;color:var(--muted);
  transition:color .3s;
}
.cart-drawer-close:hover{color:var(--green)}
/* An × drawn from two bars — no glyph to go missing in a fallback font, same as the panel marks. */
.cart-drawer-close-icon{position:relative;width:11px;height:11px;flex:0 0 auto}
.cart-drawer-close-icon::before,
.cart-drawer-close-icon::after{
  content:"";position:absolute;left:0;top:5px;width:11px;height:1px;background:currentColor;
}
.cart-drawer-close-icon::before{transform:rotate(45deg)}
.cart-drawer-close-icon::after{transform:rotate(-45deg)}

/* ---- body: the scrolling list ---- */
/*
 * The body scrolls and the total/buttons stay put, which is what makes the reference's footer sit
 * at the bottom of the panel however many lines the cart has. The mini cart's own markup is one
 * flow — <ul>, then the total <p>, then the buttons <p> — so the pinning is done by making the
 * REFRESHED div a flex column and pushing the total down with margin-top:auto.
 */
.cart-drawer-body{flex:1 1 auto;min-height:0;display:flex;flex-direction:column}
.cart-drawer-body>.widget_shopping_cart_content{
  flex:1 1 auto;min-height:0;display:flex;flex-direction:column;
}
.cart-drawer-body ul.woocommerce-mini-cart{
  flex:1 1 auto;min-height:0;overflow-y:auto;
  list-style:none;margin:0;padding:clamp(14px,1.8vw,20px) clamp(18px,2.2vw,26px);
}
/*
 * THE ROW, and why the thumbnail is positioned rather than placed in a grid.
 *
 * WooCommerce wraps the thumbnail AND the product name in a single <a>. So the image cannot be a
 * grid item of the row and cannot span its rows — which put the price, a sibling of that <a>, on a
 * row BELOW the image and left ~75px of nothing between the name and the price. The reference has
 * them one under the other beside the thumbnail.
 *
 * Taking the image out of flow solves it with no markup surgery. `position:absolute` on the <img>
 * resolves against the LI, because the <a> is not positioned — so the thumbnail pins to the left
 * of the row while the name and the price flow normally in the padded column beside it. The other
 * routes were worse: `display:contents` on the <a> is an accessibility gamble on a client site,
 * and moving the price inside the name with WooCommerce's filters changes the link's accessible
 * name and needs a flag to keep it off the cart page, which uses the same filter.
 */
.cart-drawer-body li.woocommerce-mini-cart-item{
  position:relative;min-height:60px;
  padding:0 0 16px 74px;margin:0 0 16px;border-bottom:1px solid var(--hair);
}
.cart-drawer-body li.woocommerce-mini-cart-item:last-child{border-bottom:0;margin-bottom:0;padding-bottom:0}
.cart-drawer-body li.woocommerce-mini-cart-item img{
  position:absolute;left:0;top:0;
  width:60px;height:60px;object-fit:cover;border-radius:3px;background:var(--cream-alt);
}
.cart-drawer-body li.woocommerce-mini-cart-item>a:not(.remove){
  display:block;padding-right:30px;
  font-size:.85rem;line-height:1.5;color:var(--green);
}
/*
 * display:block is load-bearing here, and the reason is a real collision. woo.css styles the
 * quantity STEPPER with `.woocommerce .quantity{display:inline-flex}`, and the mini cart's
 * quantity is also a `<span class="quantity">` — so it became a flex container, and a flex
 * container discards the whitespace between its items. WooCommerce emits `2 &times; <span>S$280`,
 * so the line read "2 ×S$280" with the space gone. Worse, woo.css does not load on the homepage,
 * so it was right there and wrong on every shop page.
 */
.cart-drawer-body li.woocommerce-mini-cart-item .quantity{
  display:block;margin:3px 0 0;font-size:.78rem;color:var(--muted);
}
/* Variation data, if a bag ever gains colourways. Empty for a simple product. */
.cart-drawer-body li.woocommerce-mini-cart-item dl.variation{
  margin:3px 0 0;font-size:.74rem;color:var(--muted);
}
.cart-drawer-body li.woocommerce-mini-cart-item a.remove{
  position:absolute;right:0;top:-2px;
  width:1.2em;height:1.2em;line-height:1.1;text-align:center;
  font-size:18px;color:var(--muted);text-decoration:none;transition:color .3s;
}
.cart-drawer-body li.woocommerce-mini-cart-item a.remove:hover{color:var(--green)}

.cart-drawer-body .woocommerce-mini-cart__empty-message{
  margin:0;padding:clamp(24px,3vw,34px) clamp(18px,2.2vw,26px);
  font-size:.88rem;color:var(--muted);
}

/* ---- foot: subtotal and the two buttons ---- */
.cart-drawer-body .woocommerce-mini-cart__total{
  flex:0 0 auto;margin:auto 0 0;
  display:flex;align-items:baseline;justify-content:space-between;gap:16px;
  padding:16px clamp(18px,2.2vw,26px);border-top:1px solid var(--hair);
  font-size:.78rem;letter-spacing:.14em;text-transform:uppercase;color:var(--muted);
}
.cart-drawer-body .woocommerce-mini-cart__total strong{font-weight:inherit}
.cart-drawer-body .woocommerce-mini-cart__total .amount{
  font-size:1.05rem;letter-spacing:.02em;text-transform:none;color:var(--ink);
}
.cart-drawer-body .woocommerce-mini-cart__buttons{
  flex:0 0 auto;margin:0;display:grid;gap:10px;
  padding:0 clamp(18px,2.2vw,26px) clamp(18px,2.2vw,26px);
}
/*
 * The buttons come from WooCommerce's widget hooks as bare `.button` links. woo.css's button block
 * is not here on the homepage, so they get the design's treatment from this file. View cart reads
 * as the outline and Checkout as the fill — one of the two has to be the decision.
 */
.cart-drawer-body .woocommerce-mini-cart__buttons a.button{
  display:inline-flex;align-items:center;justify-content:center;
  padding:15px 20px;border:1px solid var(--btn-bg);border-radius:6px;
  font-family:'Poppins',system-ui,sans-serif;font-weight:700;font-size:.66rem;
  letter-spacing:.2em;text-transform:uppercase;line-height:1;text-decoration:none;
  background:transparent;color:var(--green);
  transition:background .35s,color .35s;
}
.cart-drawer-body .woocommerce-mini-cart__buttons a.button:hover{background:var(--green);color:var(--btn-fg)}
.cart-drawer-body .woocommerce-mini-cart__buttons a.button.checkout{background:var(--btn-bg);color:var(--btn-fg)}
.cart-drawer-body .woocommerce-mini-cart__buttons a.button.checkout:hover{background:transparent;color:var(--btn-hover-fg)}

/* The page behind must not scroll under the panel. */
body.cart-open{overflow:hidden}

/* ============ responsive ============ */
/*
 * ⚑ The homepage's own responsive rules are NOT here — they are at the foot of
 * assets/css/pages/home.css. This block was lifted wholesale from homepage.html during the
 * scaffold, but home.css loads AFTER shell.css, so at equal specificity every base rule in
 * home.css out-orders a media query in this file. `.mat-bg{position:absolute}` in home.css beat
 * `.mat-bg{position:static}` here and the Oleatex band stopped stacking below 1024px, while the
 * desktop view stayed pixel-perfect. Anything that only the homepage uses belongs in home.css;
 * what is left here is shared with the inner pages (the chrome, .hero, .split, .shopband-copy,
 * .why-*, .mat-stats/.mstat and the footer), none of which any page file re-declares.
 */
@media(max-width:1180px){
  .mainnav>li>a{font-size:.74rem;letter-spacing:.08em;padding:0 12px}
  .hdr{gap:26px}
}
@media(max-width:1080px){
  .why-item{padding:0 clamp(14px,2.6vw,30px)}
  .why-item .ico{width:88px;height:76px;margin-bottom:22px}
  .foot-top{grid-template-columns:1fr 1fr}
  .foot-cols{grid-column:1/-1}
}
/*
 * ⚑ The stat band is FIVE cells, and below 1024 it used to become five full-width ROWS — a
 * 516px ribbon on a 375px phone with two thirds of every line empty, because .mstat keeps the
 * icon BESIDE the label and a short uppercase label cannot fill a phone's width. Five of those
 * read as five unrelated list items rather than one band of figures.
 *
 * So below 1024 the icon goes ABOVE its label and the cells sit side by side: three across on a
 * tablet, two on a phone.
 *
 * The lattice is drawn per-cell rather than with the usual gap-and-background trick, because
 * .mat-stats sits on #EAE2D8 on the homepage and on --sand-hi on Our Material — a faked gap
 * would have to know which, and would be wrong on the next page that reuses this.
 *
 * The :last-child span rules fill the short final row (five in threes leaves one gap; five in
 * twos leaves one) so the band never ends on a hole. They are written against the cell's
 * POSITION IN ITS ROW, not against "the fifth one", so adding a sixth stat still lays out.
 */
@media(max-width:1024px){
  .mat-stats{grid-template-columns:repeat(3,1fr);
    padding:0 var(--pad) clamp(30px,6vw,50px)}
  .mstat{flex-direction:column;justify-content:flex-start;text-align:center;
    gap:clamp(10px,1.8vw,16px);padding:clamp(20px,3.4vw,30px) clamp(6px,1.2vw,16px)}
  .mstat .ico{width:clamp(52px,8vw,72px);height:clamp(52px,8vw,72px)}
  .mstat+.mstat{border-left:0}
  .mstat:not(:nth-child(3n+1)){border-left:1px solid var(--hair)}
  .mstat:nth-child(n+4){border-top:1px solid var(--hair)}
  .mstat:last-child:nth-child(3n+2){grid-column:span 2}
}
@media(max-width:560px){
  .mat-stats{grid-template-columns:repeat(2,1fr)}
  /* Undo the three-across lattice before drawing the two-across one. */
  .mstat:not(:nth-child(3n+1)){border-left:0}
  .mstat:nth-child(n+4){border-top:0}
  .mstat:last-child:nth-child(3n+2){grid-column:auto}
  .mstat:nth-child(even){border-left:1px solid var(--hair)}
  .mstat:nth-child(n+3){border-top:1px solid var(--hair)}
  .mstat:last-child:nth-child(odd){grid-column:1/-1}
}
@media(max-width:900px){
  :root{--hdr-h:62px}
  .mainnav{display:none}
  .burger{display:block}
  .logo-link{margin-right:auto}
  .hdr-tools{margin-left:0}
  .logo{height:22px}
  .abar-msg{font-size:9.96px;letter-spacing:.2px}
  .abar{gap:12px}
  .shopband-copy{position:static;transform:none;right:auto;width:auto;
    padding:clamp(22px,5vw,32px) 2px 4px;text-align:left}
  .shopband-copy p{max-width:46ch}
  .split{grid-template-columns:1fr}
  .split.rev figure{order:-1}
  .split figure{min-height:280px}
  /*
   * Same decision, much sharper: a 375x600 frame keeps only 27% of the image's width, so 78% was
   * showing bags two and three and the standfirst ran straight across their handles. 45% puts the
   * crescent bag complete to the right of the copy with the haze behind the words. Further left
   * than about 35% and there is no bag in the hero at all.
   */
  .hero-img{object-position:45% 62%}
  .hero{min-height:min(74vh,600px)}
  .hero-fade{background:linear-gradient(180deg,rgba(234,226,216,.55) 0%,rgba(234,226,216,.4) 40%,rgba(234,226,216,.15) 70%,rgba(234,226,216,.05) 100%)}
}
@media(max-width:760px){
  .why-grid{grid-template-columns:1fr}
  .why-item{padding:32px clamp(14px,3vw,30px)}
  .why-item:first-child{padding-top:0}
  .why-item+.why-item{border-left:0;border-top:1px solid var(--hair)}

  /*
   * The product card's footer stacks: details on top, a full-width Add to cart under them.
   *
   * ⚑ IN shell.css ON PURPOSE, and moved here from woo.css on 14 Sep 2026. The row layout above
   * gives the button `flex:0 0 auto` and `white-space:nowrap`, so it keeps its full 137px and
   * `.card-text{min-width:0}` absorbs the whole shortfall. On a 375px phone the homepage carousel
   * card is 227px wide — the arrows sit beside the viewport and take ~100px of it — which left the
   * text column 30px and broke "INSPIRED BY CURRY PUFF" one word to a line, four lines deep.
   *
   * The rules were right; they were only in the wrong file. woo.css loads on shop screens alone, so
   * /shop/ looked correct and the homepage band — the SAME .card component, filled from WooCommerce
   * by template-parts/content/home/collection.php — did not. Same trap the cart drawer and the
   * header bag badge are in this file to avoid. Anything .card needs on every screen belongs here.
   *
   * 760px matches the breakpoint woo.css used, so the shop is unchanged. Above it the card is wide
   * enough for the row, and the desktop icon row is untouched.
   */
  .card-info{flex-direction:column;align-items:flex-start;gap:14px}
  .card .add-cart{width:100%}
}
@media(max-width:560px){
  .foot-top{grid-template-columns:1fr;text-align:left}
  .foot-mark{text-align:left}
  .foot-mark hr{margin-left:0}
  .foot-mark img{margin-left:0}
  .foot-cols{grid-template-columns:1fr 1fr}
}
@media(prefers-reduced-motion:reduce){
  *{animation:none!important;transition:none!important;scroll-behavior:auto!important}
  .rv{opacity:1;transform:none}
}


/* ------------------------------------------------------------------ WhatsApp ---------------- */
/* Printed by inc/whatsapp.php, and only when the client has a real WhatsApp link on file.

   z-index 60 puts it under the cart drawer (80), the mobile nav overlay (120) and the gallery
   lightbox (200). A chat button floating over an open drawer is the commonest way this pattern
   goes wrong, and it is an ordering decision rather than a bug to find on someone else's phone.

   Brand green rather than WhatsApp's #25D366: the glyph carries the recognition by itself, and a
   saturated green circle is the one thing on the page that would belong to no other part of this
   palette. One line to change if the client would rather have the official colour.

   No idle animation on purpose. A bouncing button on every page of a considered brand reads as an
   advert, and the reduced-motion rules above would disable it for some visitors anyway, so it
   could never be relied on to draw the eye. */
.wa-float{
  position:fixed;
  right:clamp(16px,2.4vw,28px);
  /* env() keeps it clear of the iOS home indicator; max() keeps it sane where env() resolves to 0. */
  bottom:max(18px,calc(env(safe-area-inset-bottom) + 12px));
  z-index:60;
  display:flex;align-items:center;justify-content:center;
  width:54px;height:54px;border-radius:50%;
  background:var(--green);color:var(--cream);
  box-shadow:0 6px 20px rgba(0,0,0,.22);
  text-decoration:none;
  transition:transform .18s ease,background-color .18s ease
}
.wa-float:hover,.wa-float:focus-visible{background:var(--green-mid);color:var(--cream);transform:translateY(-2px)}
.wa-float:focus-visible{outline:3px solid var(--gold);outline-offset:3px}
.wa-float__icon{display:block;width:28px;height:28px}
@media(max-width:768px){
  .wa-float{width:50px;height:50px}
  .wa-float__icon{width:26px;height:26px}
}
@media print{.wa-float{display:none}}
/* Tucked away by site.js while a primary action is on screen — see the note there for the
   measurement that made this necessary. visibility, not just opacity, so a hidden button cannot
   still take keyboard focus; the 0s delay on the way out lets the fade finish first. */
.wa-float.is-tucked{
  opacity:0;visibility:hidden;pointer-events:none;
  transform:translateY(12px) scale(.92);
  transition:opacity .18s ease,transform .18s ease,visibility 0s .18s
}
