/*
Theme Name: Pulse Luxe
Theme URI: https://github.com/Pulse-PEMF/PulsePEMF-Shop-Theme
Description: Standalone theme (converted off Astra in 0.8.0) carrying the Pulse PEMF luxury design system — Cormorant Garamond / Jost, ink & gold.
Author: Pulse PEMF IT
Version: 0.12.42
*/

/* ============ Fonts (self-hosted, variable) ============ */
@font-face{
  font-family:'Cormorant Garamond';
  src:url('fonts/cormorant.woff2') format('woff2');
  font-weight:300 500; font-style:normal; font-display:swap;
}
@font-face{
  font-family:'Cormorant Garamond';
  /* Variable italic (wght axis), 2026-08-06 — the previous file was a STATIC 400
     cut, so an italic inside a 300 display heading rendered 400 no matter what
     CSS asked for: that is the "the italic word looks like a different font"
     complaint. Metrics at 400 are within 0.1% of the old file and glyph
     coverage is identical, so existing body italics are unchanged. Range is
     capped at 500 like the roman — the axis reaches 700, and 600/700 is
     forbidden here.
     The FILENAME carries the version (-var), not a ?query: same-name-new-bytes
     would leave returning visitors on the cached static cut reporting the bug
     as unfixed, and a query string has to be repeated in the functions.php
     preload list — two literals that drift silently into a double fetch and
     the FOUT the preload exists to prevent. A wrong filename 404s loudly. */
  src:url('fonts/cormorant-italic-var.woff2') format('woff2');
  font-weight:300 500; font-style:italic; font-display:swap;
}
@font-face{
  font-family:'Jost';
  src:url('fonts/jost.woff2') format('woff2');
  font-weight:300 500; font-style:normal; font-display:swap;
}

/* ============ Tokens (canonical luxury system) ============
   Type ladder (0.6.0 — "small text" complaint): nothing below .74rem;
   micro labels/captions .8 · eyebrows .8 · table heads/tabs .82 ·
   buttons/text-links/spec keys .85 · body clamp(1.125→1.25).
   Secondary text is ivory-60 (7:1 on ink); ivory-40 is reserved for
   disabled states and non-text decoration only. */
:root{
  --ink:#0f0f11;
  --ink-2:#151518;
  --ivory:#f1ece2;
  --ivory-60:rgba(241,236,226,.72);
  --ivory-40:rgba(241,236,226,.5);
  --gold:#c2a15e;
  --gold-ink:#7d6229; /* gold for ivory grounds — #c2a15e is 2.09:1 on ivory, this is 4.89:1 */
  --gold-soft:rgba(194,161,94,.55);
  --hairline:rgba(241,236,226,.16);
  --hairline-ink:rgba(15,15,17,.16);
  --ink-soft:rgba(15,15,17,.62); /* secondary text on ivory grounds — 5.09:1 */
  --tile:#f7f4ee; /* product-photo tile — warm cream, sits between #fff and the ivory page */
  --error:#e07b6d; /* error voice on ink — the 2024 #c0392b failed contrast */
  --error-ink:#9c3a28; /* error voice on ivory — the on-ink salmon fails there */
  --serif:'Cormorant Garamond', 'Times New Roman', serif;
  --sans:'Jost', 'Avenir Next', 'Helvetica Neue', sans-serif;
  --pad:clamp(1.4rem, 5vw, 5rem);
}

/* ============ Ground-aware role tokens (0.10.0) ============
   THE fix for the counter-block arms race: rules below say what role a color
   plays (--fg, --line, --field…); the GROUND decides the value. Custom
   properties resolve by inheritance, not specificity, so a paper surface
   flips every substituted rule at once — no per-surface counter, no
   specificity fight. Gold/error get -role variants because their legible
   value differs per ground (gold is 2.09:1 on ivory). Gold FACES
   (backgrounds) stay raw --gold on both grounds — only gold TEXT re-scopes. */
:root{
  /* PAPER is the default ground — every store page is paper; only the
     chrome components below re-scope to the dark set. A surface nobody
     styled yet renders paper like the rest of the store, not dark. */
  --ground:var(--ivory);
  --fg:var(--ink);
  --fg-soft:var(--ink-soft);
  --fg-mute:rgba(15,15,17,.38);
  --body-fg:var(--ink);
  --line:var(--hairline-ink);
  --field:#fff;
  --panel:#fff;
  --btn-line:var(--hairline-ink); /* secondary-button border: hairline-ink on paper, gold-soft on ink */
  --gold-role:var(--gold-ink);    /* gold's only legible voice on ivory (raw gold is 2.09:1) */
  --err-role:var(--error-ink);
}
/* The three genuinely-dark chrome components re-scope their own tokens —
   they sit inside paper pages and must not inherit the paper set. */
.site-header, .site-footer,
p.woocommerce-store-notice, p.demo_store{
  --ground:var(--ink);
  --fg:var(--ivory);
  --fg-soft:var(--ivory-60);
  --fg-mute:var(--ivory-40);
  --body-fg:var(--ivory-60);
  --line:var(--hairline);
  --field:var(--ink-2);
  --panel:var(--ink-2);
  --btn-line:var(--gold-soft);
  --gold-role:var(--gold);
  --err-role:var(--error);
}

/* ============ Global typography (skeleton scope: fonts only, no color shift) ============ */
body, button, input, select, textarea{
  font-family:var(--sans);
}
body{
  font-weight:350;
  -webkit-font-smoothing:antialiased;
  /* ONE figure law (0.12.13): Cormorant's DEFAULT numerals are old-style —
     measured at 100px, cap "X" inks 64px but "1" inks 40px, exactly the
     x-height of lowercase "x". So "Pulse X1" renders as a cap-height X next
     to an x-height 1 and reads "Pulse Xi" (Logan 2026-08-17); "5" and "9"
     also drop below the baseline mid-word. lining-nums swaps in the
     cap-height figures the woff2 already carries (verified: the lnum feature
     is present in BOTH the roman and the italic-var cut — digit advances
     change 429.6px -> 458.4px / 388.5px -> 417.1px, and "1" ink goes
     40px -> 64px, matching "X" exactly).
     Set on body, not on the product title: model names carrying digits show
     up in titles, breadcrumbs, cart/order line items, spec sheets, related
     products and the landing copy — every serif digit in the theme wants
     cap-height, so one inherited declaration beats a dozen per-surface ones.
     Jost is lining-only, so the sans side is unchanged either way. */
  font-variant-numeric:lining-nums;
}
h1, h2, h3, .entry-title{
  font-family:var(--serif);
  font-weight:300;
  line-height:1.08;
  letter-spacing:.005em;
}
/* ONE heading law (0.10.0): h1-h3 = serif display voice (checkout "Your
   order"/"Billing details", cart/my-account section heads — the voice Logan
   approved through six walkthrough rounds); h4-h6 = sans utility tier.
   Replaces three per-surface serif-h3 overrides that left product/builder
   h3s sans (RC6). Astra pinned h3-h6 to Montserrat — keep h4-h6 on-system. */
h4, h5, h6{font-family:var(--sans)}
/* Money font, everywhere: single-product/archive price rules below only ever
   added color+size on top of this — every OTHER price context (variation
   price, cart, checkout, mini-cart, order-received) was falling through to
   the body sans default with no rule targeting it at all. Target
   .woocommerce-Price-amount (not .price) — cart/checkout price cells render
   the amount span directly with no .price wrapper, so .price alone misses them.
   font-weight:300 is load-bearing, not cosmetic: the self-hosted Cormorant
   woff2 only declares weight 300-500 (see @font-face above). Astra's own
   default bolds .price/.woocommerce-Price-amount to 700 — outside that
   range, so the browser fakes it with synthetic bold, and faux-bold
   distorts the currencySymbol "$" far more than the old-style digit glyphs
   next to it (thin strokes vs a full-height bar), which is what actually
   reads as "two different fonts" on prices. Pinning the real 300 weight
   the font-face has a true cut for removes the synthetic bolding and the
   symbol/digit mismatch with it. */
/* ONE money law (0.10.0, replaces the serif/300 treatment + its twelve
   per-surface size compensations): money is Jost like the UI around it, at
   the size of its context — Cormorant's small x-height read ~2 sizes
   smaller at equal px, which is every "total is tiny / different font"
   complaint (my-orders, checkout review). tabular-nums keeps columns of
   amounts aligned. To bring serif money back deliberately: set
   --money-font:var(--serif) here plus a global font-size:1.18em optical
   compensation — never bare. */
/* lining-nums repeated on purpose: font-variant-numeric is ONE property, not a
   shorthand, so a bare tabular-nums here would wipe the inherited body value —
   invisible today (Jost is lining-only) but it would silently restore old-style
   money the moment --money-font goes back to var(--serif) as the note above
   invites. */
.woocommerce .woocommerce-Price-amount{font-family:var(--sans);font-weight:400;font-variant-numeric:lining-nums tabular-nums}
em{font-style:italic;font-weight:400}
/* self-hosted Cormorant/Jost stop at 500 — any 700 is synthesized fake-bold
   (distorted glyphs, "different font" complaints). Cap emphatic weight at
   the real cut; WC core loves 700 (strong, th, td::before, required *). */
body:not(.luxe-landing) strong, body:not(.luxe-landing) b{font-weight:500}
::selection{background:var(--gold);color:var(--ink)}

/* ============================================================
   Commerce dress — DARK. The store wears the same ink/gold/ivory
   system as the landing (Logan 2026-07-13: the light/tan variant
   was jarring). White survives only behind product photography.
   Cosmetic only: no layout/display changes to the builder flow.
   ============================================================ */
body:not(.luxe-landing){
  background:var(--ground);color:var(--body-fg);
  /* same base clamp as the landing — Astra's 16px (15/14 at breakpoints)
     ran unopposed here, splitting the store from the landing's 18px */
  font-size:clamp(1.125rem, 1.05rem + .3vw, 1.25rem);
}

/* ---- buttons: canonical dark luxe hairline, gold fill on hover ---- */
.woocommerce a.button:not(.show-password-input),
.woocommerce button.button:not(.show-password-input),
.woocommerce input.button:not(.show-password-input),
.woocommerce #respond input#submit,
.woocommerce button#place_order,
.ast-button:not(.show-password-input),
.ast-custom-button,
.wp-block-button__link{
  font-family:var(--sans);
  font-weight:400;
  font-size:.85rem;
  letter-spacing:.18em;
  text-transform:uppercase;
  background:transparent;
  color:var(--fg);
  border:1px solid var(--btn-line);
  border-radius:0;
  padding:.85rem 1.6rem;
  transition:background .45s ease, color .45s ease, border-color .45s ease;
}
.woocommerce a.button:not(.show-password-input):hover,
.woocommerce button.button:not(.show-password-input):hover,
.woocommerce input.button:not(.show-password-input):hover,
.woocommerce #respond input#submit:hover,
.woocommerce button#place_order:hover,
.ast-button:not(.show-password-input):hover,
.ast-custom-button:hover,
.wp-block-button__link:hover{
  background:var(--gold);
  border-color:var(--gold);
  color:var(--ink);
}

/* ---- store notice ---- */
body p.woocommerce-store-notice, body p.demo_store{
  background-color:var(--ink-2);color:var(--ivory-60);border-bottom:1px solid var(--hairline);
  box-shadow:none; /* woocommerce-grid.min.css ships a 1em drop shadow */
}
body p.woocommerce-store-notice a, body p.demo_store a{color:var(--gold);background:transparent}
/* Astra's default "hang-over-top" position sits the notice over the fixed
   header, hiding the wordmark — pin it to the bottom edge instead everywhere
   (Storefront pattern: no magic-number header offsets, survives the two-line
   mobile wrap). Was luxe-landing-only; widened site-wide so every page
   (builder, cart, checkout, get-started, products, my-account) matches the
   home/equine treatment instead of duplicating this rule per-page. */
body p.woocommerce-store-notice,
body p.demo_store{
  position:fixed;top:auto;bottom:var(--pulse-fixed-bar-h,0px);left:0;right:0;z-index:95;
  border-bottom:none;border-top:1px solid var(--hairline);
}
/* 2026-08-04: for logged-in reviewers (staff/admin bar showing), Astra prints
   a higher-specificity dynamic rule — `.admin-bar .demo_store[data-position=
   "hang-over-top"]{top:32px}` (class-astra-woocommerce.php) — that beats the
   top:auto above regardless of source order. top:32px + bottom:0 on a fixed
   element stretches it to fill the whole viewport as a black overlay.
   !important is the only lever that outguns Astra's un-flagged declaration. */
body p.woocommerce-store-notice,
body p.demo_store{top:auto !important}

/* ---- Astra separate-container content boxes → let the ink through.
   NB: ast-separate-container sits ON body, not below it. ---- */
body.ast-separate-container:not(.luxe-landing) .ast-article-inner,
body.ast-separate-container:not(.luxe-landing) .ast-article-single:not(.ast-related-post),
body.ast-separate-container:not(.luxe-landing) .ast-article-post,
body.ast-separate-container:not(.luxe-landing) .ast-woocommerce-container{background-color:transparent;background-image:none}

/* ---- header: ink bar + luxe wordmark (the black IT-dept logo png is
   invisible on ink and off-brand — swap for the landing wordmark) ---- */
.site-header, .ast-header-sticked, .main-header-bar{background:var(--ink)}
body:not(.luxe-landing) .site-header{border-bottom:1px solid var(--hairline)}
body:not(.luxe-landing) .custom-logo-link img{display:none}
body:not(.luxe-landing) .custom-logo-link::before{
  content:"Pulse PEMF";
  font-family:var(--sans);font-weight:500;font-size:.95rem;
  letter-spacing:.58em;text-transform:uppercase;color:var(--ivory);
}
body:not(.luxe-landing) .custom-logo-link::after{content:".";color:var(--gold);font-size:.95rem;font-weight:500}
body:not(.luxe-landing) .site-header a,
body:not(.luxe-landing) .site-header .ast-header-account-wrap{color:var(--ivory)}
body:not(.luxe-landing) .site-header svg{fill:var(--ivory)}
/* Account icon — the blanket .site-header svg{fill} misses the logged-in
   account glyph (own color / stroke-based outline), so pin it on every paint
   property. fill==stroke==ivory means no outline artifact whichever it is. */
body:not(.luxe-landing) .ast-header-account-wrap,
body:not(.luxe-landing) .ast-header-account-wrap a,
body:not(.luxe-landing) .ast-header-account-wrap svg,
body:not(.luxe-landing) .ast-header-account-wrap svg *{
  color:var(--ivory) !important;fill:var(--ivory) !important;stroke:var(--ivory) !important;
}
/* Account icon names itself on hover (Logan 2026-08-06) — the glyph alone left
   people guessing. Absolutely positioned off a relative wrap, so it can never
   shift the header row; right-anchored so it grows leftward and stays inside
   the viewport at 390. .site-header is position:fixed/overflow:visible, so
   nothing clips it. aria-label on the anchor (header.php) carries the same
   words for screen readers; no `title` attribute on purpose — the native
   tooltip would double up on this one. */
body:not(.luxe-landing) .ast-header-account-wrap{position:relative}
body:not(.luxe-landing) .ast-header-account-link::after{
  content:"My Account";
  position:absolute;top:calc(100% + 12px);right:0;
  font-family:var(--sans);font-size:.6rem;font-weight:400;
  letter-spacing:.22em;text-transform:uppercase;white-space:nowrap;
  color:var(--ivory-60) !important;background:var(--ink-2);
  border:1px solid var(--hairline);padding:.5rem .7rem;
  opacity:0;pointer-events:none;transition:opacity .35s ease;
}
body:not(.luxe-landing) .ast-header-account-link:hover::after,
body:not(.luxe-landing) .ast-header-account-link:focus-visible::after{opacity:1}

/* ---- footer ---- */
body:not(.luxe-landing) .site-footer,
body:not(.luxe-landing) .site-footer .ast-builder-grid-row{background:var(--ink)}
body:not(.luxe-landing) .site-footer{
  border-top:1px solid var(--hairline);
  font-size:.8rem;letter-spacing:.28em;text-transform:uppercase;color:var(--ivory-60);
}
/* 2026-08-27 (Logan): store pages ended in a bare centered copyright line with
   no route back to pulsepemf.com. They now render template-parts/luxe-footer.php
   — the same partial as the two landing templates — so the element carries both
   .site-footer (ink ground + the type rule above) and .luxe-footer (layout).
   The .luxe-footer/.text-link declarations live nested inside the
   body.luxe-landing block (~2650 / ~2380) and are scoped out here, so their four
   layout declarations are restated for the store ground. Restating beats
   un-nesting that whole block: everything else in it is landing-only.
   The below-footer-wrap and .ast-footer-copyright rules that stood here are gone
   with the markup they targeted. */
body:not(.luxe-landing) .luxe-footer{
  padding:2.6rem var(--pad);
  display:flex;justify-content:space-between;align-items:center;gap:1.5rem;flex-wrap:wrap;
}
body:not(.luxe-landing) .luxe-footer nav{display:flex;gap:1.8rem;flex-wrap:wrap}
body:not(.luxe-landing) .luxe-footer .text-link{
  /* .85rem/.3em, NOT the .8rem/.28em the footer wrapper carries — these are the
     .text-link values from the landing block. Probed 2026-08-27: taking the
     wrapper's scale rendered the store links 12.8px/3.584px against the
     homepage's 13.6px/4.08px, and "the same footer" has to mean the same. */
  font-size:.85rem;letter-spacing:.3em;text-transform:uppercase;font-weight:400;
  color:var(--ivory-60);border-bottom:1px solid var(--hairline);padding-bottom:.35rem;
  transition:color .4s ease, border-color .4s ease;
}
body:not(.luxe-landing) .luxe-footer .text-link:hover{color:var(--gold);border-color:var(--gold-soft)}

/* ---- Astra chrome the child theme never dressed (audit 2026-07-28) ---- */
/* cart flyout drawer — a paper object sliding over either ground (0.7.9;
   was themed ink in 0.6.0 when the whole store was dark) */
/* Base drawer mechanics (0.8.0 standalone conversion) — position:fixed,
   the off-canvas hidden-by-default transform, and the overlay scrim used
   to be astra-addon's own WooCommerce-module CSS (dynamic.css.php /
   compatibility CSS), not this child stylesheet — only the colors below
   were ever theme-owned. astra-addon no longer runs at all (confirmed via
   its own get_template()!=='astra' guard), so the drawer's basic
   slide-in/hide mechanics have to live here now, driven by
   js/cart-drawer.js toggling body.pulse-cart-drawer-open. */
body:not(.luxe-landing) .astra-cart-drawer{
  position:fixed;top:0;right:0;height:100%;width:min(420px,90vw);
  transform:translateX(100%);transition:transform .3s ease;
  z-index:10000;overflow-y:auto;padding:0;
}
body.pulse-cart-drawer-open:not(.luxe-landing) .astra-cart-drawer{transform:translateX(0)}
body:not(.luxe-landing) .astra-mobile-cart-overlay{
  position:fixed;inset:0;background:rgba(0,0,0,.5);
  opacity:0;pointer-events:none;transition:opacity .3s ease;z-index:9999;
}
body.pulse-cart-drawer-open:not(.luxe-landing) .astra-mobile-cart-overlay{opacity:1;pointer-events:auto}
body:not(.luxe-landing) .astra-cart-drawer-header{
  display:flex;align-items:center;justify-content:space-between;padding:1.25rem 1.5rem;
}
body:not(.luxe-landing) .astra-cart-drawer-close{
  background:transparent;border:none;font-size:1.5rem;line-height:1;cursor:pointer;color:inherit;
}
body:not(.luxe-landing) .astra-cart-drawer-content{padding:0 1.5rem 1.5rem}
body:not(.luxe-landing) .astra-cart-drawer{background-color:var(--ivory);color:var(--ink)}
body:not(.luxe-landing) .astra-cart-drawer .astra-cart-drawer-header{border-bottom:1px solid var(--hairline-ink)}
body:not(.luxe-landing) .astra-cart-drawer .astra-cart-drawer-title,
body:not(.luxe-landing) .astra-cart-drawer .astra-cart-drawer-close{color:var(--ink)}
body:not(.luxe-landing) .astra-cart-drawer a{color:var(--ink)}
body:not(.luxe-landing) .astra-cart-drawer a:hover{color:var(--gold-ink)}
body:not(.luxe-landing) .astra-cart-drawer .woocommerce-mini-cart-item,
body:not(.luxe-landing) .astra-cart-drawer .woocommerce-Price-amount{color:var(--ink)}
body:not(.luxe-landing) .astra-cart-drawer .woocommerce-mini-cart__total{color:var(--ink);border-top:1px solid var(--hairline-ink)}
/* size + typography (0.8.1) — same missing-Astra-base regression as the cart
   table thumbnail above: the drawer's product-name link had no font rule at
   all, so it fell through to WC core's own mini-cart CSS (bold, 1.5em —
   30px/700 measured), reading as "heavy" against this theme's Jost voice
   everywhere else. Match the cart/checkout table's own product-name
   treatment (line ~547) instead of inventing a new size. */
/* hairline between items — the drawer list ran together with no separation
   while every other surface uses rules (Logan 2026-08-05). Left padding is
   load-bearing: WC absolutely positions a.remove at the li's top-left, and
   a bare `padding:1rem 0` wipes the 2em gutter it needs (name overlapped
   the × — caught on screenshot). Keep the gutter, pin the × to the row. */
body:not(.luxe-landing) .astra-cart-drawer .woocommerce-mini-cart-item{
  position:relative;border-bottom:1px solid var(--hairline-ink);
  padding:1rem 0 1rem 32px;margin:0;
}
/* The drawer is a PAPER surface (its own ground computes ivory), so a #fff
   thumbnail was a white square on cream. Same recipe as the loops and the
   gallery — the photo's baked-in white multiplies away into the ground it
   sits on. No tile of its own: the mini-cart <a> wraps the product NAME as
   well as the img, so there is no wrapper here that could carry one without
   putting a cream slab behind the text. The drawer's ivory is the ground. */
body:not(.luxe-landing) .astra-cart-drawer .woocommerce-mini-cart-item img{
  background:none;mix-blend-mode:multiply;
  border:1px solid var(--gold-soft);width:70px;height:70px;object-fit:contain;
}
body:not(.luxe-landing) .astra-cart-drawer .woocommerce-mini-cart-item a:not(.remove){
  font-weight:400;font-size:1.25rem;
}
/* one deliberate type ladder (0.8.3 — Logan walkthrough: "3 fonts, 5 sizes").
   Two voices only: Jost eyebrow (.85rem/400/uppercase/.18em — same as the
   buttons below) for labels, Cormorant for names + money. WC core's mini-cart
   CSS otherwise leaks its own sizes/weights in (30px/700 remove ×, 700
   Subtotal — faux-bold: self-hosted Jost stops at 500). */
body:not(.luxe-landing) .astra-cart-drawer-title{
  font-size:.85rem;font-weight:400;letter-spacing:.18em;text-transform:uppercase;
}
body:not(.luxe-landing) .astra-cart-drawer .woocommerce-mini-cart-item .quantity{
  font-family:var(--sans);font-size:.95rem;color:var(--ink-soft);letter-spacing:.06em;
}
body:not(.luxe-landing) .astra-cart-drawer .woocommerce-mini-cart-item .quantity .woocommerce-Price-amount{
  font-size:1.2rem;font-weight:400;
}
body:not(.luxe-landing) .astra-cart-drawer .woocommerce-mini-cart__total strong{
  font-family:var(--sans);font-size:.85rem;font-weight:400;letter-spacing:.18em;
  text-transform:uppercase;color:var(--ink-soft);
}
body:not(.luxe-landing) .astra-cart-drawer .woocommerce-mini-cart__total .woocommerce-Price-amount{
  font-size:1.4rem;font-weight:400;
}
body:not(.luxe-landing) .astra-cart-drawer a.remove{font-size:1.25rem;font-weight:400}
body:not(.luxe-landing) .astra-cart-drawer input.qty,
body:not(.luxe-landing) .astra-cart-drawer .quantity .minus,
body:not(.luxe-landing) .astra-cart-drawer .quantity .plus{
  background:#fff;border:1px solid var(--hairline-ink);color:var(--ink);
}
/* drawer remove × — same 22px centered circle as the cart table's (WC's
   default is 1em box with the glyph riding high against the border) */
body:not(.luxe-landing) .astra-cart-drawer a.remove{
  color:var(--ink-soft) !important;border:1px solid var(--hairline-ink);border-radius:50%;
  width:22px;height:22px;line-height:20px;font-size:.95rem;font-weight:400;text-align:center;
  /* vertically centered against the whole row, not pinned to its top
     (Logan round 2: "button too high"). !important: WC's
     .woocommerce.widget_shopping_cart .cart_list li a.remove is (0,4,1)
     and re-pins top:0 — the transform alone then centers the × ON the
     item's top border. */
  position:absolute;left:0;top:50% !important;transform:translateY(-50%);
}
body:not(.luxe-landing) .astra-cart-drawer .woocommerce-mini-cart__buttons a.button{
  background:transparent;border:1px solid var(--hairline-ink);color:var(--ink);border-radius:0;
  font-family:var(--sans);font-weight:400;letter-spacing:.18em;text-transform:uppercase;font-size:.85rem;
}
body:not(.luxe-landing) .astra-cart-drawer .woocommerce-mini-cart__buttons a.button:hover{
  background:var(--gold);border-color:var(--gold);color:var(--ink);
}
body:not(.luxe-landing) .astra-cart-drawer .woocommerce-mini-cart__buttons a.button.checkout{
  background:var(--gold);border-color:var(--gold);color:var(--ink);
}
body:not(.luxe-landing) .astra-cart-drawer .woocommerce-mini-cart__buttons a.button.checkout:hover{
  background:transparent;color:var(--gold-ink);border-color:var(--gold-ink);
}
/* scroll-top button — was #26222f on ink, 1.23:1 */
body:not(.luxe-landing) #ast-scroll-top{
  background-color:transparent;border:1px solid var(--gold-soft);color:var(--gold);
  border-radius:0;font-size:1rem;
}
body:not(.luxe-landing) #ast-scroll-top:hover{background-color:var(--gold);color:var(--ink)}
/* header cart badge — was Inter bold on #26222f pill w/ shadow; hide when empty.
   position/content/size were previously Astra-addon's dynamic customizer CSS
   (dynamic.css.php, theme-option-driven) — now gone with the theme, so the
   badge's base geometry (not just its color) is theme-owned here. */
body:not(.luxe-landing) .ast-site-header-cart i.astra-icon{position:relative}
body:not(.luxe-landing) .ast-site-header-cart i.astra-icon:after{
  content:attr(data-cart-total);
  position:absolute;top:-8px;right:-10px;
  font-size:.68rem;line-height:16px;height:16px;min-width:16px;
  text-align:center;font-style:normal;
  background:var(--gold);color:var(--ink);border-radius:0;box-shadow:none;
  font-family:var(--sans);font-weight:400;
}
body:not(.luxe-landing) .ast-site-header-cart .ast-site-header-cart-li:hover i.astra-icon:after{
  background-color:var(--gold);color:var(--ink);
}
body:not(.luxe-landing) .ast-site-header-cart i.astra-icon[data-cart-total="0"]:after{display:none}
/* Woo checkboxes — addon paints white rounded, checked state went navy */
body:not(.luxe-landing) .woocommerce input[type="checkbox"]{
  background:var(--field);border:1px solid var(--line);border-radius:0;
}
body:not(.luxe-landing) input[type="checkbox"]:checked{
  border-color:var(--gold);background-color:var(--gold);
}

/* ---- links & headings ---- */
/* text-decoration:none was Astra's own base-CSS reset — never restated in
   this child theme because it didn't need to be. Without Astra's CSS, the
   browser default underline shows through on plain-text links (most
   visibly the .custom-logo-link wordmark, an <a> with no styling of its
   own beyond the ::before/::after content this theme adds in header.php). */
body:not(.luxe-landing) a{color:var(--fg);text-decoration:none}
body:not(.luxe-landing) a:hover{color:var(--gold-role)}
body:not(.luxe-landing) h1, body:not(.luxe-landing) h2,
body:not(.luxe-landing) h3, body:not(.luxe-landing) h4,
body:not(.luxe-landing) h5, body:not(.luxe-landing) h6{color:var(--fg)}

/* ---- Woo product loops (archive + pulse_shop embedded loops) ----
   photos keep white (product shots are white-background), framed by hairline */
.woocommerce ul.products li.product .woocommerce-loop-product__title{
  font-family:var(--serif);font-weight:400;font-size:1.5rem;color:var(--fg);line-height:1.2;
}
.woocommerce ul.products li.product .price{
  font-weight:400;color:var(--fg-soft);font-size:1.25rem;
}
/* loop buttons: compact one-liners — the canonical .18em/.85rem wraps "SELECT
   OPTIONS" to two ragged lines inside narrow grid columns.
   Side padding is fluid for the same reason the builder button's is (~line
   1795): nowrap + a flat 1.3rem ring makes "Select options" 169.7px wide,
   which does not fit the 165.7px card of a 2-up 390px loop — it used to hang
   over the card edge, and now that the button is width:100% it would hang
   over its own border instead. 3vw resolves to 11.7px at 390 and clamps back
   to the full 1.3rem ring from ~693px up, so desktop is untouched. */
.woocommerce ul.products li.product a.button{
  white-space:nowrap;letter-spacing:.14em;font-size:.82rem;padding:.8rem clamp(.7rem,3vw,1.3rem);
}
/* Cart page / checkout review thumbnails keep the white tile deliberately:
   those two sit on genuinely white order panels, where a warm tile would draw
   a cream ring around the photo's own baked-in white — a seam, not a surface.
   Every thumbnail on a PAPER ground (loops below, gallery ~line 1370, cart
   drawer ~line 317) gets the tile + multiply treatment instead.
   A background of some kind is mandatory here, not decorative: transparent-PNG
   machine shots otherwise let the ground bleed through the product (2026-07-15). */
.woocommerce table.cart img,
.woocommerce table.cart td.product-thumbnail img,
.woocommerce-checkout-review-order td.product-thumbnail img{
  background:#fff;
  border:1px solid var(--gold-soft);
}

/* ---- loop grid: equal-height cards so the buttons line up ----
   WooCommerce still lays loops out with floats (woocommerce-layout.css:
   li.product{float:left;width:30.75%…}, smallscreen: width:48% + a
   nth-child(2n) float:right). Floated siblings each take their own content
   height, so a card whose price wraps to two lines ("$700.00 – $950.00" at
   the 165px mobile column) is 32px taller than its neighbour and its button
   sits 32px lower — the misalignment. A flex column with an auto margin
   CANNOT fix that on its own: with no free space in the card there is
   nothing for auto to absorb. The row has to equalise first, so the loop
   becomes a grid (items stretch to the tallest in their row by default) and
   THEN the button pins to the bottom.
   Geometry is deliberately identical to the float math it replaces: 1fr
   tracks + WC's own 3.8%/4% gutters, and row-gap:2.992em is WC's own
   li margin-bottom (it resolves against the same 18/20px font-size).
   min-width:0 on the card is load-bearing, not tidiness: a 1fr track will not
   shrink below its content's min-content width, and a nowrap "Select options"
   button is 169.7px against a 165.7px card — the two tracks grew and the grid
   hung 8px out of the container until the floor was removed.
   The width/margin reset needs BOTH selectors: WC's mobile rule carries a
   [class*=columns-] attribute and so out-specifies the plain one. No `body`
   prefix and no !important anywhere here — `.woocommerce` is a BODY class on
   archives (there is no inner wrapper), so a `body .woocommerce` descendant
   chain matches nothing, and this sheet already enqueues after
   woocommerce-layout/-smallscreen, which settles the equal-specificity ties.
   Column counts come from the columns-N class WC prints on every loop ul,
   above WC's own 768px smallscreen boundary; columns-2 falls through to the
   mobile default. */
.woocommerce ul.products{display:grid;grid-template-columns:repeat(2,1fr);column-gap:4%;row-gap:2.992em}
.woocommerce ul.products::before,.woocommerce ul.products::after{content:none}
.woocommerce ul.products li.product,
.woocommerce ul.products[class*="columns-"] li.product{width:auto;margin:0;min-width:0;display:flex;flex-direction:column}
/* the row's slack is absorbed ABOVE the button, by the photo/title/price link,
   not by margin-top:auto ON the button — that would REPLACE the button's own
   top margin, and each surface sets a different one (WC's 1em on archives,
   the plugin's 10px on the builder tiles). An auto margin here leaves every
   one of them exactly as it was and still lands the button on the card floor.
   Targeted by class, not :first-child: on a sale item WC prints span.onsale
   first, and that one is position:absolute, so an auto margin on it would
   absorb nothing and the button would float back up. */
.woocommerce ul.products li.product > a.woocommerce-LoopProduct-link{margin-bottom:auto}
/* full-width, centred label — this also settles the ragged x-positions: the
   button used to be as wide as its own label ("Select options" 169.7px next to
   "Add to cart" 163.4px in the same row). */
.woocommerce ul.products li.product a.button{width:100%;box-sizing:border-box;text-align:center}
@media (min-width:769px){
  .woocommerce ul.products{column-gap:3.8%}
  .woocommerce ul.products.columns-1{grid-template-columns:1fr}
  .woocommerce ul.products.columns-3{grid-template-columns:repeat(3,1fr)}
  .woocommerce ul.products.columns-4{grid-template-columns:repeat(4,1fr)}
  /* no columns-5/-6 here on purpose: nothing on the shop sets them, and when
     forced they measured broken at this card's minimum — at 1024px a 6-up runs
     the button label 3.7px past its own border, at 800px 30.9px past and the
     document picks up a horizontal scrollbar. Without a rule these fall through
     to the 2-up mobile default, which is merely narrow, not broken. Add one
     back only alongside a card that actually fits, and re-measure at 800px. */
}

/* ---- loop tiles: one square panel per product (punch list #16 + #18) ----
   Two faults, one treatment. (#18) The shots are 2:3, 3:2 and 1:1 originals
   and `woocommerce_thumbnail` is a hard 300x300 crop, so the portrait machines
   were beheaded and every product landed at a different scale — the WC option
   is 600 UNCROPPED now (a DB change; see the task-5 deploy sequence), and
   `contain` in a fixed square + uniform padding presents them as one set.
   (#16) The tile was #fff, a studio white that read as a hard cut-out
   floating on the ivory page.

   The tile is painted by li::before rather than by the img, and that is
   load-bearing: every product shot has studio white BAKED INTO the file, so a
   warm tile behind a `contain` photo shows a white rectangle sitting in a
   cream square (verified — it looks worse than the white tile did). The img
   multiplies instead, which maps its white to exactly the tile beneath it and
   leaves the product and its shadow alone. An img carrying its own background
   cannot do that: mix-blend-mode blends the element's *composite*, so the
   white would blend with the page and the padding ring would go dark. */
.woocommerce ul.products li.product{position:relative;isolation:isolate}
/* 2026-08-06 (Logan): no tile, no frame. The transparent masters are meant to
   sit ON the page, not inside a panel — a cream tile with a gold rule read as
   "white background with a gold border" and defeated the transparency we just
   shipped. The ::before stays (it cannot go): mix-blend-mode needs an opaque
   backdrop INSIDE li.product's isolated stacking context, or the baked-white
   accessory photos have nothing to multiply against. Painting it in the page
   ground instead of --tile keeps that backdrop while making it invisible, so
   an accessory's studio white maps to the exact ground behind it and a
   transparent machine shows the ground through its own alpha. Same pixel, no
   box. */
.woocommerce ul.products li.product::before{
  content:"";position:absolute;top:0;left:0;width:100%;aspect-ratio:1;
  background:var(--ground);border:0;box-sizing:border-box;
}
.woocommerce ul.products li.product img{
  position:relative;background:none;border:0;
  aspect-ratio:1;width:100%;height:auto;
  object-fit:contain;
  /* percentage padding, not a clamp: the builder's accessory grid runs 4-up at
     230px while the machine grid runs 3-up at 321px, and a fixed 24px ring ate
     21% of the small tile against 15% of the large one — the accessories read
     visibly shrunken next to the machines (Logan 2026-08-06). 6% resolves
     against the tile's own width, so an edge-to-edge product occupies 88% of
     the tile edge at EVERY column count and viewport. */
  padding:6%;box-sizing:border-box;
  mix-blend-mode:multiply;
}
/* MULTIPLY EXEMPTION for the transparent masters. multiply exists to map a
   photo's baked-in studio white onto the tile; an alpha image has no white to
   map, so it just darkens the product body — the XL Pro's shell is near-white
   and went visibly grey. WebP is the transparent-master format in this
   library and the ONLY other webp is WooCommerce's own placeholder — which is
   NOT a spare detail: 8 published products (every package) have no featured
   image, so /product-category/packages/ renders the placeholder on every tile.
   It is 100% opaque with a ~10% pure-white region, i.e. exactly the baked
   white multiply exists to map away, so it is excluded by name and the
   extension key alone would have put punch-list #16 back on a live archive.
   NOT "png means baked white": Bolster Set and Chair Frame are alpha PNGs too.
   They stay on multiply on purpose — their product bodies are dark, so mapping
   them against a #f7f4ee tile shifts them by ~3%, which is invisible, and one
   rule beats a growing per-file exception list.
   ponytail: attribute heuristic instead of a per-attachment class filter —
   one rule, no PHP. Upgrade to a class stamped on the attachment if a
   baked-white webp, or a LIGHT-bodied alpha PNG, is ever uploaded. Each
   selector adds one attribute to the surface's own multiply rule, so it wins
   on specificity without !important. */
.woocommerce ul.products li.product img[src$=".webp" i]:not([src*="woocommerce-placeholder" i]),
.woocommerce div.product .woocommerce-product-gallery img[src$=".webp" i]:not([src*="woocommerce-placeholder" i]),
body:not(.luxe-landing) .astra-cart-drawer .woocommerce-mini-cart-item img[src$=".webp" i]:not([src*="woocommerce-placeholder" i]){
  mix-blend-mode:normal;
}
/* explicit thumbnail size (0.8.1) — Astra's core CSS used to size these
   table thumbnails (~70px, measured off the pre-fork baseline); WC's own
   default is much smaller (34px) and nothing in this child theme ever
   restated a width, so cart/checkout thumbnails shrank site-wide the moment
   Astra's CSS left (Logan 2026-08-05, flagged on the cart drawer but the
   same regression hit the cart page table too). */
.woocommerce table.cart img,
.woocommerce table.cart td.product-thumbnail img,
.woocommerce-checkout-review-order td.product-thumbnail img{
  width:70px;height:70px;object-fit:contain;
}

/* sale badge + star rating — Astra hardcodes 2024-brand navy (#16435F) with a
   rounded pill; flat gold chip on dark grounds, ink chip on paper grounds */
.woocommerce span.onsale{
  background:var(--gold);color:var(--ink);border:0;border-radius:0;
  font-family:var(--sans);font-weight:400;font-size:.8rem;letter-spacing:.14em;text-transform:uppercase;
}
.woocommerce .star-rating{color:var(--gold)}
body.single-product .woocommerce span.onsale,
body.woocommerce-cart .woocommerce span.onsale,
body.page-id-224 .woocommerce span.onsale{background:var(--ink);color:var(--ivory)}
body.single-product .star-rating,
body.woocommerce-cart .star-rating,
body.page-id-224 .star-rating{color:var(--gold-ink)}

/* ---- pulse_shop builder chrome (body-prefixed: plugin sheet loads after this one) ---- */
/* both pulse-package-builder and pulse-shop-checkout/builder enqueue their
   CSS/JS from inside the [pulse_shop] shortcode callback, which runs during
   content rendering — after wp_head already printed. Their <link> lands at
   the tail of <body>, so on a slow connection the browser paints before it
   arrives: build-path AND browse-path both render at once, stacked below
   the hero, missing the plugin's own layout rules (unstyled HUMAN/ANIMAL
   tabs, etc). Plugin-owned bug (enqueue timing) — flagged, not patched
   there. Promoting just the plugin's own show/hide rule here (loads
   correctly, in <head>) holds the intended default — only the hero visible
   — from first paint; the late plugin CSS re-declares the same values
   harmlessly once it lands. */
body .pulse-path{display:none}
body .pulse-path.visible{display:block}
/* same story for the sticky footer's own default (plugin CSS: display:none
   until .visible is toggled) — without it, "BACK / NEXT: ACCESSORIES" flashes
   in its unstyled block position for the same late-CSS window. */
body .pulse-sticky-footer{display:none}
body .pulse-sticky-footer.visible{display:block}
/* hero LAYOUT promoted from the same late plugin sheet (shop-builder.css) —
   without it the two cards paint stacked/unstyled for the pre-footer-CSS
   window (Logan 2026-08-05: "/build/ flashes then loads"). Values mirror
   the plugin's own .pulse-hero/.pulse-hero-card rules. */
body .pulse-hero{
  display:flex;gap:24px;margin:clamp(32px,14vh,220px) auto 48px;
  justify-content:center;flex-wrap:wrap;
}
/* on ?resume= loads the hero is never the destination — the plugin JS (also
   footer-loaded) advances past it on init, so it must not paint at all.
   html.pulse-resume is stamped by the inline head script in functions.php.
   The plugin's own back-to-hero handler sets style.display inline, which
   still beats this rule if the hero is ever legitimately re-shown. */
html.pulse-resume .pulse-hero{display:none}
body .pulse-hero-card{
  flex:1;min-width:280px;max-width:450px;padding:40px 30px;
  text-align:center;cursor:pointer;
  border:1px solid var(--line);border-radius:0;background:transparent;
  transition:border-color .45s ease, background .45s ease;
}
body .pulse-hero-card:hover{transform:none;box-shadow:none}
body .pulse-hero-build:hover, body .pulse-hero-build.active,
body .pulse-hero-packages:hover, body .pulse-hero-packages.active{
  background:rgba(194,161,94,.08);
  border-color:var(--gold-soft);
}
body .pulse-hero-card h2{font-family:var(--serif);font-weight:300;color:var(--fg)}
body .pulse-hero-card p{color:var(--fg-soft);font-size:1.05rem;line-height:1.55}
body .pulse-section-title, body .pulse-step-title{
  font-family:var(--serif);font-weight:300;color:var(--fg);
  border-bottom:1px solid var(--line);
}
/* The theme never declared a SIZE here, so the grid headings fell through to
   the plugin's `.pulse-section-title{font-size:22px}` — a 22px serif head
   sitting on top of 27px product titles, which reads as a caption rather than
   a section (Logan 2026-08-06). Sized here in the theme's own h2 register.
   .pulse-step-title is deliberately left at the plugin's 22px: it lives in the
   sticky step chrome, where a 33px head would blow the bar's height. */
body .pulse-section-title{font-size:clamp(1.75rem,2.2vw,2.1rem)}
body .pulse-section-subtitle, body .pulse-step-subtitle{color:var(--fg-soft);font-size:1rem}
body .pulse-step-number{
  background:transparent;border:1px solid var(--gold-soft);color:var(--gold-role);
}
body .pulse-sticky-header, body .pulse-sticky-footer{background:var(--ground);border-color:var(--line)}
body .pulse-tab{
  background:transparent;border:1px solid var(--line);color:var(--fg-soft);
  font-family:var(--sans);font-weight:400;font-size:.82rem;letter-spacing:.18em;text-transform:uppercase;
  transition:border-color .45s ease, color .45s ease;
  cursor:pointer; /* markup is a plain <div onclick>, not button/a — plugin-frozen, CSS-only fix */
}
body .pulse-tab:hover{border-color:var(--gold-soft);color:var(--fg)}
body .pulse-tab.active{background:transparent;border-color:var(--gold);color:var(--gold-role)}
body .pulse-nav-btn.primary, body .pulse-nav-btn.checkout,
body .pulse-nav-btn.secondary{
  background:transparent;color:var(--fg);border:1px solid var(--btn-line);border-radius:0;
  font-family:var(--sans);font-weight:400;letter-spacing:.18em;text-transform:uppercase;
}
body .pulse-nav-btn.secondary{border-color:var(--line);color:var(--fg-soft)}
body .pulse-nav-btn:hover{opacity:1;background:var(--gold);border-color:var(--gold);color:var(--ink)}
body .pulse-products .products .product, body .pulse-products ul.products li.product{background:transparent;border:none}
body .pulse-products ul.products li.product a.button,
body .pulse-products ul.products li.product a.add_to_cart_button,
body .pulse-products ul.products li.product a.product_type_variable,
body .pulse-products ul.products li.product a.product_type_grouped{
  background:transparent !important;
  color:var(--fg) !important;
  border:1px solid var(--btn-line) !important;
}
body .pulse-products ul.products li.product a.button:hover,
body .pulse-products ul.products li.product a.add_to_cart_button:hover,
body .pulse-products ul.products li.product a.product_type_variable:hover,
body .pulse-products ul.products li.product a.product_type_grouped:hover{
  background:var(--gold) !important;
  color:var(--ink) !important;
  border-color:var(--gold) !important;
}

/* ---- Woo notices ---- */
.woocommerce-message, .woocommerce-info, .woocommerce-error{
  background-color:var(--panel);
  border:1px solid var(--line);
  border-top:2px solid var(--gold);
  color:var(--fg-soft);
  outline:none;
}
.woocommerce-message::before, .woocommerce-info::before{color:var(--gold-role)}
/* required-field asterisk — dark ground, paper override on the two surfaces
   with real Woo forms (checkout billing/shipping, my-account register/login) */
.woocommerce form .required{color:var(--err-role);font-weight:400}
body.woocommerce-checkout .woocommerce form .required,
body.woocommerce-account .woocommerce form .required{color:var(--error-ink)}

/* builder cart/checkout links painted with inline background:var(--ast-global-color-0)
   — the pin makes them solid gold, identical to their hover. Hairline instead. */
body:not(.luxe-landing) a[style*="var(--ast-global-color-0"]{
  background:transparent !important;border:1px solid var(--btn-line) !important;
  color:var(--fg) !important;border-radius:0 !important;
  font-family:var(--sans);font-size:.85rem !important;
  letter-spacing:.18em !important;text-transform:uppercase !important;
  padding:.85rem 1.6rem !important;transition:background .45s ease, color .45s ease;
}
body:not(.luxe-landing) a[style*="var(--ast-global-color-0"]:hover{
  background:var(--gold) !important;border-color:var(--gold) !important;color:var(--ink) !important;
}

/* ---- checkout-workflow inline-styled pills (no class; plugin prints style="")  ---- */
.woocommerce a[href*="resume=browse"]{
  background:transparent !important;
  color:var(--fg) !important;
  border:1px solid var(--btn-line) !important;
  border-radius:0 !important;
  padding:.85rem 1.6rem !important;
  font-size:.85rem !important;
  text-transform:uppercase !important;
  letter-spacing:.18em;
  font-family:var(--sans);
  transition:background .45s ease, color .45s ease;
}
.woocommerce a[href*="resume=browse"]:hover{
  background:var(--gold) !important;
  color:var(--ink) !important;
  border-color:var(--gold) !important;
}

/* ---- disabled buttons — visible but clearly inactive on ink ---- */
.woocommerce .woocommerce-cart-form button[name="update_cart"]:disabled,
.woocommerce button.button.alt.disabled,
.woocommerce button.button.alt.disabled:hover,
.woocommerce button.button:disabled,
.woocommerce button.button:disabled[disabled]{
  background:transparent;
  border:1px solid var(--line);
  color:var(--fg-mute);
}

/* ---- cart totals / cross-sells panel ---- */
.woocommerce-cart .cart-collaterals .cart_totals{
  background:var(--panel);
  border:1px solid var(--line);
}
.woocommerce-cart .cart-collaterals .cart_totals>h2,
.woocommerce-cart .cart-collaterals .cross-sells>h2{
  background-color:transparent;
  margin:0 0 20px;
  border-bottom:1px solid var(--line);
  font-family:var(--serif);
  font-weight:300;
  color:var(--fg);
}

/* radius-zero for every form control, ending the per-rule whack-a-mole
   (astra-addon login inputs carry 4px at high specificity) */
body:not(.luxe-landing) input,
body:not(.luxe-landing) button,
body:not(.luxe-landing) textarea,
body:not(.luxe-landing) select{border-radius:0 !important}
/* Woo injects a show-password toggle via JS — Astra paints it as a blank gold
   chip with no icon. Restate as a quiet text toggle. */
body:not(.luxe-landing) button.show-password-input{
  background:transparent !important;border:none !important;width:auto;height:auto;
  color:var(--fg-soft);font-family:var(--sans);font-size:.8rem;
  letter-spacing:.18em;text-transform:uppercase;
}
body:not(.luxe-landing) button.show-password-input:hover{color:var(--gold-role)}
body:not(.luxe-landing) button.show-password-input::after{content:"Show"}
body:not(.luxe-landing) button.show-password-input.display-password::after{content:"Hide"}
/* ---- forms & inputs — charcoal fields, ivory text ---- */
body:not(.luxe-landing) input[type="text"],
body:not(.luxe-landing) input[type="email"],
body:not(.luxe-landing) input[type="tel"],
body:not(.luxe-landing) input[type="password"],
body:not(.luxe-landing) input[type="number"],
body:not(.luxe-landing) input[type="search"],
body:not(.luxe-landing) textarea,
body:not(.luxe-landing) select{
  background:var(--field);
  border:1px solid var(--line);
  border-radius:0;
  color:var(--fg);
  font-family:var(--sans);
}
body:not(.luxe-landing) input::placeholder,
body:not(.luxe-landing) textarea::placeholder{color:var(--fg-soft)}
body:not(.luxe-landing) .woocommerce form .form-row label{color:var(--fg-soft)}
/* select2 (country/state dropdowns) */
body:not(.luxe-landing) .select2-container--default .select2-selection--single{
  /* !important: astra-addon's form-row select2 radius rule sits at (0,7,1) */
  background:var(--field);border:1px solid var(--line);border-radius:0 !important;
}
body:not(.luxe-landing) .select2-container--default .select2-selection--single .select2-selection__rendered{color:var(--fg)}
.select2-dropdown{background:var(--field);border:1px solid var(--line);color:var(--fg)}
.select2-container--default .select2-results__option--highlighted[aria-selected]{background:var(--gold);color:var(--ink)}
.select2-container--default .select2-search--dropdown .select2-search__field{background:var(--field);border:1px solid var(--line);color:var(--fg)}

/* ---- tables (cart, order review) ---- */
.woocommerce table.shop_table{border:1px solid var(--line);border-radius:0;background:transparent}
.woocommerce table.shop_table th,
.woocommerce-js table.shop_table th,
.woocommerce-page table.shop_table th{
  font-weight:400;font-size:.82rem;letter-spacing:.18em;text-transform:uppercase;color:var(--fg-soft);
}
.woocommerce-js table.shop_table thead,
.woocommerce-page table.shop_table thead{background-color:transparent}
.woocommerce table.shop_table td, .woocommerce table.shop_table th{border-color:var(--line) !important}
.woocommerce table.shop_table td{color:var(--fg-soft);background:transparent}
.woocommerce table.shop_table .product-name a{font-size:1.05rem}
/* qty steppers */
body:not(.luxe-landing) .quantity .qty,
.woocommerce-js .quantity .qty,
.woocommerce table.shop_table .quantity .qty{background:var(--field);border:1px solid var(--line);color:var(--fg)}
body:not(.luxe-landing) .quantity .minus,
body:not(.luxe-landing) .quantity .plus,
.woocommerce-js .quantity .minus,
.woocommerce-js .quantity .plus{background:transparent;border:1px solid var(--line);color:var(--fg-soft)}
/* qty stepper buttons (js/qty-stepper.js wraps input.qty with these) */
.quantity{display:inline-flex;align-items:stretch;vertical-align:middle}
.quantity .qty{width:44px;text-align:center;-moz-appearance:textfield;box-sizing:border-box}
.quantity .qty::-webkit-inner-spin-button,.quantity .qty::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}
.quantity .minus,.quantity .plus{width:36px;cursor:pointer;font-family:var(--sans);font-size:1rem;line-height:1;padding:0;box-sizing:border-box}
.quantity .qty,.quantity .minus,.quantity .plus{height:43px}

/* ---- checkout: the ivory order sheet (0.7.5, decision closed 2026-07-30) ----
   The one surface where the customer writes. Billing form + Your Order flip
   to ivory paper on the dark page — the catalogue metaphor (you sign on
   paper), and 35+ legibility at the money moment. Every color role is
   restated below per the .light law: gold NEVER sits on ivory — --gold-ink
   is gold's voice here. Checkout went paper first; cart, product, and
   get-started followed in 0.7.6-0.7.9 (see their own sections below). */
.woocommerce-checkout h3,
.woocommerce-billing-fields>h3,
.woocommerce-additional-fields>h3,
#order_review_heading{font-family:var(--serif) !important;font-weight:300 !important;color:var(--ink)}
/* full paper ground (0.7.8 — checkout joined the all-paper flow; the sheets
   became white panels on ivory, same grammar as the cart totals box) */
body.woocommerce-checkout{background:var(--ivory);color:var(--ink)}
body.woocommerce-checkout #content h1,
body.woocommerce-checkout .entry-title{color:var(--ink)}
body.woocommerce-checkout #content > * a:not(.pulse-btn){color:var(--ink)}
body.woocommerce-checkout #content > * a:not(.pulse-btn):hover{color:var(--gold-ink)}
body.woocommerce-checkout .woocommerce-form-coupon-toggle .woocommerce-info,
body.woocommerce-checkout .woocommerce-message,
body.woocommerce-checkout .woocommerce-info,
body.woocommerce-checkout .woocommerce-error{
  background-color:#fff;border:1px solid var(--hairline-ink);border-top:2px solid var(--gold);color:var(--ink-soft);
}
body.woocommerce-checkout .woocommerce-message::before,
body.woocommerce-checkout .woocommerce-info::before{color:var(--gold-ink)}
body.woocommerce-checkout .blockUI.blockOverlay{background:var(--ivory) !important}
/* checkout → payment hand-off veil (drives off js/checkout-progress.js).
   "Purchase" fires an AJAX materialize (order create → tax freeze → SO PDF →
   NetSuite push) and only then navigates to the signing page. On staging that
   gap runs several seconds with no feedback but a button caption at the bottom
   of the order column — which is the "site looks crashed" Logan hit
   (2026-08-06). Paper ground so the veil reads as the same sheet, not a modal.
   Nothing here intercepts the click: the veil is display-only. */
.pulse-veil{
  position:fixed;inset:0;z-index:9999;display:none;
  flex-direction:column;align-items:center;justify-content:center;gap:1.2rem;
  background:rgba(241,236,226,.94); /* --ivory at 94% — the page shows through */
}
body.pulse-veil-on .pulse-veil{display:flex}
.pulse-veil-line{
  margin:0;font-family:var(--sans);font-size:.8rem;font-weight:400;
  letter-spacing:.22em;text-transform:uppercase;color:var(--ink-soft);
}
/* ---- the one loading indicator, everywhere ----
   .pulse-loading-coin is an empty box; js/loading-coin.js drops Logan's
   <logo-coin-flip> into it (and into WooCommerce's blockUI overlays, which
   the theme cannot print markup inside). The box only centres it — the coin
   draws in shadow DOM and takes its diameter from its own `size` attribute,
   so sizing lives with the markup, not here. It replaced the 34px rotating
   square the veils used to show, which read as a tilted diamond (RC 2026-08-06).
   Reduced motion is handled by the component's `paused` attribute, not CSS. */
.pulse-loading-coin{display:flex;align-items:center;justify-content:center;pointer-events:none}
.blockUI.blockOverlay > .pulse-loading-coin{position:absolute;inset:0}
/* checkout stepper: token base (~1541) already speaks paper here; the old
   body-scoped counters out-specified .is-pending and erased pending states
   (RC8) — deleted 0.10.0, only the line variants keep surface value */
body.woocommerce-checkout .pulse-stepper-line{background:var(--hairline-ink)}
body.woocommerce-checkout .pulse-stepper-line.is-done{background:var(--gold-ink)}
/* two-column checkout (was astra-addon's checkout-modern-layout-type=
   two-column-checkout — an astra-addon presentation option with no WC-core
   equivalent, since WC's own col2-set only splits billing/shipping *inside*
   #customer_details). #customer_details, #order_review_heading and
   #order_review are the three siblings of <form class="checkout"> worth
   grid-placing directly (form-checkout.php). Note: WC's checkout JS
   relocates .woocommerce-additional-fields (order notes/vocation/account
   type) INSIDE #customer_details .col-2 at runtime — server-rendered HTML
   has it as a form-level sibling, but live DOM (checked via
   getComputedStyle/parentElement, not just view-source) nests it under
   .col-2, so it rides along with the billing/shipping split below and
   needs no grid placement of its own. */
@media (min-width:800px){
  .woocommerce-checkout form.checkout{
    display:grid;
    grid-template-columns:1fr minmax(300px,380px);
    column-gap:2.5rem;
    align-items:start;
  }
  .woocommerce-checkout form.checkout #customer_details{grid-column:1;grid-row:1 / span 3}
  .woocommerce-checkout form.checkout #order_review_heading{grid-column:2;grid-row:1}
  .woocommerce-checkout form.checkout #order_review{grid-column:2;grid-row:2}
  /* the desktop-only overlap (Logan 2026-08-05, "Your order laying on top"):
     the sheets are content-box, so #customer_details' 2rem padding pushed its
     rendered box 66px past its 1fr track, under the order column. border-box
     makes the track the whole truth. */
  /* and de-cramp: the global 1220px .ast-container leaves 1060px for a
     three-column page — billing fields were ~130px wide on any desktop.
     Checkout alone gets a wider sheet. :not() restated to out-specify the
     global body:not(.luxe-landing) .ast-container rule (source order loses). */
  body.woocommerce-checkout:not(.luxe-landing) .ast-container{max-width:1440px}
  /* "Ship to a different address?" lives under Billing details (Logan
     2026-08-05), its fields sliding open below it. WC's markup nests it in
     the right float column — dissolve both float cols (display:contents)
     and grid-place the three field blocks directly: billing left,
     shipping under it, Additional Information right. WC core's own
     slide-toggle on .shipping_address keeps working untouched. */
  /* align-self:stretch fights the form's own align-items:start for THIS item
     only: the order column is legitimately taller than billing (a 2-item
     table with coupon + tax + total rows), so the two sheets used to end
     ~180px apart and the taller one sat alone against the footer (Logan
     2026-08-14). Stretching billing to the spanned rows lands both bottom
     edges on the same line. #order_review keeps start, so the reverse case
     (shipping fields expanded → billing taller) is unaffected.
     align-content:start: the stretch's spare height used to be shared out
     across the auto rows, so a tall order column (5 items + coupons) grew
     row 1 and dropped "Ship to a different address?" far below the billing
     fields (Logan 2026-09-23). Rows now hug their content; the spare height
     collects at the bottom of the sheet. */
  .woocommerce-checkout form.checkout #customer_details{
    display:grid;grid-template-columns:1fr 1fr;column-gap:2rem;align-items:start;
    align-self:stretch;align-content:start;
  }
  .woocommerce-checkout form.checkout #customer_details .col-1,
  .woocommerce-checkout form.checkout #customer_details .col-2{display:contents}
  .woocommerce-checkout form.checkout #customer_details .woocommerce-billing-fields{grid-column:1;grid-row:1}
  .woocommerce-checkout form.checkout #customer_details .woocommerce-shipping-fields{grid-column:1;grid-row:2}
  .woocommerce-checkout form.checkout #customer_details .woocommerce-additional-fields{grid-column:2;grid-row:1 / span 2}
  /* hidden attribution inputs would become a stray auto-placed grid item
     once .col-1 dissolves — display:none form fields still submit */
  .woocommerce-checkout form.checkout #customer_details wc-order-attribution-inputs{display:none}
}

/* the two sheets — white panels on the ivory ground. border-box at ALL
   widths: WC core's .col2-set{width:100%} + this padding overflowed the
   sheet 18px past the viewport on mobile (Logan 2026-08-05, "no padding on
   the right side") — and on desktop the same content-box math shoved it
   under the order column. */
.woocommerce-checkout form.checkout #customer_details,
body.woocommerce-checkout #order_review_heading,
body:not(.luxe-landing) #order_review{
  box-sizing:border-box;
}
.woocommerce-checkout form.checkout #customer_details,
body:not(.luxe-landing) #order_review{
  background:#fff;border:1px solid var(--hairline-ink);border-radius:0;padding:2.2rem 2rem;
}
/* on-sheet headings go ink. Astra boxes #order_review_heading with a 2px frame
   via a :not(#id) selector (unbeatable specificity — the !importants below are
   for that fight only): fuse the heading INTO the sheet so "Your order" sits on
   paper exactly like "Billing details". */
.woocommerce-checkout #customer_details h3{color:var(--ink)}
body.woocommerce-checkout #order_review_heading{
  background:#fff;color:var(--ink) !important;
  border:1px solid var(--hairline-ink) !important;border-bottom:none !important;
  margin:0 !important;padding:2.2rem 2rem 0 !important;
}
body.woocommerce-checkout #order_review{border-top:none !important}
/* Paystand containment backstop (0.12.4). The SDK mounts its iframe into
   #ps_container_id and only ps-width is configurable — there is no height
   API (WCGatewayPaystand::validate_width_field is the whole dimension
   contract). Height rides a postMessage resize handshake; when that lags or
   fails the iframe stays at its SDK default, and #order_review's own block
   height honestly grows to fit it — the panel runs past the footer with a
   dead white stretch below the last real row. One bare-#order_review-scoped
   rule covers both surfaces, since payment_fields() (/checkout/) and
   receipt_page() (/checkout/order-pay/) render the same container. Cap sits
   well above a real card+bank form (~600px), so a correct render never
   scrolls — only the failure mode gets bitten. Fixing the handshake itself
   is a Paystand-side investigation, not a theme change.
   The CONTAINER is capped, never the iframe: an oversized iframe has to stay
   oversized so this div's own scrollbar can reach its bottom. Capping the
   iframe too would leave nothing for overflow:auto to scroll and hand the
   whole reachability job to the framed document — which payment SDKs
   routinely lock (scrolling="no", body overflow:hidden), stranding the Pay
   button. Div-scroll works no matter what the SDK does inside. */
#order_review #ps_container_id{
  max-height:720px;overflow:auto;
}
/* field labels ride INSIDE the fields as placeholders (functions.php copies
   label → placeholder; Logan 2026-08-05, pre-fork voice) — hide the visible
   label but keep it for screen readers. Direct-child > only: checkbox labels
   (ship-to-different-address etc.) wrap their input and must stay visible. */
.woocommerce-checkout #customer_details .form-row > label{
  position:absolute;width:1px;height:1px;margin:-1px;padding:0;
  overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;
}
/* order-review table ladder (Logan 2026-08-05: "× 2 massive, subtotal smaller
   than product text") — same two voices as the cart drawer: names serif,
   quantity a quiet sans eyebrow, amounts serif with only the Total stepping
   up. WC's strong.product-quantity was Jost 700 = faux-bold (Jost stops at
   500) at full body size. */
#order_review .shop_table td.product-name{font-size:1.05rem;font-weight:400}
#order_review .shop_table .product-quantity{
  font-family:var(--sans);font-size:.85rem;font-weight:400;
  color:var(--ink-soft);letter-spacing:.06em;
}
#order_review .shop_table th{font-weight:400}
#order_review .shop_table .woocommerce-Price-amount{font-size:1.05rem;font-weight:400}
/* totals rows step up from the 13px column-header eyebrow — Logan 2026-08-05
   round 2: "sub total still small and hard to see" */
#order_review .shop_table tfoot th{font-size:.95rem;letter-spacing:.14em}
#order_review .shop_table tfoot .woocommerce-Price-amount{font-size:1.05rem}
#order_review .shop_table tr.order-total .woocommerce-Price-amount{font-size:1.25rem}
/* labels, body text, links on paper */
.woocommerce-checkout #customer_details .form-row label,
.woocommerce-checkout #order_review .payment_box,
.woocommerce-checkout #order_review .woocommerce-privacy-policy-text,
.woocommerce-checkout #order_review .woocommerce-privacy-policy-text p{color:var(--ink-soft)}
.woocommerce-checkout #order_review a,
.woocommerce-checkout #customer_details a{color:var(--ink)}
.woocommerce-checkout #order_review a:hover,
.woocommerce-checkout #customer_details a:hover{color:var(--gold-ink)}
/* fields: white on paper, ink hairlines */
/* ONE field spec for the whole sheet (0.8.8 — Logan: select2 country/state
   rendered 47px/20px next to 34px/13px inputs, and the plugin's vocation/
   account selects ship appearance:none + 40px arrow gutter expecting an
   arrow image the white-background rule above wiped). Everything is a
   44px box, 1rem type: inputs, textarea, native selects (theme chevron),
   and select2 pinned to match. */
.woocommerce-checkout #customer_details .form-row input.input-text,
.woocommerce-checkout #customer_details .form-row textarea,
.woocommerce-checkout #customer_details .form-row select,
.woocommerce-checkout #customer_details #order_comments{
  background:#fff;border:1px solid var(--hairline-ink);color:var(--ink);
  font-size:1rem;line-height:1.4;padding:.6em .9em;width:100%;box-sizing:border-box;
}
.woocommerce-checkout #customer_details #order_comments{min-height:7em}
.woocommerce-checkout #customer_details .form-row select{
  appearance:none;-webkit-appearance:none;
  background:#fff url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='11' height='7' viewBox='0 0 11 7'><path d='M1 1l4.5 4.5L10 1' fill='none' stroke='%230f0f11' stroke-opacity='.62' stroke-width='1.2'/></svg>") no-repeat right .9em center;
  padding-right:2.6em;
}
.woocommerce-checkout #customer_details input::placeholder,
.woocommerce-checkout #customer_details textarea::placeholder{color:var(--ink-soft)}
.woocommerce-checkout #customer_details input[type=checkbox]{
  background:#fff;border:1px solid var(--hairline-ink);accent-color:var(--gold-ink);
}
.woocommerce-checkout #customer_details input[type=checkbox]:checked{background:var(--gold);border-color:var(--gold)}
/* select2 on paper (dropdown attaches to body — scope by page) */
.woocommerce-checkout #customer_details .select2-container--default .select2-selection--single{
  border:1px solid var(--hairline-ink);border-radius:0 !important;
  height:auto;
  /* same chevron as the native selects — select2's own arrow is a border-
     triangle <b> that arrives border:0 here (dead), so it's hidden below */
  background:#fff url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='11' height='7' viewBox='0 0 11 7'><path d='M1 1l4.5 4.5L10 1' fill='none' stroke='%230f0f11' stroke-opacity='.62' stroke-width='1.2'/></svg>") no-repeat right .9em center;
}
.woocommerce-checkout #customer_details .select2-selection__arrow{display:none}
.woocommerce-checkout #customer_details .select2-selection__rendered{
  color:var(--ink) !important;
  font-size:1rem;line-height:1.4 !important;padding:.6em 2.6em .6em .9em !important;
}
.woocommerce-checkout .select2-dropdown{background:#fff;border:1px solid var(--hairline-ink);color:var(--ink)}
.woocommerce-checkout .select2-container--default .select2-search--dropdown .select2-search__field{
  background:#fff;border:1px solid var(--hairline-ink);color:var(--ink);
}
/* mobile checkout (Logan 2026-08-05, dev-tools pass):
   - Save Estimate / Purchase were 140px tall: the plugin's .pulse-btn carries
     flex:1 1 140px (basis-as-width for the desktop ROW); when its container
     goes flex-direction:column on small screens the basis becomes HEIGHT.
   - totals rows read small on a phone — one step up from the desktop spec. */
@media (max-width:800px){
  .woocommerce-checkout .pulse-checkout-buttons .pulse-btn{flex-basis:auto}
  #order_review .shop_table tfoot th{font-size:1rem}
  #order_review .shop_table tfoot .woocommerce-Price-amount{font-size:1.15rem}
}

/* order table: ink type, ink hairlines, gold rule over the total.
   !important: line 488's .woocommerce table.shop_table td/th{border-color:
   var(--hairline) !important} is dark-era and wins without it — same bug
   as the cart table (which already carries this !important) — and
   --hairline is the ivory-tinted color for dark ink grounds, functionally
   invisible on white. */
.woocommerce-checkout #order_review table.shop_table,
.woocommerce-checkout #order_review table.shop_table th,
.woocommerce-checkout #order_review table.shop_table td{
  color:var(--ink);border-color:var(--hairline-ink) !important;background:transparent;
}
.woocommerce-checkout #order_review table.shop_table tr.order-total th,
.woocommerce-checkout #order_review table.shop_table tr.order-total td{border-top:1px solid var(--gold)}
/* payment area */
.woocommerce-checkout #payment{background:transparent;border:none}
.woocommerce-checkout #payment .payment_box{border-radius:0;background:transparent}
/* AJAX overlay inside the sheets stays paper, not ink */
.woocommerce-checkout #order_review .blockUI.blockOverlay,
.woocommerce-checkout #customer_details .blockUI.blockOverlay{background:var(--ivory) !important}
/* plugin's inline navy links inside the sheets (staging-era markup) */
.woocommerce-checkout #order_review a[style*="#16435F"],
.woocommerce-checkout #customer_details a[style*="#16435F"]{color:var(--ink-soft) !important}
.woocommerce-checkout #order_review a[style*="#16435F"]:hover{color:var(--gold-ink) !important}
/* form errors on paper: the on-ink salmon fails here — deep brick instead */
.woocommerce-checkout #order_review .pulse-form-msg,
.woocommerce-checkout #order_review #pulse-form-msg{color:var(--error-ink) !important}
/* action buttons on paper — both eras (ids = old + de-skinned plugins) */
.woocommerce-checkout button#pulse-submit-purchase{border-color:var(--gold)}
.woocommerce-checkout button#pulse-submit-purchase:hover{background:transparent;color:var(--gold-ink);border-color:var(--gold-ink)}
.woocommerce-checkout button#pulse-save-quote{color:var(--ink);border:1px solid var(--hairline-ink)}
.woocommerce-checkout button#pulse-save-quote:hover{border-color:var(--gold-ink);color:var(--gold-ink)}
.woocommerce-checkout #order_review .pulse-btn{color:var(--ink);border-color:var(--hairline-ink)}
.woocommerce-checkout #order_review .pulse-btn:hover{background:var(--gold);border-color:var(--gold);color:var(--ink)}
.woocommerce-checkout #order_review .pulse-btn--primary{background:var(--gold);border-color:var(--gold);color:var(--ink)}
.woocommerce-checkout #order_review .pulse-btn--primary:hover{background:transparent;color:var(--gold-ink);border-color:var(--gold-ink)}
@media (max-width:540px){
  .woocommerce-checkout form.checkout #customer_details,
  body:not(.luxe-landing) #order_review{padding:1.6rem 1.2rem}
  body.woocommerce-checkout #order_review_heading{padding:1.6rem 1.2rem 0 !important}
}

/* ---- the builder goes paper (0.7.5, Logan 2026-07-30) ----
   The entire /build + /sales?build=1 surface joins the ivory writing flow:
   the worktable where the order is composed. Scoped via :has() on the two
   builder wrappers (the virtual routes carry no unique body class). Site
   header/footer stay ink — dark house, paper worktable. Same .light law:
   --gold-ink is gold's only voice on paper. */
body:has(.pulse-self-service-builder),
body:has(.pulse-affiliate-builder){background:var(--ivory);color:var(--ink)}
body:has(.pulse-self-service-builder) .site-header,
body:has(.pulse-affiliate-builder) .site-header,
body:has(.pulse-self-service-builder) .site-footer,
body:has(.pulse-affiliate-builder) .site-footer{background:var(--ink)}
body:has(.pulse-self-service-builder) #content a,
body:has(.pulse-affiliate-builder) #content a{color:var(--ink)}
body:has(.pulse-self-service-builder) #content a:hover,
body:has(.pulse-affiliate-builder) #content a:hover{color:var(--gold-ink)}
body:has(.pulse-self-service-builder) #content h1,
body:has(.pulse-self-service-builder) #content h2,
body:has(.pulse-self-service-builder) #content h3,
body:has(.pulse-affiliate-builder) #content h1,
body:has(.pulse-affiliate-builder) #content h2,
body:has(.pulse-affiliate-builder) #content h3{color:var(--ink)}
/* hero chooser cards */
body:has(.pulse-self-service-builder) .pulse-hero-card,
body:has(.pulse-affiliate-builder) .pulse-hero-card{border-color:var(--hairline-ink);background:transparent}
body:has(.pulse-self-service-builder) .pulse-hero-card h2,
body:has(.pulse-affiliate-builder) .pulse-hero-card h2{color:var(--ink)}
body:has(.pulse-self-service-builder) .pulse-hero-card p,
body:has(.pulse-affiliate-builder) .pulse-hero-card p{color:var(--ink-soft)}
/* sticky step chrome */
body:has(.pulse-self-service-builder) .pulse-sticky-header,
body:has(.pulse-affiliate-builder) .pulse-sticky-header,
body:has(.pulse-self-service-builder) .pulse-sticky-footer,
body:has(.pulse-affiliate-builder) .pulse-sticky-footer{background:var(--ivory);border-color:var(--hairline-ink)}
/* Step heading scrolls with the page, not sticky (decision 2026-08-03) —
   overrides the plugin's position:sticky/top:0/z-index:100 (shop-builder.css:33). */
body:has(.pulse-self-service-builder) .pulse-sticky-header,
body:has(.pulse-affiliate-builder) .pulse-sticky-header{position:static}
body:has(.pulse-self-service-builder) .pulse-section-title,
body:has(.pulse-self-service-builder) .pulse-step-title,
body:has(.pulse-affiliate-builder) .pulse-section-title,
body:has(.pulse-affiliate-builder) .pulse-step-title{color:var(--ink)}
body:has(.pulse-self-service-builder) .pulse-step-subtitle,
body:has(.pulse-self-service-builder) .pulse-section-subtitle,
body:has(.pulse-affiliate-builder) .pulse-step-subtitle,
body:has(.pulse-affiliate-builder) .pulse-section-subtitle{color:var(--ink-soft)}
body:has(.pulse-self-service-builder) .pulse-step-number,
body:has(.pulse-affiliate-builder) .pulse-step-number{
  color:var(--gold-ink);font-size:1.9rem;font-family:var(--serif);font-style:italic;
  background:transparent !important;border:none !important;width:auto !important;height:auto !important;line-height:1 !important;
}
body:has(.pulse-self-service-builder) .pulse-tab,
body:has(.pulse-affiliate-builder) .pulse-tab{color:var(--ink-soft);border-color:var(--hairline-ink);background:transparent}
body:has(.pulse-self-service-builder) .pulse-tab:hover,
body:has(.pulse-affiliate-builder) .pulse-tab:hover{border-color:var(--gold-ink);color:var(--ink)}
body:has(.pulse-self-service-builder) .pulse-tab.active,
body:has(.pulse-affiliate-builder) .pulse-tab.active{border-color:var(--gold-ink);color:var(--gold-ink)}
/* nav + cart summary in the sticky footer */
body:has(.pulse-self-service-builder) .pulse-nav-btn.secondary,
body:has(.pulse-affiliate-builder) .pulse-nav-btn.secondary{border-color:var(--hairline-ink);color:var(--ink-soft)}
body:has(.pulse-self-service-builder) .pulse-nav-btn:hover,
body:has(.pulse-affiliate-builder) .pulse-nav-btn:hover{background:var(--gold);border-color:var(--gold);color:var(--ink)}
body:has(.pulse-self-service-builder) .pulse-cart-summary,
body:has(.pulse-self-service-builder) .pulse-product-cart-summary,
body:has(.pulse-self-service-builder) .pulse-product-cart-summary *,
body:has(.pulse-affiliate-builder) .pulse-cart-summary,
body:has(.pulse-affiliate-builder) .pulse-product-cart-summary,
body:has(.pulse-affiliate-builder) .pulse-product-cart-summary *{color:var(--ink-soft) !important}
/* product loop on paper — white photo tiles keep their gold-soft frames */
body:has(.pulse-self-service-builder) .woocommerce ul.products li.product .woocommerce-loop-product__title,
body:has(.pulse-affiliate-builder) .woocommerce ul.products li.product .woocommerce-loop-product__title{color:var(--ink)}
body:has(.pulse-self-service-builder) .woocommerce ul.products li.product .price,
body:has(.pulse-affiliate-builder) .woocommerce ul.products li.product .price{color:var(--ink-soft)}
body:has(.pulse-self-service-builder) .pulse-products ul.products li.product .price,
body:has(.pulse-affiliate-builder) .pulse-products ul.products li.product .price{color:var(--ink)}
body:has(.pulse-self-service-builder) ul.products li.product a.button,
body:has(.pulse-self-service-builder) ul.products li.product a.add_to_cart_button,
body:has(.pulse-affiliate-builder) ul.products li.product a.button,
body:has(.pulse-affiliate-builder) ul.products li.product a.add_to_cart_button{
  border-color:var(--hairline-ink);color:var(--ink);background:transparent;
}
body:has(.pulse-self-service-builder) ul.products li.product a.button:hover,
body:has(.pulse-self-service-builder) ul.products li.product a.add_to_cart_button:hover,
body:has(.pulse-affiliate-builder) ul.products li.product a.button:hover,
body:has(.pulse-affiliate-builder) ul.products li.product a.add_to_cart_button:hover{
  background:var(--gold);border-color:var(--gold);color:var(--ink);
}
/* the dark-era builder loop-button rule carries !important + the grouped/variable
   product classes (the machines ARE grouped products) — counter in kind */
body:has(.pulse-self-service-builder) .pulse-products ul.products li.product a.button,
body:has(.pulse-self-service-builder) .pulse-products ul.products li.product a.add_to_cart_button,
body:has(.pulse-self-service-builder) .pulse-products ul.products li.product a.product_type_variable,
body:has(.pulse-self-service-builder) .pulse-products ul.products li.product a.product_type_grouped,
body:has(.pulse-affiliate-builder) .pulse-products ul.products li.product a.button,
body:has(.pulse-affiliate-builder) .pulse-products ul.products li.product a.add_to_cart_button,
body:has(.pulse-affiliate-builder) .pulse-products ul.products li.product a.product_type_variable,
body:has(.pulse-affiliate-builder) .pulse-products ul.products li.product a.product_type_grouped{
  color:var(--ink) !important;border-color:var(--hairline-ink) !important;
}
body:has(.pulse-self-service-builder) .pulse-products ul.products li.product a.button:hover,
body:has(.pulse-self-service-builder) .pulse-products ul.products li.product a.add_to_cart_button:hover,
body:has(.pulse-self-service-builder) .pulse-products ul.products li.product a.product_type_variable:hover,
body:has(.pulse-self-service-builder) .pulse-products ul.products li.product a.product_type_grouped:hover,
body:has(.pulse-affiliate-builder) .pulse-products ul.products li.product a.button:hover,
body:has(.pulse-affiliate-builder) .pulse-products ul.products li.product a.add_to_cart_button:hover,
body:has(.pulse-affiliate-builder) .pulse-products ul.products li.product a.product_type_variable:hover,
body:has(.pulse-affiliate-builder) .pulse-products ul.products li.product a.product_type_grouped:hover{
  background:var(--gold) !important;color:var(--ink) !important;border-color:var(--gold) !important;
}
/* nav buttons: base + primary get ink voices on paper (secondary handled above) */
body:has(.pulse-self-service-builder) .pulse-nav-btn.primary,
body:has(.pulse-self-service-builder) .pulse-nav-btn.checkout,
body:has(.pulse-affiliate-builder) .pulse-nav-btn.primary,
body:has(.pulse-affiliate-builder) .pulse-nav-btn.checkout{
  background:var(--gold);border-color:var(--gold);color:var(--ink);
}
body:has(.pulse-self-service-builder) .pulse-nav-btn.primary:hover,
body:has(.pulse-self-service-builder) .pulse-nav-btn.checkout:hover,
body:has(.pulse-affiliate-builder) .pulse-nav-btn.primary:hover,
body:has(.pulse-affiliate-builder) .pulse-nav-btn.checkout:hover{
  background:transparent;border-color:var(--gold-ink);color:var(--gold-ink);
}
/* panels, banners, modal, bundle chrome */
body:has(.pulse-self-service-builder) .pulse-back-to-builder,
body:has(.pulse-affiliate-builder) .pulse-back-to-builder{background:var(--ivory);border-color:var(--hairline-ink)}
body:has(.pulse-self-service-builder) .pulse-back-to-builder-hint,
body:has(.pulse-affiliate-builder) .pulse-back-to-builder-hint{color:var(--ink-soft)}
body:has(.pulse-self-service-builder) .pulse-package-banner,
body:has(.pulse-self-service-builder) .pulse-bundle-footer,
body:has(.pulse-affiliate-builder) .pulse-package-banner,
body:has(.pulse-affiliate-builder) .pulse-bundle-footer{background:#fff;border-color:var(--hairline-ink)}
body:has(.pulse-self-service-builder) .pulse-package-banner-notice,
body:has(.pulse-affiliate-builder) .pulse-package-banner-notice{color:var(--ink-soft)}
body:has(.pulse-self-service-builder) .pulse-bundle-card,
body:has(.pulse-self-service-builder) .pulse-bundle-heading,
body:has(.pulse-self-service-builder) .pulse-bundle-selector select,
body:has(.pulse-affiliate-builder) .pulse-bundle-card,
body:has(.pulse-affiliate-builder) .pulse-bundle-heading,
body:has(.pulse-affiliate-builder) .pulse-bundle-selector select{border-color:var(--hairline-ink)}
/* "Already have a machine?" warn modal (shop-builder.js ~line 90, inline
   markup) — paper panel. This tied on specificity with the dark-era global
   version of the same signature (deleted below, was `body:not(.luxe-landing)
   div[style*="max-width:500px"]...`) and lost on source order, which is why
   it was rendering dark; deleting that duplicate instead of layering a
   third override on top. Dim scrim behind the panel (#pulse-machine-warning,
   inline rgba(0,0,0,.5)) stays dark on purpose — it's a backdrop, not
   content (Logan, 2026-08-04). */
body:has(.pulse-self-service-builder) div[style*="max-width:500px"][style*="box-shadow"],
body:has(.pulse-affiliate-builder) div[style*="max-width:500px"][style*="box-shadow"]{
  background:#fff !important;border:1px solid var(--hairline-ink);
}
body:has(.pulse-self-service-builder) div[style*="max-width:500px"] h3,
body:has(.pulse-affiliate-builder) div[style*="max-width:500px"] h3{color:var(--ink)}
body:has(.pulse-self-service-builder) div[style*="max-width:500px"] p,
body:has(.pulse-affiliate-builder) div[style*="max-width:500px"] p{color:var(--ink-soft) !important}
/* secondary — "Choose a Machine" */
body:has(.pulse-self-service-builder) button#pulse-warn-back,
body:has(.pulse-affiliate-builder) button#pulse-warn-back{
  border-color:var(--hairline-ink) !important;color:var(--ink-soft) !important;background:transparent !important;
  font-family:var(--sans);font-weight:400 !important;letter-spacing:.18em;text-transform:uppercase;font-size:.85rem !important;
}
body:has(.pulse-self-service-builder) button#pulse-warn-back:hover,
body:has(.pulse-affiliate-builder) button#pulse-warn-back:hover{
  border-color:var(--gold-ink) !important;color:var(--gold-ink) !important;
}
/* primary — "Continue Without", the money action, same gold-fill recipe
   as Proceed to Checkout / pulse-btn--primary */
body:has(.pulse-self-service-builder) button#pulse-warn-proceed,
body:has(.pulse-affiliate-builder) button#pulse-warn-proceed{
  background:var(--gold) !important;border:1px solid var(--gold) !important;color:var(--ink) !important;
  font-family:var(--sans);font-weight:400 !important;letter-spacing:.18em;text-transform:uppercase;font-size:.85rem !important;
}
body:has(.pulse-self-service-builder) button#pulse-warn-proceed:hover,
body:has(.pulse-affiliate-builder) button#pulse-warn-proceed:hover{
  background:transparent !important;border-color:var(--gold-ink) !important;color:var(--gold-ink) !important;
}
/* Woo notices + AJAX overlay on paper */
body:has(.pulse-self-service-builder) .woocommerce-message,
body:has(.pulse-self-service-builder) .woocommerce-info,
body:has(.pulse-affiliate-builder) .woocommerce-message,
body:has(.pulse-affiliate-builder) .woocommerce-info{
  background-color:#fff;border:1px solid var(--hairline-ink);border-top:2px solid var(--gold);color:var(--ink-soft);
}
body:has(.pulse-self-service-builder) .woocommerce-message::before,
body:has(.pulse-self-service-builder) .woocommerce-info::before,
body:has(.pulse-affiliate-builder) .woocommerce-message::before,
body:has(.pulse-affiliate-builder) .woocommerce-info::before{color:var(--gold-ink)}
body:has(.pulse-self-service-builder) .blockUI.blockOverlay,
body:has(.pulse-affiliate-builder) .blockUI.blockOverlay{background:var(--ivory) !important}
/* plugin-era inline navy + gold-pinned links on paper */
body:has(.pulse-self-service-builder) a[style*="#16435F"],
body:has(.pulse-affiliate-builder) a[style*="#16435F"]{color:var(--ink-soft) !important}
body:has(.pulse-self-service-builder) a[style*="#16435F"]:hover,
body:has(.pulse-affiliate-builder) a[style*="#16435F"]:hover{color:var(--gold-ink) !important}
/* privacy note = quiet subtext, moved BELOW the action buttons (source order
   has it above; flex-order swap avoids touching plugin markup) */
.woocommerce-checkout #payment .place-order{
  display:flex;flex-direction:column;border:none;padding:0 1.5rem 1.5rem;
}
/* plugin lays the two buttons out flex-wrap side-by-side — leave its layout,
   just calm the type inside the narrow order column */
.woocommerce-checkout #payment .pulse-checkout-buttons button{padding:.95rem 1rem !important}
.woocommerce-checkout #payment .place-order .pulse-checkout-buttons{order:1}
.woocommerce-checkout #payment .place-order .pulse-form-msg{order:2}
.woocommerce-checkout #payment .place-order .woocommerce-terms-and-conditions-wrapper{
  order:3;margin:1.4rem 0 0;
}
/* dead height in the order sheet (Logan 2026-08-14, "it's just too long").
   Measured, not guessed: WC's [Remove] coupon link inherits the tfoot price
   voice — Jost 20px/700 — and wrapped a full 30px line inside a 148px cell,
   30px x 2 coupons; and the affiliate button stacked the plugin's own
   20px margins (class-affiliate.php prints them inline, so this out-specifies
   rather than edits a plugin we don't own) on top of .place-order's padding.
   Both ids restated so the padding beats whatever was winning over the
   .place-order rule above — computed top padding measured 20px, not the 0
   that rule asks for. 964px -> 883px. */
#order_review .woocommerce-remove-coupon{
  display:block;font-family:var(--sans);font-size:.72rem;font-weight:400;
  letter-spacing:.1em;line-height:1.5;color:var(--ink-soft);
}
#order_review #payment .place-order{padding:0 1.5rem 1.5rem}
#order_review #payment .place-order .pulse-affiliate-submit{margin:0}
/* and the sheets sat flush on the black footer — measured gap was 0px, so
   any late growth (a Paystand iframe, an error notice) read as overlap. */
.woocommerce-checkout form.checkout{margin-bottom:3.5rem}
/* native #place_order — normally hidden on /checkout/ (the pulse workflow
   substitutes its own #pulse-submit-purchase gold button there), so it never
   got a paper coat. /checkout/order-pay/ is the one paper-classed page where
   WooCommerce renders it for real (gateway-labelled, e.g. "Pay With Paystand")
   and it fell back to the dark-ground default: ivory text on transparent —
   unreadable on paper. Same money-action gold fill as every other CTA. */
.woocommerce-checkout button#place_order{
  background:var(--gold);color:var(--ink);border-color:var(--gold);
}
.woocommerce-checkout button#place_order:hover{
  background:transparent;color:var(--gold-ink);border-color:var(--gold-ink);
}
.woocommerce-privacy-policy-text, .woocommerce-privacy-policy-text p{
  color:var(--fg-soft);font-size:.85rem;line-height:1.6;
}

/* checkout-workflow Save Quote / Submit (plugin prints #id rules inline in body;
   button#id out-specifies without !important). Submit = the money button, gold. */
button#pulse-submit-purchase{
  background:var(--gold);color:var(--ink);border:1px solid var(--gold);border-radius:0;
  font-family:var(--sans);font-weight:400;font-size:.85rem;letter-spacing:.18em;text-transform:uppercase;
  transition:background .45s ease, color .45s ease;
}
button#pulse-submit-purchase:hover{background:transparent;color:var(--gold-role)}
button#pulse-save-quote{
  background:transparent;color:var(--fg);border:1px solid var(--line);border-radius:0;
  font-family:var(--sans);font-weight:400;font-size:.85rem;letter-spacing:.18em;text-transform:uppercase;
  transition:background .45s ease, color .45s ease;
}
button#pulse-save-quote:hover{border-color:var(--gold);color:var(--gold-role)}

/* Astra form-row specificity beats element selectors for some fields */
.woocommerce form .form-row textarea,
.woocommerce form .form-row input.input-text,
.woocommerce form .form-row select,
body:not(.luxe-landing) #order_comments{
  background:var(--field);border:1px solid var(--line);border-radius:0;color:var(--fg);
}
/* plugin back-link is navy — unreadable on ink */
body .pulse-back-link{color:var(--fg-soft)}
body .pulse-back-link:hover{color:var(--gold-role)}
/* checkout-workflow prints inline navy links (style="color:#16435F") — catch them all */
body:not(.luxe-landing) a[style*="#16435F"]{color:var(--fg-soft) !important}
body:not(.luxe-landing) a[style*="#16435F"]:hover{color:var(--gold-role) !important}
/* Woo blockUI paints a WHITE overlay (inline style) during AJAX updates — ink it */
.blockUI.blockOverlay{background:var(--ground) !important}
/* ...and paints its own spinner into ::before (loader.svg + a CSS spin). Kill it;
   js/loading-coin.js appends the coin instead. !important because WC scopes its
   rule as `.woocommerce .blockUI.blockOverlay::before` — one class more specific
   than anything unscoped, and the overlay lands under several different
   ancestors (cart form, order review, mini-cart, builder panels). */
.blockUI.blockOverlay::before{display:none !important}

/* ---- 2026-08-04: the /sales estimate-received screen goes paper ----
   Same pattern as the builder (:has() scope — route has no body class).
   Header/footer stay ink like every other paper surface. */
body:has(.pulse-affiliate-confirm){background:var(--ivory);color:var(--ink)}
body:has(.pulse-affiliate-confirm) .site-header,
body:has(.pulse-affiliate-confirm) .site-footer{background:var(--ink)}
body:has(.pulse-affiliate-confirm) #content a{color:var(--ink)}
body:has(.pulse-affiliate-confirm) #content a:hover{color:var(--gold-ink)}
body:has(.pulse-affiliate-confirm) #content h1{color:var(--ink)}
body:has(.pulse-affiliate-confirm) .pulse-affiliate-confirm-intro{color:var(--ink-soft)}
body:has(.pulse-affiliate-confirm) .pulse-aff-copy{background:#fff;border-color:var(--hairline-ink)}
body:has(.pulse-affiliate-confirm) .pulse-aff-copy-label{color:var(--ink)}
body:has(.pulse-affiliate-confirm) .pulse-aff-copy-option{background:#fff;border-color:var(--hairline-ink);color:var(--ink-soft)}
body:has(.pulse-affiliate-confirm) .pulse-aff-copy input{background:#fff;border-color:var(--hairline-ink);color:var(--ink)}
body:has(.pulse-affiliate-confirm) #content .pulse-aff-copy-skip{color:var(--ink-soft)}
body:has(.pulse-affiliate-confirm) #content .pulse-aff-copy-skip:hover{color:var(--gold-ink)}
body:has(.pulse-affiliate-confirm) .pulse-aff-copy-msg.is-error{color:var(--error-ink)}
body:has(.pulse-affiliate-confirm) .pulse-aff-copy-msg.is-ok{color:var(--gold-ink)}
body:has(.pulse-affiliate-confirm) .pulse-aff-success-msg{color:var(--gold-ink)}

/* ---- single product ---- */
.woocommerce div.product .product_title{color:var(--fg)}
.woocommerce div.product p.price{font-size:1.7rem;color:var(--fg)}
.woocommerce div.product .woocommerce-tabs ul.tabs li a{
  font-family:var(--sans);font-weight:400;font-size:.85rem;letter-spacing:.18em;text-transform:uppercase;color:var(--fg-soft);
}
.woocommerce div.product .woocommerce-tabs ul.tabs li.active a{color:var(--gold-role)}
.woocommerce div.product .woocommerce-tabs ul.tabs li.active,
.woocommerce div.product .woocommerce-tabs ul.tabs li.active a{border-bottom-color:var(--gold)}
.woocommerce div.product .woocommerce-tabs ul.tabs{border-bottom:1px solid var(--line)}
/* WC core's folder-corner ::before/::after boxes killed (0.8.2) — flat tabs.
   Active marker = a 2px strip across the TOP of the tab (Logan 2026-08-05;
   the earlier re-shown gold ::before rendered as WC's corner squares, and the
   bottom underline is gone with it). ::before is repurposed for the strip —
   WC core already gives li position:relative-equivalent via its box, but pin
   it explicitly since the strip is absolute. */
.woocommerce div.product .woocommerce-tabs ul.tabs li::after{display:none}
.woocommerce div.product .woocommerce-tabs ul.tabs li,
.woocommerce-js div.product .woocommerce-tabs ul.tabs li{position:relative;background:transparent;border:none;border-radius:0}
.woocommerce div.product .woocommerce-tabs ul.tabs li::before{
  content:"";display:none;position:absolute;top:0;left:0;right:0;height:2px;
  background:var(--gold) !important;border:none !important;box-shadow:none;
}
/* width/height restated here: WC core's own li.active::before sets a 5px
   square at this same specificity — later source order wins the tie */
.woocommerce div.product .woocommerce-tabs ul.tabs li.active::before{display:block;width:auto;height:2px}
/* smallscreen: WC stacks the tab list — the two labels sit side by side
   instead (Logan 2026-08-05). WC's 18px li side-padding + full eyebrow
   tracking made ADDITIONAL INFORMATION alone 260px wide — tightened so both
   fit a 345px column; the gap carries the separation. */
@media (max-width:768px){
  .woocommerce div.product .woocommerce-tabs ul.tabs{display:flex;flex-wrap:wrap;gap:0 1.6rem}
  .woocommerce div.product .woocommerce-tabs ul.tabs li{margin:0;padding:0}
  .woocommerce div.product .woocommerce-tabs ul.tabs li a{font-size:.78rem;letter-spacing:.12em;padding:.5em 0}
}
/* the tab anchor's UA focus ring boxed the whole tab on click — mouse focus
   quiet, keyboard focus keeps a visible ring */
.woocommerce div.product .woocommerce-tabs ul.tabs li a:focus:not(:focus-visible){outline:none}
.woocommerce div.product .woocommerce-tabs ul.tabs li a:focus-visible{outline:1px solid var(--gold-ink);outline-offset:2px}
/* tab panels — Astra pins dark text */
.woocommerce div.product .woocommerce-tabs .panel,
.woocommerce div.product .woocommerce-tabs .panel p,
.woocommerce div.product .woocommerce-tabs .panel li,
.woocommerce div.product .woocommerce-tabs .panel td{color:var(--fg-soft)}
.woocommerce div.product .woocommerce-tabs .panel h2{color:var(--fg)}
/* attributes table (Weight/Dimensions) — not a shop_table */
.woocommerce table.woocommerce-product-attributes,
.woocommerce table.shop_attributes{border:1px solid var(--line)}
.woocommerce table.woocommerce-product-attributes th,
.woocommerce table.shop_attributes th{
  background:transparent;
  font-weight:400;font-size:.82rem;letter-spacing:.18em;text-transform:uppercase;
}
/* Labels forced to ivory with !important + descendant catch — same old-site
   inline #16435F blue was sitting on the th (or a child), which the plain
   th color rule couldn't override. (2026-07-15) */
.woocommerce table.woocommerce-product-attributes th,
.woocommerce table.woocommerce-product-attributes th *,
.woocommerce table.shop_attributes th,
.woocommerce table.shop_attributes th *{color:var(--fg) !important}
/* Values forced to theme ivory with !important — the Additional Information
   rows carried dark old-site inline colors (#16435F blue / #000) sitting on
   the td or a non-span element, which the div.product span[style] neutralizer
   below doesn't reach. This catches them regardless of element. (2026-07-15) */
.woocommerce table.woocommerce-product-attributes td,
.woocommerce table.woocommerce-product-attributes td *,
.woocommerce table.shop_attributes td,
.woocommerce table.shop_attributes td *{background:transparent;color:var(--fg) !important}
.woocommerce table.woocommerce-product-attributes th,
.woocommerce table.woocommerce-product-attributes td,
.woocommerce table.shop_attributes th,
.woocommerce table.shop_attributes td{border-color:var(--line) !important}
/* kill WC core's zebra shading (rgba(0,0,0,.025) on even rows), italic
   values, and dotted 1px hairlines — flat rows + solid hairline everywhere
   this table renders, dark or paper. Selector must match WC core's exact
   text (assets/css/woocommerce.css) for specificity parity — source order
   (theme loads after WC) is what decides it, same trap as item I below. */
.woocommerce table.shop_attributes tr:nth-child(2n) td,
.woocommerce table.shop_attributes tr:nth-child(2n) th{background:transparent}
.woocommerce table.shop_attributes td{font-style:normal}
.woocommerce table.shop_attributes th,
.woocommerce table.shop_attributes td{border-style:solid !important;border-width:1px !important}
/* Catalog content carries Google-Docs paste artifacts (inline color:#000000,
   Poppins, 10pt spans) — normalize every pasted span to the theme. Data cleanup
   is a separate post-launch item; this keeps catalog data untouched. */
.woocommerce div.product span[style],
.woocommerce div.product li[dir] span{
  color:inherit !important;
  font-family:inherit !important;
  font-size:inherit !important;
  background-color:transparent !important;
}

/* Back-to-Builder banner — classless inline-styled div from the plugin */
div[style*="position:fixed"][style*="background:#fff"]{
  background:var(--ground) !important;
  border-top:1px solid var(--line) !important;
}
div[style*="position:fixed"][style*="background:#fff"] span{color:var(--fg-soft) !important}
/* ...on phones it stays (Steven's builder flow depends on it — Logan
   2026-08-05 walked back an earlier hide) but slims to one row: helper
   sentence dropped, button single-line full-width, tighter padding. */
@media (max-width:800px){
  div[style*="position:fixed"][style*="bottom:0"][style*="background:#fff"]{padding:10px 16px !important}
  div[style*="position:fixed"][style*="bottom:0"][style*="background:#fff"] span{display:none}
  div[style*="position:fixed"][style*="bottom:0"][style*="background:#fff"] a{
    display:block;text-align:center;white-space:nowrap;padding:.65rem 1rem !important;margin:0 !important;
  }
}
.pulse-product-cart-summary, .pulse-product-cart-summary *{color:var(--fg-soft) !important}
body:not(.luxe-landing) a[style*="background:#16435F"]{
  background:transparent !important;
  border:1px solid var(--btn-line) !important;
  color:var(--fg) !important;
  border-radius:0 !important;
  padding:.85rem 1.6rem !important;
  font-size:.85rem !important;
  font-weight:400 !important;
  letter-spacing:.18em;
  text-transform:uppercase;
}
body:not(.luxe-landing) a[style*="background:#16435F"]:hover{
  background:var(--gold) !important;
  border-color:var(--gold) !important;
  color:var(--ink) !important;
}
/* Gallery joins the loop tiles (punch list #16): the WRAPPER carries the tile,
   the photo multiplies onto it. Same reason as the loops — studio white is
   baked into every product file, so a warm background on the img itself is a
   no-op behind the photo and a seam anywhere the photo doesn't reach.
   isolation keeps the blend inside each wrapper; the zoom trigger and the
   photoswipe dialog are outside them and are untouched. One rule covers the
   main image and the flex thumbs; the zoom overlay is carved out below. */
.woocommerce div.product .woocommerce-product-gallery img{
  border:1px solid var(--line);background:none;mix-blend-mode:multiply;
}
/* the zoom overlay never multiplies. jquery-zoom lays .zoomImg OVER the base
   photo and leaves the base visible (verified live: base opacity 1 during
   hover), so multiply blends the magnified shot with the un-magnified one
   underneath — a double exposure, not a magnifier. Multiply exists to map a
   photo's baked studio white onto the tile; the overlay does not sit on the
   tile, it sits on the photo, so it has nothing to map.
   Surfaced when Pulse X went back to the blue master (Logan 2026-08-25):
   PulseX.png is a transparent alpha PNG, so it misses the .webp exemption
   above and was the last product whose zoom still multiplied.
   ponytail: one rule for every product, not another per-file src exemption. */
.woocommerce div.product .woocommerce-product-gallery img.zoomImg{
  mix-blend-mode:normal;
}
.woocommerce div.product .woocommerce-product-gallery__image,
.woocommerce div.product .flex-control-thumbs li{background:var(--tile);isolation:isolate}
.woocommerce div.product div.images .flex-control-thumbs{margin-top:1rem}

/* ============================================================
   0.6.0 consistency sweep — the pulse plugins print 2024-brand
   inline styles (navy #16435F, green #0e7c66, 6–10px radii, white
   panels) on the store's front-end pages: /shop/ steps, /find-order/,
   affiliate flow, builder modal, My Account kebab menu. Cosmetic
   overrides only, matched by inline-style signature (the established
   pattern in this file). Emails and wp-admin keep the 2024 brand.
   ============================================================ */
/* the store has no rounded corners — kill every inline radius in one move */
body:not(.luxe-landing) [style*="border-radius"]{border-radius:0 !important}
/* ...and the stylesheet-declared ones the child rules didn't reach */
body .pulse-tab, body .pulse-tab:first-child, body .pulse-tab:last-child,
body .pulse-step-number, body .pulse-kebab-toggle, body .pulse-kebab-menu,
body .pulse-kebab-menu a.button, body .pulse-kebab-menu a.woocommerce-button{border-radius:0}

/* step numerals (circles in plugin markup) — unboxed: plain gold serif
   numeral, same voice as the catalogue's i./ii./iii. */
body:not(.luxe-landing) div[style*="background:#0e7c66"][style*="border-radius:50%"]{
  background:transparent !important;border:none !important;
  color:var(--gold-role) !important;font-family:var(--serif);font-style:italic;
  font-weight:400 !important;font-size:1.9rem;text-align:left !important;
  width:auto !important;height:auto !important;line-height:1 !important;
}
body .pulse-step-number{
  background:transparent;border:none;color:var(--gold-role);
  font-family:var(--serif);font-style:italic;font-weight:400;font-size:1.5rem;
}

/* white/gray inline cards — hairline on the ground */
body:not(.luxe-landing) div[style*="border:1px solid #e3e8ec"],
body:not(.luxe-landing) div[style*="border:1px solid #d6dde4"]{
  border-color:var(--line) !important;background:transparent !important;
}
body:not(.luxe-landing) div[style*="flex:1 1 200px"]{padding:2.2rem 2rem !important}

/* inline 2024-brand text colors → system roles */
body:not(.luxe-landing) p[style*="color:#16435F"]{
  color:var(--fg) !important;font-size:1.35rem !important;font-weight:400 !important;
}
body:not(.luxe-landing) p[style*="color:#666"],
body:not(.luxe-landing) p[style*="color:#555"]{
  color:var(--fg-soft) !important;font-size:1.2rem !important;line-height:1.6 !important;
}

/* inline navy buttons (order lookup, rep search, modal Continue) — hairline luxe */
body:not(.luxe-landing) button[style*="background:#16435F"]{
  background:transparent !important;border:1px solid var(--btn-line) !important;color:var(--fg) !important;
  font-family:var(--sans);font-weight:400 !important;letter-spacing:.18em;text-transform:uppercase;font-size:.85rem !important;
  transition:background .45s ease, color .45s ease;
}
body:not(.luxe-landing) button[style*="background:#16435F"]:hover{
  background:var(--gold) !important;border-color:var(--gold) !important;color:var(--ink) !important;
}
/* inline/classed green primary buttons — the money action, gold fill */
body .pulse-affiliate-submit button{
  background:var(--gold) !important;color:var(--ink) !important;border:1px solid var(--gold) !important;
  font-family:var(--sans);font-weight:400 !important;letter-spacing:.18em;text-transform:uppercase;font-size:.85rem !important;
  transition:background .45s ease, color .45s ease;
}
body .pulse-affiliate-submit button:hover{background:transparent !important;color:var(--gold-role) !important}

/* inline-styled inputs (order lookup, affiliate email) — system fields */
body:not(.luxe-landing) input[style*="border:1px solid #ccc"]{
  background:var(--field) !important;border:1px solid var(--line) !important;color:var(--fg) !important;
}

/* My Account order-actions kebab menu — system panel */
body:not(.luxe-landing) .pulse-kebab-menu{background:var(--panel);border-color:var(--line);box-shadow:none}
body:not(.luxe-landing) .pulse-kebab-menu a.button,
body:not(.luxe-landing) .pulse-kebab-menu a.woocommerce-button{color:var(--fg-soft) !important}
body:not(.luxe-landing) .pulse-kebab-menu a.button:hover,
body:not(.luxe-landing) .pulse-kebab-menu a.woocommerce-button:hover{
  background:rgba(194,161,94,.12) !important;color:var(--fg) !important;
}

/* bundle-builder select focus ring — keep it visible, make it gold */
body:not(.luxe-landing) .pulse-bundle-selector select:focus{
  border-color:var(--gold);outline:2px solid var(--gold-soft);outline-offset:1px;
}
body .pulse-bundle-footer{background:var(--panel);border-color:var(--line)}

/* ---- pulse-shop 3.0 surfaces the earlier signature rules don't reach ---- */
/* form error lines — plugin prints #c0392b, 3.2:1 on ink */
body .pulse-form-msg, body #pulse-form-msg, body a.pulse_delete{color:var(--err-role) !important}
/* checkout stepper circles (class-stepper.php): green/navy/gray → unboxed gold numerals */
body:not(.luxe-landing) div[style*="background:#1e8e3e"][style*="border-radius:50%"],
body:not(.luxe-landing) div[style*="background:#16435F"][style*="border-radius:50%"],
body:not(.luxe-landing) div[style*="background:#e0e0e0"][style*="border-radius:50%"]{
  background:transparent !important;border:none !important;
  color:var(--gold-role) !important;font-family:var(--serif);font-style:italic;
  font-weight:400 !important;font-size:1.5rem;
}
body:not(.luxe-landing) div[style*="background:#e0e0e0"][style*="border-radius:50%"]{color:var(--fg-mute) !important}
/* affiliate confirmation h1 (green) */
body:not(.luxe-landing) h1[style*="color:#1e8e3e"]{color:var(--gold-role) !important}
/* estimate-review table borders sit on th/td, not divs */
body:not(.luxe-landing) th[style*="#e3e8ec"],
body:not(.luxe-landing) td[style*="#e3e8ec"]{border-color:var(--line) !important}
/* DocuSign signing page chrome (iframe content itself is external) */
/* box-sizing: the iframe's UA border is 2px per side outside a width:100%
   content box, which pushed it 4px past the column once the cap came off */
body #pulse-signing-iframe{border-color:var(--line) !important;background:#fff;box-sizing:border-box}
body #pulse-signing-error{background:var(--panel) !important;border-color:var(--line) !important}
body #pulse-signing-error, body #pulse-signing-error *{color:var(--err-role)}
body #pulse-signing-container div[style*="color:#666"]{color:var(--fg-soft) !important}
/* the agreement box joins the checkout's content column (Logan 2026-08-06).
   The plugin caps .pulse-pay-section--signing at 900px with 20px of side
   padding, so the sign step landed as a narrow inset ~200px in from the
   billing/order sheets the customer just came from. ID beats the plugin's
   class rule, so no !important is needed. Heading + intro copy ride the same
   widened column, which is what makes the step read as one aligned column. */
body #pulse-signing-container{max-width:none;padding-left:0;padding-right:0}

/* generic 2024-palette inline-style maps — cover the order-flow screens
   (thank-you, pay-balance, order lookup, estimate review, stepper) without
   a rule per element. Element-scoped :not(a) keeps link rules in charge. */
body:not(.luxe-landing) [style*="color:#16435F"]:not(a){color:var(--fg) !important}
body:not(.luxe-landing) [style*="color:#1e8e3e"]:not(a){color:var(--gold-role) !important}
body:not(.luxe-landing) [style*="color:#444"]:not(a),
body:not(.luxe-landing) [style*="color:#888"]:not(a),
body:not(.luxe-landing) [style*="color:#999"]:not(a),
body:not(.luxe-landing) [style*="color:#333"]:not(a){color:var(--fg-soft) !important}
body:not(.luxe-landing) [style*="color:#c0392b"]:not(a){color:var(--err-role) !important}
body:not(.luxe-landing) [style*="border:1px solid #ddd"],
body:not(.luxe-landing) [style*="border-bottom:1px solid #eee"],
body:not(.luxe-landing) [style*="border-top:2px solid #eee"],
body:not(.luxe-landing) [style*="#eef1f3"]{border-color:var(--line) !important}
body:not(.luxe-landing) [style*="border-top:2px solid #16435F"]{border-color:var(--gold) !important}
body:not(.luxe-landing) [style*="border:2px solid #16435F"]{border:1px solid var(--gold-soft) !important}
/* light panels → system panel */
body:not(.luxe-landing) [style*="background:#f8f8f8"],
body:not(.luxe-landing) [style*="background:#f4f6f8"],
body:not(.luxe-landing) [style*="background:#f3f5f6"],
body:not(.luxe-landing) [style*="background:#f5f5f5"]{
  background:var(--panel) !important;border-color:var(--line) !important;color:var(--fg) !important;
}
/* status boxes: error reds / success greens → system panels with system voice */
body:not(.luxe-landing) [style*="background:#fbeceb"],
body:not(.luxe-landing) [style*="background:#fff3f3"]{
  background:var(--panel) !important;border-color:var(--line) !important;color:var(--err-role) !important;
}
body:not(.luxe-landing) [style*="background:#eef6ee"]{
  background:var(--panel) !important;border-color:var(--line) !important;color:var(--gold-role) !important;
}
/* stepper connector line */
body:not(.luxe-landing) div[style*="height:2px"][style*="background:#e0e0e0"]{background:var(--line) !important}

/* payment-decision gate (class-signing-page.php prints its own <style> for
   .pulse-decide — the renamed .pulse-choose; class rules, not inline).
   Only ever rendered on /checkout/order-pay/ (always body.woocommerce-checkout,
   i.e. paper ground) — brought into the paper family 0.7.18, was still the
   dark-era card sitting on the ivory page. */
body .pulse-decide{background:#fff !important;border:1px solid var(--hairline-ink) !important;border-radius:0 !important}
body .pulse-decide h2{color:var(--ink) !important}
/* the sub-line is only "Choose how to pay for order SHOP-611." — that SHOP-{id}
   is the plugin's own minted reference (class-order-prefix.php) and is NOT the
   NetSuite SO number, so showing it to the customer here just seeds a number
   support can't look up (Logan 2026-08-06). Hidden, not restyled: the h2 above
   already says what the screen is, and the decision JS only ever reads
   input[name=pc] / #pc-amt / #pc-go, never this paragraph. Colour rule kept in
   place underneath for the day the plugin can print the real SO number. */
body .pulse-decide .sub{color:var(--ink-soft) !important;font-size:1rem !important;display:none !important}
body .pulse-decide label.opt{background:transparent !important;border:1px solid var(--hairline-ink) !important;border-radius:0 !important;color:var(--ink)}
body .pulse-decide label.opt:hover{border-color:var(--gold-ink) !important}
body .pulse-decide input{background:#fff !important;border:1px solid var(--hairline-ink) !important;border-radius:0 !important;color:var(--ink) !important}
body .pulse-decide .err{color:var(--error-ink) !important}
body .pulse-decide .dep{color:var(--ink-soft) !important}
body .pulse-decide .go{
  background:var(--gold) !important;color:var(--ink) !important;
  border:1px solid var(--gold) !important;border-radius:0 !important;
  font-family:var(--sans);letter-spacing:.18em;text-transform:uppercase;font-size:.85rem !important;
}
body .pulse-decide .go:hover{background:transparent !important;color:var(--gold-ink) !important;border-color:var(--gold-ink) !important}

/* ============================================================
   De-skinned plugin surfaces (pulse-shop `luxe-de-skin` branch).
   The plugin emits classed markup with layout-only structure; the
   theme owns every pixel of skin via these class hooks. As surfaces
   are de-skinned, their [style*=...] signature rules above become
   dead and get deleted. No !important needed — nothing to fight.
   Vocabulary: .pulse-btn / .pulse-btn--primary (shared), .pulse-oa
   (order-access: /find-order, /my-order messages).
   ============================================================ */
body .pulse-btn{
  display:inline-block;background:transparent;border:1px solid var(--btn-line);
  color:var(--fg);padding:.85rem 1.6rem;cursor:pointer;text-decoration:none;
  font-family:var(--sans);font-weight:400;letter-spacing:.18em;text-transform:uppercase;font-size:.85rem;
  transition:background .45s ease, color .45s ease, border-color .45s ease;
}
body .pulse-btn:hover{background:var(--gold);border-color:var(--gold-role);color:var(--ink)}
/* the money action — gold fill, inverts on hover */
body .pulse-btn--primary{background:var(--gold);border-color:var(--gold-role);color:var(--ink)}
body .pulse-btn--primary:hover{background:transparent;color:var(--gold-role)}
/* mobile chrome for every .pulse-btn surface (checkout, order lookup, affiliate,
   thank-you, signing, bundle, builder bar) — the desktop padding + .18em tracking
   made these near-full-width and prone to wrapping on a phone. One block here
   instead of a copy per surface. Vertical padding stays at .8rem (NOT tighter) so
   the box clears the 44px tap-target floor at this font-size. */
@media (max-width:600px){
  body .pulse-btn{padding:.8rem 1.15rem;letter-spacing:.12em;font-size:.78rem}
}

.pulse-oa p{color:var(--fg-soft);line-height:1.6}
.pulse-oa-form label{color:var(--fg-soft);font-size:.95rem}
.pulse-oa-form input{background:var(--field);border:1px solid var(--line);color:var(--fg);font-size:1rem}
.pulse-oa-form input:focus{border-color:var(--gold-soft);outline:none}
.pulse-oa-msg,.pulse-msg{border:1px solid var(--line);background:var(--panel)}
.pulse-oa-msg.is-error,.pulse-msg.is-error{color:var(--err-role)}
.pulse-oa-msg.is-ok,.pulse-msg.is-ok{color:var(--gold-role)}

/* shared de-skinned form fields (order search) */
.pulse-orders-search-input{background:var(--field);border:1px solid var(--line);color:var(--fg);font-size:1rem}
.pulse-orders-search-input:focus{border-color:var(--gold-soft);outline:none}

/* welcome landing renderer (/shop + /sales front doors) */
.pulse-landing-badge{border:1px solid var(--gold-soft);color:var(--gold-role);letter-spacing:.18em;text-transform:uppercase;font-size:.8rem}
.pulse-landing-step{border:1px solid var(--line)}
.pulse-landing-step-badge{color:var(--gold-role);font-family:var(--serif);font-style:italic;font-size:1.5rem}
.pulse-landing-step-title{color:var(--fg);font-weight:400;font-size:1.05rem}
.pulse-landing-step-description,.pulse-landing-footnote{color:var(--fg-soft)}

/* checkout stepper — unboxed gold serif numerals, same voice as i./ii./iii. */
.pulse-stepper-circle{color:var(--gold-role);font-family:var(--serif);font-style:italic;font-size:1.5rem}
.pulse-stepper-circle.is-pending{color:var(--fg-mute)}
.pulse-stepper-label{color:var(--fg-soft);font-size:.8rem;letter-spacing:.1em;text-transform:uppercase}
.pulse-stepper-label.is-current{color:var(--fg)}
.pulse-stepper-label.is-pending{color:var(--fg-mute)}
.pulse-stepper-line{background:var(--line)}
.pulse-stepper-line.is-done{background:var(--gold-soft)}

/* thank-you / pay-balance message pages */
.pulse-ty-msg p,.pulse-pb-msg{color:var(--fg-soft)}
.pulse-ty-msg-secondary{color:var(--fg-soft);font-size:.95rem}

/* my-account additions */
.pulse-ma-payments-title{color:var(--fg);font-family:var(--serif);font-weight:300}
.pulse-ma-balance-due{color:var(--gold-role)}
.pulse-ma-amount-paid{color:var(--fg-soft)}
.pulse-orders-search-clear,.pulse-aff-copy-skip,.pulse-companion-remove{color:var(--fg-soft);text-decoration:underline}
.pulse-orders-search-clear:hover,.pulse-aff-copy-skip:hover,.pulse-companion-remove:hover{color:var(--gold-role)}
.pulse-orders-page-indicator,.pulse-order-support-note{color:var(--fg-soft)}

/* builder / bundle chrome */
.pulse-package-banner{background:var(--panel);border:1px solid var(--line)}
.pulse-package-banner-notice{color:var(--fg-soft)}

/* checkout section intro under Save-Estimate heading — paper ground (checkout
   is all-paper since 0.7.8); ivory-60 was dark-era leftover, unreadable on ivory */
.pulse-checkout-section-intro{color:var(--ink-soft);font-size:.95rem}

/* final-review fixes: theme-side skin the sweep left uncovered */
.pulse-bundle-card,.pulse-bundle-heading,
.pulse-bundle-selector select{border-color:var(--line)}
.pulse-bundle-card-placeholder{background:var(--panel)}
.pulse-ma-payments th,.pulse-ma-payments td{border-bottom:1px solid var(--line)}
.pulse-ma-total{color:var(--fg)}
.pulse-table th,.pulse-table td{border-bottom:1px solid var(--line)}
.pulse-table th{color:var(--fg-soft);font-weight:400;letter-spacing:.14em;text-transform:uppercase;font-size:.8rem}
.pulse-table .pulse-table-total td,.pulse-table .pulse-table-total th{
  border-top:1px solid var(--gold);border-bottom:none;color:var(--fg);
}
.pulse-back-link{margin-bottom:16px}

/* builder chrome newly classed by the de-skin (was signature-matched) */
.pulse-back-to-builder{background:var(--ground);border-top:1px solid var(--line)}
.pulse-back-to-builder-hint,.pulse-cart-note,.pulse-cart-empty{color:var(--fg-soft)}
.pulse-back-link-anchor{color:var(--fg-soft)}
.pulse-back-link-anchor:hover{color:var(--gold-role)}
.pulse-warn-modal{background:var(--panel);border:1px solid var(--line)}
.pulse-loading-title{color:var(--fg)}
.pulse-loading-text,.pulse-loading{color:var(--fg-soft)}

/* estimate-review page (/my-order → review) */
.pulse-est-intro,.pulse-est-footnote{color:var(--fg-soft)}
.pulse-est-footnote{font-size:.85rem}
.pulse-est-items-table th,.pulse-est-items-table td,
.pulse-est-summary-table th,.pulse-est-summary-table td{border-bottom:1px solid var(--line);padding:.7rem .5rem}
.pulse-est-items-table th{color:var(--fg-soft);font-weight:400;letter-spacing:.14em;text-transform:uppercase;font-size:.8rem}
.pulse-est-summary-table .total th,.pulse-est-summary-table .total td,
.pulse-est-summary-table tr:last-child th,.pulse-est-summary-table tr:last-child td{border-top:1px solid var(--gold);border-bottom:none;color:var(--fg)}

/* bundle-builder add button (plugin CSS carries 9 !importants, green) */
body .pulse-bundle-add-btn{
  background:var(--gold) !important;color:var(--ink) !important;
  border:1px solid var(--gold) !important;border-radius:0 !important;box-shadow:none !important;
  font-family:var(--sans);letter-spacing:.18em;text-transform:uppercase;
}
body .pulse-bundle-add-btn:hover{background:transparent !important;color:var(--gold-role) !important}
/* builder product-card buttons: pin radius/shadow too (plugin CSS has them
   !important). The font-size/padding here USED TO BE PLAIN DECLARATIONS and
   were therefore dead: shop-builder.css ships `font-size:14px !important;
   font-weight:600 !important; padding:10px 20px !important` on this exact
   selector minus the `body`, so the plugin won every one of them and the
   buttons rendered 14px/600 — a weight neither Jost nor Cormorant has, i.e.
   browser-synthesized fake bold, which the type contract forbids (Logan
   2026-08-06). Countered in kind: `body` + the same chain out-specifies the
   plugin, and !important is what makes that specificity count. font-weight is
   stated explicitly because the theme never declared one here at all. */
body .pulse-products ul.products li.product a.button,
body .pulse-products ul.products li.product a.add_to_cart_button{
  border-radius:0 !important;box-shadow:none !important;
  font-size:.85rem !important;font-weight:400 !important;
  /* Fluid side padding + a wrap escape valve. The failure here tracks TILE
     width, not viewport: at 900px the accessories grid is still 4-up on 171px
     tiles, so a viewport media query cannot catch it. A flat 2rem ring made
     every caption overrun its column (measured "Select options" 197px in a
     150px tile at 390 — and 181px pre-fix, so the overflow predates this
     change and is only being closed now). 2vw keeps the desktop ring, the
     .9rem floor keeps mobile legible, and normal wrapping means the worst
     case is two lines rather than a button lying across its neighbour. */
  padding:.9rem clamp(.9rem,2vw,2rem) !important;
  white-space:normal !important;max-width:100% !important;
}
/* the builder machine grid is the purchase moment — larger than the base loop */
body .pulse-products ul.products li.product .woocommerce-loop-product__title{font-size:1.7rem}
body .pulse-products ul.products li.product .price{font-size:1.4rem;color:var(--fg)}

/* ---- Customizer post 595 neutralizers ----
   Additional CSS lives in the DB, loads after this sheet, and does NOT
   travel with a git deploy — so these carry !important and must stay in
   the theme. Durable cleanup = trim the Customizer CSS on prod itself.
   (1) zoom:1.45 was written for /affiliate/ (now 404) but its
   [style*="max-width:820px"] hook only matches /shop/ today → that one
   page rendered ~23px. (2) sub-ladder type on /get-started/. */
body:not(.luxe-landing) #content div[style*="max-width:820px"]{
  zoom:1 !important;max-width:1220px !important;
}
body .pulse-choose .pc-eyebrow{font-size:.8rem !important}
body .pulse-choose .pc-cta{font-size:.85rem !important}

/* ---- single product goes paper (0.7.6, Logan 2026-07-30) ----
   The whole single-product surface joins the ivory writing flow — the
   catalogue page you read before you buy. body.single-product is Woo's
   native scope hook, no :has() needed. #content boxes are already
   background:transparent (see the ast-separate-container rule near the
   top of this file), so flipping body is enough to paper the whole page.
   Site header/footer already stay ink unconditionally (their rules key
   off body:not(.luxe-landing), which single-product still satisfies) —
   nothing to restate there. Same .light law as checkout/builder:
   --gold-ink is gold's only voice on paper; raw --gold never sits on ivory
   as text. Grouped/package products render through the pulse_shop
   .pulse-bundle-* custom template (verified live), NOT Woo's native
   woocommerce-grouped-product-list table — that table never ships on
   this build, so it isn't styled here (nothing to counter).

   body.tax-product_cat joins the same paper treatment (0.7.26) — the
   category archives (under /product-category/) were the last loop surface
   left on the dark ground, illegible against the dark-on-dark loop cards
   below. Pure WP/Woo taxonomy template: no pulse-shop-checkout rewrite
   rule or template_redirect touches tax-product_cat (grepped both plugin
   dirs — the only product_cat hits are wp_get_post_terms() bundle lookups
   and a template_redirect that only fires INSIDE an active affiliate flow
   to clear it, never rewrites/redirects the archive itself), so this is
   safe cosmetic-only and can't touch Steven's /sales/ or /build/ routes.
   /shop/ redirects away (shim #1 above) so archives are the only
   remaining loop surface. */
body.single-product,
body.tax-product_cat{background:var(--ivory);color:var(--ink)}
body.single-product #content a,
body.tax-product_cat #content a{color:var(--ink)}
body.single-product #content a:hover,
body.tax-product_cat #content a:hover{color:var(--gold-ink)}
body.single-product #content h1,
body.single-product #content h2,
body.single-product #content h3,
body.single-product #content h4,
body.tax-product_cat #content h1,
body.tax-product_cat #content h2,
body.tax-product_cat #content h3,
body.tax-product_cat #content h4{color:var(--ink)}

/* title + price + meta */
body.single-product div.product .product_title{color:var(--ink)}
body.single-product div.product p.price{color:var(--ink)}
body.single-product div.product .product_meta{color:var(--ink-soft)}
body.single-product div.product .product_meta a{color:var(--ink-soft)}
body.single-product div.product .product_meta a:hover{color:var(--gold-ink)}
/* SKU hidden site-wide on product pages (Logan 2026-08-04) — .posted_in
   (the "Categories: ..." line) is a sibling, untouched, stays visible.
   !important: astra-woocommerce-grid.min.css's ".product_meta > span"
   carries an extra type selector (0,3,2 vs our 0,3,1) and wins on
   specificity alone regardless of source order. */
body.single-product .product_meta .sku_wrapper{display:none !important}
body.single-product div.product p.stock{color:var(--ink-soft)}
body.single-product .woocommerce-product-details__short-description{color:var(--ink-soft)}

/* gallery frame — photos are already white tiles, reframe hairline-ink
   (the site-wide gold-soft frame at the top of this file is scoped to
   cart/checkout thumbnails too, so it's countered here, not edited) */
body.single-product div.product .woocommerce-product-gallery__image img{
  border-color:var(--hairline-ink);
}
body.single-product .flex-control-thumbs li img{border:1px solid var(--hairline-ink)}

/* quantity input — #fff/hairline-ink/ink, both the simple-product form and
   inside variations/grouped-bundle forms */
body.single-product .quantity .qty{background:#fff;border:1px solid var(--hairline-ink);color:var(--ink)}
body.single-product .quantity .minus,
body.single-product .quantity .plus{background:transparent;border:1px solid var(--hairline-ink);color:var(--ink-soft)}

/* variation form — plain <select>, no select2 on this build (verified live).
   appearance:none + padded field + own chevron (0.8.3 — Logan walkthrough:
   native control rendered "goofy and small" at UA default height/font). */
body.single-product .variations select{
  appearance:none;-webkit-appearance:none;
  background:#fff url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='11' height='7' viewBox='0 0 11 7'><path d='M1 1l4.5 4.5L10 1' fill='none' stroke='%230f0f11' stroke-opacity='.62' stroke-width='1.2'/></svg>") no-repeat right .9em center;
  border:1px solid var(--hairline-ink);color:var(--ink);
  font-size:1rem;line-height:1.4;padding:.7em 2.6em .7em .9em;
}
body.single-product .variations select:focus{
  outline:1px solid var(--gold-ink);outline-offset:0;border-color:var(--gold-ink);
}
/* variation row stacked: WC's two-column table crowds th.label/td.value
   side by side on the narrower single-product column — stack label above
   a full-width select instead (2026-08-05, chair-pad had a squeezed dropdown). */
.woocommerce div.product table.variations,
.woocommerce div.product table.variations tbody,
.woocommerce div.product table.variations tr,
.woocommerce div.product table.variations th,
.woocommerce div.product table.variations td{display:block;width:100%}
.woocommerce div.product table.variations th.label{padding:0 0 .5rem;text-align:left}
.woocommerce div.product table.variations td.value{padding:0}
.woocommerce div.product table.variations select{width:100%}
/* WC core's real selector is .woocommerce div.product form.cart .variations
   (4 classes) — outspecifies this 3-class selector regardless of source
   order, same tie pattern as .woocommerce-variation .price elsewhere in this
   file; needs !important to actually win. */
.woocommerce div.product table.variations{margin:0 0 2rem !important}
/* WC core sets .variations label{font-weight:700}, no size — falls through
   to body's 20px. Match the eyebrow/table-head voice used elsewhere
   (.woocommerce table.shop_table th). Astra's own copy of the same rule
   (.woocommerce-js div.product form.cart .variations label) out-specifies
   this selector on classes (4 vs 2) — same tie pattern as the variation
   price fix above, needs !important on the one property it actually wins. */
body.single-product .variations label{color:var(--ink-soft);font-weight:400 !important;font-size:.82rem;letter-spacing:.18em;text-transform:uppercase}
/* ties Astra's price-color rule AND WooCommerce core's price font-size rule
   on specificity (3 classes each) and loses both tiebreaks on element count
   — needs !important on both to actually win */
body.single-product .woocommerce-variation .price{color:var(--ink) !important;font-size:1.7rem !important}
body.single-product .woocommerce-variation-description{display:none !important}
body.single-product a.reset_variations{color:var(--ink-soft)}
body.single-product a.reset_variations:hover{color:var(--gold-ink)}

/* the money button — single_add_to_cart_button is the primary action:
   gold face + ink text always, hover flips to transparent + gold-ink.
   Full selector chain match beats the generic secondary-button rule
   near the top of this file at equal-or-higher specificity. */
body.single-product div.product form.cart .single_add_to_cart_button{
  background:var(--gold);border-color:var(--gold);color:var(--ink);
}
body.single-product div.product form.cart .single_add_to_cart_button:hover{
  background:transparent;border-color:var(--gold-ink);color:var(--gold-ink);
}

/* grouped/package product — the pulse_shop custom bundle renderer
   (.pulse-bundle-*), NOT Woo's native grouped-product-list table */
body.single-product .pulse-bundle-heading{color:var(--ink)}
body.single-product .pulse-bundle-card{border-color:var(--hairline-ink)}
body.single-product .pulse-bundle-card-name{color:var(--ink)}
body.single-product .pulse-bundle-selector label{color:var(--ink-soft)}
body.single-product .pulse-bundle-selector select{
  background:#fff;border:1px solid var(--hairline-ink);color:var(--ink);
}
body.single-product .pulse-bundle-footer{background:#fff;border-color:var(--hairline-ink)}
body.single-product .pulse-bundle-total-label{color:var(--ink-soft)}
body.single-product .pulse-bundle-total-price{color:var(--ink)}
/* .pulse-bundle-add-btn is gold-face/ink-text already (global !important
   rule) — only its hover text needs the paper voice: raw gold on ivory
   fails, gold-ink is the fix. Same specificity, later in file, wins. */
body.single-product .pulse-bundle-add-btn:hover{
  background:transparent !important;color:var(--gold-ink) !important;border-color:var(--gold-ink) !important;
}

/* Woo product tabs — ink-soft, active gold-ink, hairline-ink borders.
   ::after kill + li{border:none} + li.active border-bottom-width/style come
   from the unscoped generic block above (0.8.2) — no need to duplicate here. */
body.single-product div.product .woocommerce-tabs ul.tabs{border-bottom:1px solid var(--hairline-ink)}
body.single-product div.product .woocommerce-tabs ul.tabs li a{color:var(--ink-soft)}
body.single-product div.product .woocommerce-tabs ul.tabs li.active a{color:var(--gold-ink)}
/* the active-tab top strip (generic block above) reads gold-ink on paper */
body.single-product div.product .woocommerce-tabs ul.tabs li::before{
  background:var(--gold-ink) !important;
}
/* tab panels */
body.single-product div.product .woocommerce-tabs .panel,
body.single-product div.product .woocommerce-tabs .panel p,
body.single-product div.product .woocommerce-tabs .panel li,
body.single-product div.product .woocommerce-tabs .panel td{color:var(--ink-soft)}
body.single-product div.product .woocommerce-tabs .panel h2{color:var(--ink)}
/* attributes table (Weight/Dimensions) + the !important Google-Docs-paste
   neutralizers pinned to var(--ivory) above — counter both in kind */
body.single-product table.woocommerce-product-attributes,
body.single-product table.shop_attributes{border-color:var(--hairline-ink)}
body.single-product table.woocommerce-product-attributes th,
body.single-product table.woocommerce-product-attributes th *,
body.single-product table.shop_attributes th,
body.single-product table.shop_attributes th *{color:var(--ink) !important}
body.single-product table.woocommerce-product-attributes td,
body.single-product table.woocommerce-product-attributes td *,
body.single-product table.shop_attributes td,
body.single-product table.shop_attributes td *{color:var(--ink-soft) !important}
body.single-product table.woocommerce-product-attributes th,
body.single-product table.woocommerce-product-attributes td,
body.single-product table.shop_attributes th,
body.single-product table.shop_attributes td{border-color:var(--hairline-ink) !important}
/* "Features" bullet list (0.7.26) — color/border already inherited from the
   td * rule above.
   list-style-position is OUTSIDE with an explicit padding-left (0.12.9): the
   original `inside` was there to stop the glyph overflowing the cell, but it
   parks the bullet flat against the cell's hairline border and pushes a ~27px
   gap between glyph and text. `outside` + padding-left puts the glyph in the
   list's own padding — still inside the cell, off the border, and the
   glyph-to-text gap becomes the normal ~8px.
   No font-size: the bullets must inherit the td's 20px, or they sit at 13.6px
   directly beside the 20px Weight/Dimensions value cells in the same column and
   read as broken. The .85rem this replaced shipped in 0.7.26 but was never seen
   rendered — the Features attributes were deleted from every product the same
   day, so the two row types never appeared in one table until 2026-08-14. */
.pulse-attr-features{list-style:disc;list-style-position:outside;margin:.45rem 0;padding:0 0 0 1.35em}
/* .15rem left the li boxes touching (measured interLiGap:0) — every bit of
   apparent separation came from line-height, and at 20px that read as cramped.
   The ul margin matters just as much: without it the first and last bullet sat
   1px off the cell's hairline border. Logan 2026-08-14. */
.pulse-attr-features li{padding:.35rem 0}
/* pasted-span neutralizer above forces color:inherit — inherits ink-soft
   from the td rule, so nothing further needed here */

/* related/upsell loops — reuse the builder block's paper loop treatment.
   body.tax-product_cat joins here too (0.7.26): the category archive loop
   is the exact same ul.products/li.product markup, just the top-level loop
   instead of a related/upsell one — same cards, same fix. */
body.single-product ul.products li.product .woocommerce-loop-product__title,
body.tax-product_cat ul.products li.product .woocommerce-loop-product__title{color:var(--ink)}
body.single-product ul.products li.product .price,
body.tax-product_cat ul.products li.product .price{color:var(--ink);font-size:1.375rem}
body.single-product ul.products li.product a.button,
body.single-product ul.products li.product a.add_to_cart_button,
body.single-product ul.products li.product a.product_type_simple,
body.single-product ul.products li.product a.product_type_variable,
body.single-product ul.products li.product a.product_type_grouped,
body.tax-product_cat ul.products li.product a.button,
body.tax-product_cat ul.products li.product a.add_to_cart_button,
body.tax-product_cat ul.products li.product a.product_type_simple,
body.tax-product_cat ul.products li.product a.product_type_variable,
body.tax-product_cat ul.products li.product a.product_type_grouped{
  border-color:var(--hairline-ink);color:var(--ink);background:transparent;
}
body.single-product ul.products li.product a.button:hover,
body.single-product ul.products li.product a.add_to_cart_button:hover,
body.single-product ul.products li.product a.product_type_simple:hover,
body.single-product ul.products li.product a.product_type_variable:hover,
body.single-product ul.products li.product a.product_type_grouped:hover,
body.tax-product_cat ul.products li.product a.button:hover,
body.tax-product_cat ul.products li.product a.add_to_cart_button:hover,
body.tax-product_cat ul.products li.product a.product_type_simple:hover,
body.tax-product_cat ul.products li.product a.product_type_variable:hover,
body.tax-product_cat ul.products li.product a.product_type_grouped:hover{
  background:var(--gold);border-color:var(--gold);color:var(--ink);
}

/* breadcrumbs, if the template ever surfaces them (tax-product_cat's always does) */
body.single-product .woocommerce-breadcrumb,
body.tax-product_cat .woocommerce-breadcrumb{color:var(--ink-soft)}
body.single-product .woocommerce-breadcrumb a,
body.tax-product_cat .woocommerce-breadcrumb a{color:var(--ink-soft)}
body.single-product .woocommerce-breadcrumb a:hover,
body.tax-product_cat .woocommerce-breadcrumb a:hover{color:var(--gold-ink)}
/* the Catalog crumb links /build/?resume=browse (0.8.2 breadcrumb filter) —
   the same href signature the 0.4.x-era pill rule buttonizes with !important
   (ivory text + gold border = invisible empty box on paper; Logan 2026-08-05).
   Same counter pattern as .luxe-back's, restating the quiet crumb voice.
   Ties the pill rule's (0,2,1)+!important and wins on source order. */
.woocommerce-breadcrumb a[href*="resume=browse"]{
  background:transparent !important;color:var(--ink-soft) !important;
  border:none !important;padding:0 !important;font-size:inherit !important;
  text-transform:none !important;letter-spacing:normal;font-family:inherit;
}
.woocommerce-breadcrumb a[href*="resume=browse"]:hover{
  background:transparent !important;color:var(--gold-ink) !important;border:none !important;
}

/* archive-only chrome — no single-product analog: result count + sort dropdown */
body.tax-product_cat .woocommerce-result-count{color:var(--ink-soft)}
body.tax-product_cat .woocommerce-ordering select{
  background:#fff;border:1px solid var(--hairline-ink);color:var(--ink);
}

/* Woo notices + blockUI on paper */
body.single-product .woocommerce-message,
body.single-product .woocommerce-info,
body.single-product .woocommerce-error{
  background-color:#fff;border:1px solid var(--hairline-ink);border-top:2px solid var(--gold);color:var(--ink-soft);
}
body.single-product .woocommerce-message::before,
body.single-product .woocommerce-info::before{color:var(--gold-ink)}
body.single-product .blockUI.blockOverlay{background:var(--ivory) !important}

/* "Back to Builder" fixed banner (arrives via ?from=builder) — paper +
   hairline-ink, hint text ink-soft. Countering the global !important
   cart-summary catch and the dark .pulse-btn/.pulse-btn--primary base. */
body.single-product .pulse-back-to-builder{background:var(--ivory);border-top:1px solid var(--hairline-ink)}
body.single-product .pulse-back-to-builder-hint{color:var(--ink-soft)}
body.single-product .pulse-cart-summary,
body.single-product .pulse-product-cart-summary,
body.single-product .pulse-product-cart-summary *{color:var(--ink-soft) !important}
/* sibling banner: "Browsing Pre-Built Packages" (arrives via /shop/ package
   browsing) — same dark .pulse-package-banner base the builder block
   already counters for its own scope; single-product needs its own copy */
body.single-product .pulse-package-banner{background:#fff;border-color:var(--hairline-ink)}
body.single-product .pulse-package-banner-notice{color:var(--ink-soft)}
/* .pulse-btn is shared chrome across both banners above — one rule covers it */
body.single-product .pulse-btn{color:var(--ink);border-color:var(--hairline-ink)}
body.single-product .pulse-btn:hover{background:var(--gold);border-color:var(--gold);color:var(--ink)}
body.single-product .pulse-btn--primary{background:var(--gold);border-color:var(--gold);color:var(--ink)}
body.single-product .pulse-btn--primary:hover{
  background:transparent;color:var(--gold-ink);border-color:var(--gold-ink);
}

/* plugin-era inline-navy signature catches (2024-brand markup, if the
   product template ever prints one on this surface) */
body.single-product a[style*="#16435F"]{color:var(--ink-soft) !important}
body.single-product a[style*="#16435F"]:hover{color:var(--gold-ink) !important}
/* get-started merged cards (2026-07-29): mini step lists + secondary link.
   Cards became <div>s with multiple links when /sales + /shop content merged in. */
/* Top text shares the card grid's measure (Logan 2026-08-06): .pulse-choose is
   a flex column whose items are NOT stretched, so the h1 shrink-wrapped to its
   text and the intro was capped at a reading measure, while .pc-grid takes the
   full content box — the two-card row visibly overhung both. align-self:stretch
   hands all three the same edges without hard-coding a width, so it holds at
   every viewport. max-width:none is what defeats the Customizer's own
   `.pulse-choose .pc-intro{max-width:46ch}`: this selector is (0,2,1) against
   its (0,2,0), which is the same lever the old 58ch rule used — the
   Customizer's Additional CSS is load-bearing here and stays untouched. */
body .pulse-choose h1,
body .pulse-choose .pc-intro{align-self:stretch;max-width:none}
body .pulse-choose .pc-intro{line-height:1.6}
body .pulse-choose .pc-steps{
  list-style:none;margin:1.4rem 0 1.8rem;padding:0;counter-reset:pcstep;width:100%;
}
body .pulse-choose .pc-steps li{
  counter-increment:pcstep;position:relative;padding:.7rem 0 .7rem 2.4rem;
  border-top:1px solid var(--line);color:var(--fg-soft);font-size:1rem;line-height:1.5;
}
body .pulse-choose .pc-steps li:last-child{border-bottom:1px solid var(--line)}
body .pulse-choose .pc-steps li::before{
  content:counter(pcstep, lower-roman) ".";
  position:absolute;left:.2rem;top:.7rem;
  font-family:var(--serif);font-style:italic;color:var(--gold-role);font-size:1.1rem;
}
body .pulse-choose .pc-cta{
  display:inline-block;border:1px solid var(--gold-soft);padding:.85rem 1.6rem;
  letter-spacing:.18em;text-transform:uppercase;color:var(--fg);
  transition:background .45s ease, color .45s ease;
}
body .pulse-choose .pc-cta:hover{background:var(--gold);border-color:var(--gold);color:var(--ink)}
body .pulse-choose .pc-alt{
  display:block;margin-top:1rem;font-size:.85rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--fg-soft);
}
body .pulse-choose .pc-alt:hover{color:var(--gold-role)}
/* alignment: equal intro height so the step rows line up across cards,
   and the CTA flows right after the steps (no pushed-to-bottom blank) */
body .pulse-choose .pc-card > p{min-height:5em}
body .pulse-choose .pc-cta{margin-top:.4rem !important;margin-bottom:0 !important;align-self:flex-start}
/* hover belongs to the buttons, not the whole card (legacy card-level
   hover highlighted "Choose your machine" while hovering "browse all") */
body .pulse-choose .pc-card:hover .pc-cta{background:transparent;border-color:var(--gold-soft);color:var(--fg)}
body .pulse-choose .pc-cta:hover{background:var(--gold) !important;border-color:var(--gold) !important;color:var(--ink) !important}

/* ============================================================
   Luxe landing (template-luxe-landing.php) — scoped via CSS
   nesting under body.luxe-landing; source: luxury-landing/luxury
   ============================================================ */
@keyframes luxeHeroIn{to{transform:scale(1)}}
@keyframes luxeRise{to{opacity:1;transform:none}}
html:has(body.luxe-landing){scroll-behavior:smooth}

body.luxe-landing{
  & *{margin:0;padding:0;box-sizing:border-box}
  background:var(--ink);
  color:var(--ivory);
  font-family:var(--sans);
  font-weight:350;
  font-size:clamp(1.125rem, 1.05rem + .3vw, 1.25rem);
  line-height:1.75;
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;

  & img{display:block;max-width:100%}
  & a{color:inherit;text-decoration:none}

  /* ---- shared type ---- */
  & .eyebrow{
    font-family:var(--sans);font-weight:400;font-size:.95rem;
    letter-spacing:.42em;text-transform:uppercase;color:var(--gold);
  }
  & h1,& h2,& .display{
    font-family:var(--serif);font-weight:300;line-height:1.08;letter-spacing:.005em;
  }
  /* Astra dynamic CSS pins heading colors to its palette — landing headings must follow their section (dark/ivory) */
  & h1,& h2,& h3,& .display{color:inherit}
  & h1{font-size:clamp(3.2rem, 9vw, 6rem)}
  & h2{font-size:clamp(2.5rem, 5.2vw, 4.4rem)}
  & em{font-style:italic;font-weight:400}
  /* Display italics inherit the heading's 300 (Logan 2026-08-06): the em bump
     to 400 is for running text, but against a 300 Cormorant heading the same
     family at 400 reads as a heavier, foreign face — "Charge your *potential.*"
     was the complaint. :is() carries .display's class weight, so this beats
     the `& em` rule above; body copy keeps its 400. */
  & :is(h1,h2,h3,.display) em{font-weight:inherit}
/* self-hosted Cormorant/Jost stop at 500 — any 700 is synthesized fake-bold
   (distorted glyphs, "different font" complaints). Cap emphatic weight at
   the real cut; WC core loves 700 (strong, th, td::before, required *). */
body:not(.luxe-landing) strong, body:not(.luxe-landing) b{font-weight:500}
  & .lede{color:var(--ivory-60);max-width:34em}

  & .section{padding:clamp(5.5rem, 12vh, 10rem) var(--pad)}
  & .container{max-width:1220px;margin:0 auto}
  & .section-head{display:flex;align-items:center;gap:1.6rem;margin-bottom:clamp(2.8rem, 6vh, 4.6rem)}
  & .section-head::after{content:'';flex:1;height:1px;background:var(--hairline)}
  & .light .section-head::after{background:var(--hairline-ink)}

  /* ---- buttons (dark-context luxe) ---- */
  & .btn{
    display:inline-block;font-family:var(--sans);font-weight:400;
    font-size:.85rem;letter-spacing:.32em;text-transform:uppercase;
    padding:1.05rem 2.6rem;border:1px solid var(--gold-soft);color:var(--ivory);
    transition:background .45s ease, color .45s ease, border-color .45s ease;
  }
  & .btn:hover{background:var(--gold);border-color:var(--gold);color:var(--ink)}
  & .btn-ink{color:var(--ink);border-color:rgba(15,15,17,.4)}
  & .btn-ink:hover{background:var(--ink);border-color:var(--ink);color:var(--ivory)}
  & .text-link{
    font-size:.85rem;letter-spacing:.3em;text-transform:uppercase;font-weight:400;
    color:var(--ivory-60);border-bottom:1px solid var(--hairline);padding-bottom:.35rem;
    transition:color .4s ease, border-color .4s ease;
  }
  & .text-link:hover{color:var(--gold);border-color:var(--gold-soft)}

  /* ---- ivory sections — every on-ivory role restated (gold + ivory alphas fail on ivory) ----
     The two raw dark-ground vars are RE-BOUND here rather than counter-styled
     per descendant: custom properties resolve by inheritance, not specificity,
     so one declaration flips every --hairline rule and every ivory-60 secondary
     text inside the section at once (same trick as the :root role tokens).
     Load-bearing once craftsmanship + protocol went cream: their
     .materials/.stack-grid rules are declared AFTER this block at EQUAL
     specificity, so a counter rule here would have lost on source order. */
  & .light{
    background:var(--ivory);color:var(--ink);
    --hairline:var(--hairline-ink);
    --ivory-60:var(--ink-soft);
  }
  /* …and the elite card is a DARK island inside that cream section, so it hands
     the same two vars back (literals: a custom property can't re-read :root's) */
  & .light .elite{--hairline:rgba(241,236,226,.16);--ivory-60:rgba(241,236,226,.72)}
  & .light .lede{color:var(--ink-soft)}
  & .light .eyebrow{color:var(--gold-ink)}
  & .light .text-link{color:var(--ink-soft);border-bottom-color:var(--hairline-ink)}
  & .light .text-link:hover{color:var(--gold-ink);border-color:var(--gold-ink)}
  & .light .materials .num,& .light .stack-grid .num,& .light .glove-row .num{color:var(--gold-ink)}
  & .light .stats{border-top-color:var(--hairline-ink)}
  & .light .stats .n{color:var(--gold-ink)}
  & .light .stats .l{color:var(--ink-soft)}
  & .light .evidence-foot .micro{color:var(--ink-soft)}
  /* raw --gold text is 2.09:1 on ivory — the protocol section's research link
     is the one inline gold voice that lands on cream */
  & .light .inline-link{color:var(--gold-ink);border-bottom-color:var(--gold-ink)}
  /* gold-soft is 1.48:1 on ivory (invisible); --hairline-ink is worse at 1.39:1.
     Solid --gold-ink (4.87:1) keeps the accent gold AND keeps the frame a frame. */
  & .light .craft-visual::after{border-color:var(--gold-ink)}
  /* .pulse-roi is a dark island (like .elite) that styles its own text — keep the
     cream-section text colors out of it */
  & .light p:not(.pulse-roi *){color:var(--ink-soft)}
  & .light :is(h1,h2,h3):not(.pulse-roi *){color:var(--ink)}
  /* the elite card is a DARK island inside the light flagship section —
     restate every role the .light rules above just repainted ink-on-ink */
  & .light .elite h3{color:var(--ivory)}
  & .light .elite p{color:var(--ivory-60)}
  & .light .elite .eyebrow{color:var(--gold)}
  & .light .elite .text-link{color:var(--ivory-60);border-bottom-color:var(--hairline)}
  & .light .elite .text-link:hover{color:var(--gold);border-color:var(--gold-soft)}

  /* ---- header ---- */
  & .luxe-header{
    position:fixed;inset:0 0 auto 0;z-index:50;
    display:flex;justify-content:space-between;align-items:center;
    padding:1.25rem var(--pad);
    border-bottom:1px solid transparent;
    /* background/border only — animating padding causes layout thrash */
    transition:background .5s ease, border-color .5s ease;
  }
  & .luxe-header.scrolled{
    background:linear-gradient(rgba(15,15,17,.92), rgba(15,15,17,.78));
    backdrop-filter:blur(10px);
    border-bottom-color:rgba(241,236,226,.07);
  }
  & .luxe-nav{display:flex;align-items:center;gap:2.2rem}
  & .wordmark{
    font-family:var(--sans);font-weight:500;font-size:.95rem;
    letter-spacing:.58em;text-transform:uppercase;color:var(--ivory);
  }
  & .wordmark span{color:var(--gold)}
  & .luxe-header .text-link{border-bottom-color:transparent}

  /* ---- hero ----
     The ~20% of empty studio black that used to sit above the chair/lounger is
     trimmed out of hero-new.jpg itself (2560x1710 -> 2560x1530, git history
     carries the original). CSS can't do this job: the untrimmed source was
     1.497:1 against a 1.6:1 desktop box, so object-position had 62px of play at
     1440 and NONE at 390, and object-view-box — which could — is Chromium-only,
     a no-op in WebKit. Don't "fix" the framing here; re-crop the asset. */
  & .hero{position:relative;height:100svh;min-height:640px;display:flex;align-items:flex-end;overflow:hidden}
  & .hero > img{
    position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:center 38%;
    transform:scale(1.07);animation:luxeHeroIn 3.2s cubic-bezier(.19,.65,.25,1) forwards;
  }
  & .hero::before{
    content:'';position:absolute;inset:0;z-index:1;
    /* deepened left+bottom scrim — the new hero's subject sits center-left,
       under the headline, and needs more ink behind the type */
    background:
      linear-gradient(180deg, rgba(15,15,17,.55) 0%, rgba(15,15,17,0) 30%),
      linear-gradient(90deg, rgba(15,15,17,.78) 0%, rgba(15,15,17,.45) 42%, rgba(15,15,17,0) 68%),
      linear-gradient(0deg, rgba(15,15,17,.96) 0%, rgba(15,15,17,.45) 46%, rgba(15,15,17,0) 72%);
  }
  & .hero-content{position:relative;z-index:2;padding:0 var(--pad) clamp(4rem, 10vh, 7.5rem);max-width:1220px;margin:0 auto;width:100%}
  & .hero .eyebrow{display:block;margin-bottom:1.6rem;text-shadow:0 1px 18px rgba(15,15,17,.95),0 0 6px rgba(15,15,17,.8)}
  & .hero p.lede{margin:1.8rem 0 2.6rem;font-size:1.1em}
  & .hero-actions{display:flex;align-items:center;gap:2.4rem;flex-wrap:wrap}
  & .hero-primary{display:inline-flex;flex-direction:column;align-items:flex-start;gap:.7rem}
  & .hero-sub{font-size:.72rem;letter-spacing:.24em;text-transform:uppercase;color:var(--gold);border-bottom:1px solid var(--gold-soft);padding-bottom:.25rem}
  & .hero-sub:hover{color:var(--ivory);border-bottom-color:var(--ivory)}
  @media (max-width:700px){
    & .luxe-header{padding:1rem 1.4rem}
    & .wordmark{font-size:.85rem;letter-spacing:.42em}
    & .luxe-nav{gap:1.2rem}
    & .luxe-header .text-link{font-size:.78rem;letter-spacing:.14em;white-space:nowrap}
    & .hero{height:auto;min-height:100svh;padding-top:6.5rem}
    & h1{font-size:clamp(2.4rem, 10.5vw, 3.2rem)}
    & .eyebrow{letter-spacing:.2em}
    & .hero .eyebrow{margin-bottom:1.1rem}
    & .hero p.lede{margin:1.3rem 0 1.9rem}
    & .hero-actions{gap:1.1rem 1.6rem}
    & .hero-content{padding-bottom:3rem}
    /* the desktop .btn chrome (1.05rem 2.6rem + .32em tracking, uppercase) is
       wider than a phone: "Explore the Technology" wrapped to 2 lines / 83px.
       Scales all three landing .btn instances, not just the hero. */
    & .btn{padding:.85rem 1.4rem;letter-spacing:.14em;font-size:.72rem}
  }

  /* ---- manifesto ---- */
  & .manifesto{
    text-align:center;
    background:radial-gradient(90rem 40rem at 50% -20%, rgba(194,161,94,.13), transparent 60%), var(--ink);
  }
  & .manifesto .display{font-size:clamp(2.2rem, 4.6vw, 3.8rem);max-width:22em;margin:0 auto}
  & .manifesto p{margin:2.4rem auto 0;max-width:38em;color:var(--ivory-60)}
  & .manifesto .gold-dot{color:var(--gold)}
  & .mani-quote{margin-top:clamp(3.2rem,7vh,5rem)}
  /* short gold rule separates the testimonial from the manifesto copy */
  & .mani-quote::before{
    content:'';display:block;width:64px;height:1px;
    background:var(--gold-soft);margin:0 auto clamp(2.4rem,5vh,3.6rem);
  }
  & .mani-quote blockquote{
    font-family:var(--serif);font-style:italic;font-weight:400;
    font-size:clamp(2rem, 4.5vw, 3.2rem);line-height:1.15;color:var(--gold);
    border:none;padding:0;background:none;
  }
  & .mani-quote figcaption{
    margin-top:1.4rem;font-size:.82rem;letter-spacing:.3em;text-transform:uppercase;color:var(--ivory-60);
  }
  & .mani-quote figcaption strong{color:var(--ivory);font-weight:400}

  /* ---- craftsmanship ---- */
  & .craft{display:grid;grid-template-columns:1fr 1fr;gap:clamp(2.5rem,6vw,6rem);align-items:start}
  & .craft-copy h2{margin-bottom:1.6rem}
  & .craft-copy .lede{margin-bottom:3rem}
  & .materials{list-style:none}
  & .materials li{display:grid;grid-template-columns:3.4rem 1fr;gap:1rem;padding:1.7rem 0;border-top:1px solid var(--hairline)}
  & .materials li:last-child{border-bottom:1px solid var(--hairline)}
  & .materials .num{font-family:var(--serif);font-style:italic;font-size:1.15rem;color:var(--gold)}
  & .materials h3{font-family:var(--sans);font-weight:400;font-size:1.15rem;letter-spacing:.14em;text-transform:uppercase;margin-bottom:.45rem}
  & .materials p{font-size:1.05rem;color:var(--ivory-60)}
  /* isolation: the z-index:-1 frame below would otherwise escape to the root
     stacking context and paint UNDER the section's own ivory background once
     .reveal drops its transform — invisible on every cream section. */
  & .craft-visual{position:relative;margin-top:1.5rem;isolation:isolate}
  & .material-crop{position:relative;overflow:hidden;aspect-ratio:4/5}
  & .material-crop img{width:100%;height:100%;object-fit:cover}
  /* frames the IMAGE, not the whole column: bottom:auto + the crop's own 4/5
     ratio stop the offset frame above .craft-caption, which its old
     bottom:-1.4rem let it strike through. */
  & .craft-visual::after{content:'';position:absolute;inset:1.4rem -1.4rem auto 1.4rem;aspect-ratio:4/5;border:1px solid var(--gold-soft);z-index:-1}
  & .craft-caption{margin-top:2.6rem;font-size:.8rem;letter-spacing:.3em;text-transform:uppercase;color:var(--ivory-60)}
  @media (max-width:900px){
    & .craft{grid-template-columns:1fr}
    & .craft-visual{margin:0 1.4rem 1.4rem 0}
  }

  /* ---- flagship (ivory break) ---- */
  & .flagship-grid{display:grid;grid-template-columns:1.05fr .95fr;gap:clamp(2.5rem,6vw,5.5rem);align-items:center}
  /* catalogue plate — transparent cutout floats on ivory at native size (425px source) */
  & .flagship-plate{text-align:center;padding:clamp(.5rem,2vw,2rem)}
  & .flagship-plate img{width:min(100%,425px);margin:0 auto}
  & .flagship-copy h2{margin-bottom:.55rem}
  /* the flagship tagline sits between the name and the body — serif so it reads as
     display voice, gold-role because raw --gold is illegal on ivory */
  & .flagship-copy .tagline{font-family:var(--serif);font-style:italic;font-size:clamp(1.25rem,2vw,1.55rem);color:var(--gold-role);margin-bottom:1.4rem}
  & .spec{list-style:none;margin:2.8rem 0}
  & .spec li{display:flex;justify-content:space-between;gap:2rem;padding:1.15rem 0;border-top:1px solid var(--hairline-ink);font-size:1.05rem}
  & .spec li:last-child{border-bottom:1px solid var(--hairline-ink)}
  & .spec .k{letter-spacing:.16em;text-transform:uppercase;font-size:.85rem;font-weight:400;color:var(--ink-soft);padding-top:.15rem}
  & .spec .v{text-align:right;font-weight:400}
  & .price-line{display:flex;align-items:baseline;gap:1.4rem;flex-wrap:wrap;margin-bottom:2.2rem}
  & .price-line .price{font-family:var(--serif);font-weight:400;font-size:2rem}
  & .price-line .from{font-size:.8rem;letter-spacing:.3em;text-transform:uppercase;color:var(--ink-soft)}
  & .price-line .from b{font-weight:inherit;color:var(--gold-ink)}
  & .price-line .links{flex-basis:100%;display:flex;gap:1.6rem;flex-wrap:wrap;margin-top:.4rem}
  & .price-line .links .text-link{font-size:.8rem;letter-spacing:.18em}

  /* elite card */
  & .elite{margin-top:clamp(4rem, 9vh, 7rem);display:grid;grid-template-columns:.95fr 1.05fr;background:var(--ink);color:var(--ivory)}
  & .elite-img{position:relative;min-height:480px}
  & .elite-img img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:center 94%}
  & .elite-copy{padding:clamp(2.4rem,5vw,4.5rem)}
  & .elite-copy .eyebrow{display:block;margin-bottom:1.4rem;color:var(--gold)}
  & .elite-copy h3{font-family:var(--serif);font-weight:300;font-size:clamp(1.9rem,3.4vw,2.9rem);line-height:1.15;margin-bottom:1.3rem}
  & .elite-copy p{color:var(--ivory-60);font-size:1.05rem;margin-bottom:1.1rem}
  & .elite-price{font-family:var(--serif);font-size:1.55rem;font-weight:400;margin:1.6rem 0 2rem;color:var(--ivory)}
  /* the price note is a full sentence now, not a two-word tag — tracked-out uppercase
     would run it off the card, so it keeps sentence case and wraps under the price */
  & .elite-price .from{font-family:var(--sans);font-size:.8rem;letter-spacing:.3em;text-transform:uppercase;color:var(--ivory-60);margin-left:1rem;border-bottom:1px solid var(--hairline);padding-bottom:.2rem;white-space:nowrap}
  & .elite-price .from b{font-weight:inherit;color:var(--gold)}
  & .elite-price .from:hover{color:var(--gold);border-bottom-color:var(--gold-soft)}
  & .elite-price small{display:block;font-family:var(--sans);letter-spacing:.02em;color:var(--ivory-60);margin-top:.5rem;font-size:.95rem;line-height:1.5}
  @media (max-width:900px){
    & .flagship-grid{grid-template-columns:1fr}
    & .elite{grid-template-columns:1fr}
  }
  /* Phones: stack the spec rows (label over value, left-aligned) — the
     right-aligned value was wrapping ragged against the edge. (2026-07-15) */
  @media (max-width:540px){
    & .spec li{flex-direction:column;gap:.3rem}
    & .spec .v{text-align:left}
  }

  /* ---- stack ---- */
  & .stack-head{max-width:44em}
  & .stack-head h2{margin-bottom:1.6rem}
  & .inline-link{color:var(--gold);border-bottom:1px solid var(--gold-soft)}
  & .inline-link:hover{border-bottom-color:var(--gold)}
  & .stack-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:2.2rem;margin-top:clamp(3rem,7vh,5rem)}
  & .stack-grid article{border-top:1px solid var(--hairline);padding-top:1.6rem}
  & .stack-grid .num{font-family:var(--serif);font-style:italic;color:var(--gold-role);font-size:1.1rem;display:block;margin-bottom:1.1rem}
  & .stack-grid h3{font-family:var(--sans);font-weight:400;font-size:1.15rem;letter-spacing:.16em;text-transform:uppercase;margin-bottom:.6rem}
  & .stack-grid p{font-size:1.05rem;color:var(--ivory-60)}
  @media (max-width:900px){& .stack-grid{grid-template-columns:1fr 1fr}}
  @media (max-width:540px){& .stack-grid{grid-template-columns:1fr}}

  /* ---- evidence (catalogue numbers row + qualified footing) ---- */
  & .evidence-foot{margin-top:clamp(2.6rem,6vh,4rem)}
  & .evidence-foot .micro{
    margin-top:1.6rem;font-size:.85rem;line-height:1.7;letter-spacing:.02em;
    color:var(--ivory-60);max-width:52em;
  }

  /* ---- white-glove ---- */
  & .glove{position:relative;overflow:hidden;padding:0}
  & .glove img.bg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:78% center}
  & .glove::before{content:'';position:absolute;inset:0;background:linear-gradient(90deg, rgba(15,15,17,.98) 0%, rgba(15,15,17,.94) 48%, rgba(15,15,17,.3) 78%, rgba(15,15,17,.05) 100%)}
  & .glove-inner{position:relative;z-index:2;max-width:1220px;margin:0 auto;padding:clamp(6rem,14vh,11rem) var(--pad)}
  & .glove-inner .eyebrow{display:block;margin-bottom:1.6rem}
  & .glove-inner h2{max-width:12em;margin-bottom:1.4rem}
  & .glove-inner .lede{margin-bottom:3.4rem;max-width:26em}
  & .glove-list{
    list-style:none;max-width:600px;background:rgba(15,15,17,.5);
    backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
    padding:.4rem 1.8rem;border:1px solid rgba(241,236,226,.08);
  }
  /* items scaled ~10% (Logan 2026-08-06) — the four rows left dead space above
     and below inside the section. Every value below is its old value x1.1. */
  & .glove-list li{border-top:1px solid var(--hairline);padding:1.54rem 0;display:grid;grid-template-columns:3.74rem 1fr;gap:1.1rem}
  & .glove-list li:last-child{border-bottom:1px solid var(--hairline)}
  & .glove-list .num{font-family:var(--serif);font-style:italic;color:var(--gold);font-size:1.21rem}
  & .glove-list h3{font-weight:400;font-size:1.265rem;letter-spacing:.15em;text-transform:uppercase;margin-bottom:.385rem}
  & .glove-list p{font-size:1.155rem;color:var(--ivory-60)}
  @media (max-width:900px){
    & .glove img.bg{opacity:.35}
    & .glove::before{background:var(--ink-soft)}
  }

  /* ---- practices (ivory break — see .light block for color roles) ---- */
  & .practices-grid{display:grid;grid-template-columns:1fr 1fr;gap:clamp(2.5rem,6vw,6rem);align-items:start}
  & .practices h2{margin-bottom:1.6rem}
  & .practices .lede{margin-bottom:2.6rem}
  @media (max-width:900px){& .practices-grid{grid-template-columns:1fr}}

  /* ---- roi ---- dark card on the creme ground (Steven's mockup); the widget's own
     max-width/padding defer to .container so it lines up with the other light sections */
  & .roi{scroll-margin-top:2rem}
  & .roi .pulse-roi{max-width:none;padding:0}

  /* ---- finale ---- */
  & .finale{
    text-align:center;
    background:radial-gradient(90rem 40rem at 50% 120%, rgba(194,161,94,.13), transparent 60%), var(--ink);
    border-top:1px solid var(--hairline);
  }
  & .finale h2{font-size:clamp(2.6rem, 6vw, 4.8rem);margin-bottom:1.6rem}
  & .finale .lede{margin:0 auto 3rem}
  /* Restored: the client removed this line from the HOMEPAGE finale only (T7 deleted
     the rule with it), but the equine finale still carries it. */
  & .finale .micro{margin-top:2.6rem;font-size:.8rem;letter-spacing:.3em;text-transform:uppercase;color:var(--ivory-60)}

  /* ---- footer ---- */
  & .luxe-footer{
    border-top:1px solid var(--hairline);padding:2.6rem var(--pad);
    display:flex;justify-content:space-between;align-items:center;gap:1.5rem;flex-wrap:wrap;
    font-size:.8rem;letter-spacing:.28em;text-transform:uppercase;color:var(--ivory-60);
  }
  & .luxe-footer nav{display:flex;gap:1.8rem;flex-wrap:wrap}

  /* ---- equine page (template-luxe-equine.php) ---- */
  & .hero.equine > img{object-position:38% center}
  @media (max-width:700px){
    & .hero.equine > img{object-position:66% center}
    /* Drop the desktop line-break so the headline wraps naturally instead of
       orphaning "can't" on its own line. (2026-07-15) */
    & .hero.equine h1 br{display:none}
  }
  & .split{display:grid;grid-template-columns:1fr 1fr;gap:clamp(2.5rem,6vw,6rem);align-items:center}
  & .split.rev > .visual{order:2}
  /* Split headings sit in a ~570px column, so they take a smaller display size than
     the full-measure h2s. The client's two-sentence barn/craft headlines broke into
     4 near-single-word lines at the base clamp. (.split is equine-only.) */
  & .split h2{margin-bottom:1.6rem;font-size:clamp(2.2rem, 3.4vw, 3rem)}
  /* The equine craft body is three stacked paragraphs — 2.6rem between them reads
     as three separate blocks, so only the last one keeps the run-out gap. */
  & .split .lede{margin-bottom:1.3rem}
  & .split .lede:last-of-type{margin-bottom:2.6rem}
  /* isolation: the ::after frame below is z-index:-1, and .visual carries
     .reveal — whose transform makes a stacking context only UNTIL the reveal
     finishes (transform:none when .in). Without isolate the frame escapes to
     the root context on completion and paints under the section's own opaque
     ground, so it silently stops existing. Same fix as .craft-visual. */
  & .visual{position:relative;isolation:isolate}
  & .visual img{width:100%}
  & .visual::after{content:'';position:absolute;inset:1.4rem -1.4rem -1.4rem 1.4rem;border:1px solid var(--gold-soft);z-index:-1}
  @media (max-width:900px){
    & .split{grid-template-columns:1fr}
    & .split.rev > .visual{order:0}
    & .visual{margin:0 1.4rem 1.4rem 0}
  }
  & .benefits{list-style:none;display:grid;grid-template-columns:1fr 1fr;gap:0 clamp(1.5rem,3vw,3rem)}
  & .benefits li{border-top:1px solid var(--hairline);padding:.9rem 0;font-size:.95rem;letter-spacing:.16em;
    text-transform:uppercase;font-weight:400;color:var(--ivory-60)}
  & .benefits li::before{content:'';display:inline-block;width:1.3rem;height:1px;background:var(--gold-soft);
    margin-right:1rem;vertical-align:middle}
  @media (max-width:540px){& .benefits{grid-template-columns:1fr}}
  & .stats{display:grid;grid-template-columns:repeat(4,1fr);gap:2rem;margin-top:clamp(3.5rem,8vh,5.5rem);
    border-top:1px solid var(--hairline);padding-top:3rem}
  & .stats .n{font-family:var(--serif);font-weight:300;font-size:clamp(2.6rem,4.5vw,4.2rem);color:var(--gold);line-height:1}
  & .stats .l{margin-top:.9rem;font-size:.8rem;letter-spacing:.24em;text-transform:uppercase;color:var(--ivory-60)}
  @media (max-width:900px){& .stats{grid-template-columns:1fr 1fr;gap:2.8rem 2rem}}
  & .glove-row{display:grid;grid-template-columns:repeat(3,1fr);gap:2.2rem;margin-top:clamp(3rem,7vh,5rem)}
  & .glove-row article{border-top:1px solid var(--hairline);padding-top:1.6rem}
  & .glove-row .num{font-family:var(--serif);font-style:italic;color:var(--gold-role);font-size:1.1rem;display:block;margin-bottom:1.1rem}
  & .glove-row h3{font-weight:400;font-size:1.15rem;letter-spacing:.16em;text-transform:uppercase;margin-bottom:.6rem}
  & .glove-row p{font-size:1.05rem;color:var(--ivory-60)}
  @media (max-width:900px){& .glove-row{grid-template-columns:1fr}}
  & .personas{margin-top:clamp(3rem,7vh,4.5rem);display:flex;flex-wrap:wrap;justify-content:space-between;gap:1rem 0;
    border-top:1px solid var(--hairline);padding-top:2.4rem}
  & .personas span{font-size:.88rem;letter-spacing:.2em;text-transform:uppercase;color:var(--ivory-60);
    padding:.2rem 1rem;border-left:1px solid var(--hairline)}
  & .personas span:first-child{border-left:0;padding-left:0}
  /* Phones: keep the vertical grey bars, one item per line (full-width column)
     so nothing pairs up or overflows — and give the first item its bar too. (2026-07-15) */
  @media (max-width:540px){
    & .personas{flex-direction:column;gap:1rem}
    & .personas span,
    & .personas span:first-child{border-left:1px solid var(--hairline);padding:.15rem 0 .15rem 1.1rem}
  }
  /* light-section variants for equine splits */
  & .light .benefits li{color:var(--ink-soft);border-top-color:var(--hairline-ink)}
  & .light .benefits li::before{background:var(--gold-ink)}
  /* gold-soft is 1.49:1 on ivory (invisible) and --hairline-ink is worse at
     1.42:1 — solid --gold-ink (4.87:1) is the only visible option that keeps
     the accent gold. Matches .craft-visual on the homepage. */
  & .light .visual::after{border-color:var(--gold-ink)}

  /* ---- reveals ---- */
  & .reveal{opacity:0;transform:translateY(28px);transition:opacity 1s ease, transform 1.1s cubic-bezier(.19,.65,.25,1)}
  & .reveal.in{opacity:1;transform:none}
  & .stagger > *{opacity:0;transform:translateY(24px);transition:opacity .9s ease, transform 1s cubic-bezier(.19,.65,.25,1)}
  & .stagger.in > *{opacity:1;transform:none}
  & .stagger.in > *:nth-child(2){transition-delay:.12s}
  & .stagger.in > *:nth-child(3){transition-delay:.24s}
  & .stagger.in > *:nth-child(4){transition-delay:.36s}
  & .stagger.in > *:nth-child(5){transition-delay:.48s}
  & .hero-content > *{opacity:0;transform:translateY(26px);animation:luxeRise 1.2s cubic-bezier(.19,.65,.25,1) forwards}
  & .hero-content > *:nth-child(2){animation-delay:.18s}
  & .hero-content > *:nth-child(3){animation-delay:.36s}
  & .hero-content > *:nth-child(4){animation-delay:.54s}

  @media (prefers-reduced-motion: reduce){
    & .hero > img{animation:none;transform:none}
    & .hero-content > *{animation:none;opacity:1;transform:none}
    & .reveal,& .stagger > *{opacity:1;transform:none;transition:none}
  }

  /* ---- grain ---- */
  & .grain{
    position:fixed;inset:0;z-index:90;pointer-events:none;opacity:.05;
    background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)' opacity='0.7'/%3E%3C/svg%3E");
  }
}

/* ============================================================
   cart goes paper (0.7.6, 2026-07-30) — the cart is the third
   stop on the ivory writing flow: builder → cart → checkout.
   `.woocommerce-cart` is a class ON <body> in this theme (never
   descend into it). Same .light law as checkout/builder: --gold-ink
   is gold's only voice on ivory; gold-face buttons are the money
   action only. Site header/footer stay ink (already unconditional
   dark globally, no re-assertion needed here). */
body.woocommerce-cart{background:var(--ivory);color:var(--ink)}

/* headings + links inside the content column only — #content is an
   ID, so this safely out-specifies every dark default without
   !important and without touching header/footer (they're outside
   #content's ink-scoped rules anyway) */
body.woocommerce-cart #content h1,
body.woocommerce-cart #content h2,
body.woocommerce-cart #content h3{color:var(--ink);font-family:var(--serif);font-weight:300}
body.woocommerce-cart #content a{color:var(--ink)}
body.woocommerce-cart #content a:hover{color:var(--gold-ink)}
/* the Cart title carries the same hairline every other heading on the paper
   surfaces does (.cart_totals > h2 below, cross-sells, the drawer header) —
   it was the one heading sitting naked above its sheet (Logan 2026-08-06).
   Same 1px var(--line) the h2 rule states; the .5rem of padding is the only
   addition, buying the 40px serif's descenders the clearance the 30px h2
   doesn't need. Type size untouched — Logan: "text is fine". */
body.woocommerce-cart #content h1.entry-title{
  padding-bottom:.5rem;
  border-bottom:1px solid var(--line);
}

/* cart items table — hairline-ink frame + rows; body text ink-soft
   (mirrors the dark table's own ivory-60-for-everything hierarchy),
   product name promoted to full ink same as a link would be */
body.woocommerce-cart table.shop_table{border-color:var(--hairline-ink);background:transparent}
/* items table + coupon/update-cart row (same <table>, .actions is its last
   row) onto its own #fff card — matches checkout's two sheets and cart
   totals below. table.cart out-specifies the transparent rule above.
   Gold top border is the site's standing card/notice accent (same recipe
   as the woo-notice band above it and cart_totals' order-total row below)
   — the plain hairline-ink border alone reads cold on white where it read
   warm against ivory, which is the "gold accent" that felt lost (Logan,
   2026-08-04). */
body.woocommerce-cart table.cart.shop_table{background:#fff;border-top:2px solid var(--gold)}
body.woocommerce-cart table.shop_table td,
body.woocommerce-cart table.shop_table th{color:var(--ink-soft)}
/* line 423's border-color carries !important — counter in kind */
body.woocommerce-cart table.shop_table td,
body.woocommerce-cart table.shop_table th{border-color:var(--hairline-ink) !important}
body.woocommerce-cart table.shop_table .product-name a{color:var(--ink)}
body.woocommerce-cart table.shop_table .product-name a:hover{color:var(--gold-ink)}

/* quantity stepper — #fff/hairline-ink/ink. table.shop_table added to the
   selector to out-specify line 429's 4-class `.woocommerce table.shop_table
   .quantity .qty` (which otherwise beats a 3-class selector regardless of
   file order) */
body.woocommerce-cart table.shop_table .quantity .qty{background:#fff;border:1px solid var(--hairline-ink);color:var(--ink)}
body.woocommerce-cart .quantity .minus,
body.woocommerce-cart .quantity .plus{background:transparent;border:1px solid var(--hairline-ink);color:var(--ink-soft)}

/* remove-item × — paper voice but ROUND (Logan 2026-08-05 walked back the
   0.7.x flatten: "bring back the radial remove buttons"). WC core ships the
   glyph 30px/700 in the 32px circle (faux-bold, off-center vs the border) —
   24px circle, 1rem/400 glyph, line-height = height minus the 2px of border. */
body.woocommerce-cart .woocommerce-cart-form a.remove{
  color:var(--ink-soft) !important;border:1px solid var(--hairline-ink) !important;
  border-radius:50% !important;background:transparent !important;
  width:24px;height:24px;line-height:22px;font-size:1rem;font-weight:400;text-align:center;
}
body.woocommerce-cart .woocommerce-cart-form a.remove:hover{
  color:var(--gold-ink) !important;border-color:var(--gold-ink) !important;background:transparent !important;
}

/* coupon field — same fields-on-paper law as checkout. WC core squashes the
   cart coupon input to width:80px (td.actions .coupon .input-text) — give it
   the sheet's 44px/1rem field spec at a usable width (Logan 2026-08-05). */
body.woocommerce-cart #coupon_code{
  background:#fff;border:1px solid var(--hairline-ink);color:var(--ink);
  width:240px !important;font-size:1rem;line-height:1.4;padding:.6em .9em;height:auto;
}
body.woocommerce-cart #coupon_code::placeholder{color:var(--ink-soft)}

/* secondary buttons: coupon Apply, Update cart, empty-cart Return to
   shop, the notice's View cart link — all plain .woocommerce a/button.button.
   Dark hover (gold face + ink text, lines 110-121) is ALREADY the correct
   paper-secondary hover, so only the resting color/border need restating. */
body.woocommerce-cart .woocommerce a.button,
body.woocommerce-cart .woocommerce button.button,
body.woocommerce-cart .woocommerce input.button{color:var(--ink);border-color:var(--hairline-ink)}
/* Astra's WooCommerce-customizer CSS injects a cart-specific border rule
   with an #content-ID variant (`.woocommerce-page #content table.cart
   td.actions .button{border-color:gold}`) — an ID beats any class-only
   selector outright, so match the ID tier to win */
body.woocommerce-cart #content table.cart td.actions .button{border-color:var(--hairline-ink)}
/* Update cart — disabled vs enabled now actually look different. Root
   cause of "still too faint" (Logan, 2026-08-04): WooCommerce/Astra's core
   button:disabled already sets opacity:.5, which was compounding with our
   ink-soft (.62 alpha) fix underneath it — net ~.31 effective alpha, barely
   readable. opacity:1 here stops the double-fade; ink-soft alone is the
   correct legible-but-inactive voice. cursor:not-allowed is the browser's
   disabled-button default, no rule needed for it.
   Enabled = the row's actual next action once a qty changes, so it joins
   the primary-CTA gold family (same recipe as Proceed to Checkout below)
   rather than staying a secondary-button grey like Apply Coupon. */
body.woocommerce-cart .woocommerce-cart-form button[name="update_cart"]:disabled{
  opacity:1;background:transparent;border-color:var(--hairline-ink);color:var(--ink-soft);
}
/* border-color !important: the #content/table/td chain two rules up
   out-elements this selector (equal ID+class score, more type selectors
   wins the tiebreak) — same fight as a.remove below, same weapon. */
body.woocommerce-cart .woocommerce-cart-form button[name="update_cart"]:not(:disabled){
  background:var(--gold);border-color:var(--gold) !important;color:var(--ink);
}
body.woocommerce-cart .woocommerce-cart-form button[name="update_cart"]:not(:disabled):hover{
  background:transparent;border-color:var(--gold-ink) !important;color:var(--gold-ink);
}

/* "Forgot something? Browse all products" pulse banner — the plugin
   prints an inline-styled pill caught globally by a[href*="resume=browse"]
   with !important on every color channel (lines 322-339); counter in
   kind. Its hover (gold face/ink text/gold border) is already correct
   paper-secondary-hover, so it's left alone. */
body.woocommerce-cart .woocommerce a[href*="resume=browse"]{
  background:transparent !important;color:var(--ink) !important;border-color:var(--hairline-ink) !important;
}

/* cart totals panel — white sheet w/ hairline-ink, matching the
   checkout order-review sheet's voice. Totals text is ink (a step up
   from the item table's ink-soft — this is the number the customer
   is here to read). */
body.woocommerce-cart .cart-collaterals .cart_totals{
  background:#fff;border:1px solid var(--hairline-ink);
  /* the sheet never had padding — content ran edge to edge (Logan 2026-08-05) */
  padding:2.2rem 2rem;box-sizing:border-box;float:none;width:100%;
}
/* "Taxes and shipping calculated at the next step" note — the plugin prints
   it with inline color:#666, which the dark-era p[style*="color:#666"]
   neutralizer repaints ivory-60 !important — invisible on this white sheet.
   Counter in kind; ties its (0,2,2) and wins on source order. */
body.woocommerce-cart .cart_totals p{color:var(--ink-soft) !important}
/* cart type steps up ~10% and money reads INK (Logan round 2: prices and
   subtotals were Cormorant 300-weight at ink-soft — thin AND faded) */
body.woocommerce-cart table.shop_table thead th{font-size:.9rem}
body.woocommerce-cart table.shop_table td.product-name a{font-size:1.15rem}
body.woocommerce-cart table.shop_table td .woocommerce-Price-amount{
  font-size:1.35rem;font-weight:400;color:var(--ink);
}
/* totals sidebar rows — same step-up as the checkout tfoot. Extra
   table.shop_table hop: WC's ".woocommerce table.shop_table tbody th" is
   (0,2,3) and re-bolds at plain .cart_totals th specificity. */
body.woocommerce-cart .cart_totals table.shop_table th{font-size:.95rem;font-weight:400;letter-spacing:.14em}
body.woocommerce-cart .cart_totals td .woocommerce-Price-amount{font-size:1.25rem;font-weight:400;color:var(--ink)}
/* smallscreen: WC stacks the table; the coupon pair was a fixed-240px input
   against a floated button (Logan: "offset lol") — stack both full-width */
@media (max-width:768px){
  body.woocommerce-cart td.actions .coupon #coupon_code{width:100% !important;margin:0 0 .6rem}
  /* #content restated: WC smallscreen's own coupon rule carries that ID
     and pins the button to 48% otherwise */
  body.woocommerce-cart #content table.cart td.actions .coupon .button{width:100%;float:none}
}
/* stacked-row labels ("Product:", "Price:", ...) — WC smallscreen renders
   them as td::before at font-weight:700: synthesized fake-bold on 300–500
   Jost, which reads as a different font and "snaps" on webfont swap (Logan
   2026-08-05). Eyebrow voice instead; specificity matches WC's (0,2,3). */
@media (max-width:768px){
  body:not(.luxe-landing) table.shop_table td::before{
    font-weight:400;font-size:.85rem;letter-spacing:.14em;text-transform:uppercase;color:var(--fg-soft);
  }
  /* stacked rows had no boundary between records (cart items, orders) —
     one hairline + breathing room per stacked row group */
  body:not(.luxe-landing) table.shop_table.shop_table_responsive tbody tr,
  body:not(.luxe-landing) table.my_account_orders tbody tr{
    display:block;border-bottom:1px solid var(--line);padding:.5rem 0;
  }
  /* WC smallscreen zebra bands the stacked cells of ONE record in two
     colors — patchy; flat cells, the hairline above is the separator */
  body:not(.luxe-landing) .woocommerce table.shop_table_responsive tr td,
  body:not(.luxe-landing) .woocommerce-page table.shop_table_responsive tr td{background-color:transparent}
}
/* totals ride BESIDE the cart table as a sidebar, not below it (Logan
   2026-08-05) — same grid shape as the checkout sheet. Notices span both
   columns so an error doesn't wedge into the first cell. */
@media (min-width:800px){
  body.woocommerce-cart:not(.luxe-landing) .ast-container{max-width:1440px}
  body.woocommerce-cart .entry-content > .woocommerce{
    display:grid;grid-template-columns:1fr minmax(300px,380px);
    column-gap:2.5rem;align-items:start;
  }
  body.woocommerce-cart .entry-content > .woocommerce > .woocommerce-notices-wrapper{grid-column:1 / -1}
  body.woocommerce-cart .woocommerce-cart-form{grid-column:1}
  body.woocommerce-cart .cart-collaterals{grid-column:2;width:100%}
}
body.woocommerce-cart .cart-collaterals .cart_totals>h2,
body.woocommerce-cart .cart-collaterals .cross-sells>h2{border-bottom-color:var(--hairline-ink)}
body.woocommerce-cart .cart_totals table.shop_table td,
body.woocommerce-cart .cart_totals table.shop_table th{color:var(--ink)}
body.woocommerce-cart .cart_totals table.shop_table tr.order-total th,
body.woocommerce-cart .cart_totals table.shop_table tr.order-total td{border-top:1px solid var(--gold)}
body.woocommerce-cart .pulse-cart-note{color:var(--ink-soft)}

/* Proceed to checkout — THE money action. More specific than the
   secondary-button rule above (body+a element beats body+.woocommerce+a
   at equal class count) so it wins on its own; order still puts it
   after for a clean tie-break either way. */
body.woocommerce-cart .wc-proceed-to-checkout a.checkout-button{
  background:var(--gold);border-color:var(--gold);color:var(--ink);
}
body.woocommerce-cart .wc-proceed-to-checkout a.checkout-button:hover{
  background:transparent;border-color:var(--gold-ink);color:var(--gold-ink);
}

/* Woo notices — "added to cart" message + the empty-cart .cart-empty
   (which is itself a .woocommerce-info) — canonical paper-notice recipe */
body.woocommerce-cart .woocommerce-message,
body.woocommerce-cart .woocommerce-info,
body.woocommerce-cart .woocommerce-error{
  background-color:#fff;border:1px solid var(--hairline-ink);border-top:2px solid var(--gold);color:var(--ink-soft);
}
body.woocommerce-cart .woocommerce-message::before,
body.woocommerce-cart .woocommerce-info::before{color:var(--gold-ink)}

/* AJAX blockUI overlay (qty/coupon updates) — paper, not the global ink !important */
body.woocommerce-cart .blockUI.blockOverlay{background:var(--ivory) !important}

/* plugin-era inline-navy signature catch (staging runs original
   plugins with inline styles; local runs de-skinned — cover both) */
body.woocommerce-cart a[style*="#16435F"]{color:var(--ink-soft) !important}
body.woocommerce-cart a[style*="#16435F"]:hover{color:var(--gold-ink) !important}

/* cross-sells loop — not present for every cart (needs configured
   cross-sell products), styled defensively; reuses the single-product
   related-loop treatment with !important since this loop can inherit
   the pulse-products/product_type_* !important fights from other scopes */
body.woocommerce-cart .cross-sells ul.products li.product .woocommerce-loop-product__title{color:var(--ink) !important}
body.woocommerce-cart .cross-sells ul.products li.product .price{color:var(--ink-soft) !important}
body.woocommerce-cart .cross-sells ul.products li.product a.button,
body.woocommerce-cart .cross-sells ul.products li.product a.add_to_cart_button,
body.woocommerce-cart .cross-sells ul.products li.product a.product_type_simple,
body.woocommerce-cart .cross-sells ul.products li.product a.product_type_variable,
body.woocommerce-cart .cross-sells ul.products li.product a.product_type_grouped{
  border-color:var(--hairline-ink) !important;color:var(--ink) !important;background:transparent !important;
}
body.woocommerce-cart .cross-sells ul.products li.product a.button:hover,
body.woocommerce-cart .cross-sells ul.products li.product a.add_to_cart_button:hover,
body.woocommerce-cart .cross-sells ul.products li.product a.product_type_simple:hover,
body.woocommerce-cart .cross-sells ul.products li.product a.product_type_variable:hover,
body.woocommerce-cart .cross-sells ul.products li.product a.product_type_grouped:hover{
  background:var(--gold) !important;border-color:var(--gold) !important;color:var(--ink) !important;
}

/* ---- get-started goes paper (0.7.6, Logan 2026-07-30) ----
   The one true entry chooser (/get-started/, page-id-224) joins the ivory
   writing flow so it stops looking like a dead end before the paper builder
   it leads into. Base .pulse-choose/.pc-* rules live in WP Additional CSS
   (wp-custom-css, printed straight into <head> — see the "Customizer post
   595 neutralizers" note above) which loads AFTER this stylesheet, so ties
   go to the customizer; every property below needs a selector at least as
   specific as body.page-id-224 to win on specificity alone, and !important
   only where matching an already-!important dark rule below. Site header/
   footer stay ink (body:not(.luxe-landing) rules already cover them). */
body.page-id-224{background:var(--ivory);color:var(--ink)}
/* .pulse-choose's own clamp(2.5rem,5vw,4.5rem) top padding (customizer CSS)
   stacks on top of Astra's article.ast-article-single padding-top:106.8px —
   the same 106.8px every single-page template (cart, checkout) already gets
   for free. That doubling is the huge empty band above the h1; killing just
   the top side here matches get-started's rhythm to cart/checkout exactly
   (h1 lands at the same viewport y on both). Horizontal + bottom padding
   untouched — this is a top-only offset bug, not a spacing redesign. */
body.page-id-224 .pulse-choose{padding-top:0}
/* v0.7.25: Logan wants get-started pulled up further than the cart/checkout
   baseline above — the h1 should land a small beat below the back-link row,
   not a full article-padding's worth. Collapses the #primary padding-top:
   106.8px restored above (get-started only; cart/checkout keep it, this
   page is a decision screen not a content page). 0.8.1: retargeted from
   the dead article.ast-article-single selector (see the restore comment
   above #primary's rule) to #primary itself. */
body.page-id-224 #primary{padding-top:1.5rem !important}
body.page-id-224 .pulse-choose h1{color:var(--ink)}
body.page-id-224 .pulse-choose .pc-intro,
body.page-id-224 .pulse-choose .pc-meta{color:var(--ink-soft)}
body.page-id-224 .pulse-choose .pc-meta a{color:var(--ink)}
body.page-id-224 .pulse-choose .pc-meta a:hover{color:var(--gold-ink)}
/* cards — transparent on the ivory ground with a hairline-ink frame, same
   treatment as the builder's analogous .pulse-hero-card pair; the
   RECOMMENDED card keeps its gold-soft border (border-only, legal on paper) */
body.page-id-224 .pulse-choose .pc-card{background:transparent;border-color:var(--hairline-ink)}
body.page-id-224 .pulse-choose .pc-card h2{color:var(--ink)}
body.page-id-224 .pulse-choose .pc-card p{color:var(--ink-soft)}
body.page-id-224 .pulse-choose .pc-eyebrow{color:var(--gold-ink)}
/* RECOMMENDED gets a filled chip — same solid-gold-face vocabulary as the
   CTA button below it — so it reads as a badge at a glance instead of
   blending into the plain-text "Self-Service" eyebrow next to it. */
body.page-id-224 .pulse-choose .pc-rec .pc-eyebrow{
  background:var(--gold);color:var(--ink);padding:.3rem .6rem;display:inline-block;
  /* DELIBERATE no-box-shadow exception — Logan's call, 2026-08-04, scoped to
     the chip + the recommended card (.pc-rec below). Do not strip on a
     future design-law audit. */
  box-shadow:0 0 14px rgba(194,161,94,.4);
}
/* card-scale glow needs a bigger blur / lower alpha than the chip's or it
   reads as a sticker — this should lift the card off the paper, not ring it. */
body.page-id-224 .pulse-choose .pc-rec{box-shadow:0 0 28px rgba(194,161,94,.28)}
/* roman-numeral step list */
body.page-id-224 .pulse-choose .pc-steps li{color:var(--ink-soft);border-top-color:var(--hairline-ink)}
body.page-id-224 .pulse-choose .pc-steps li:last-child{border-bottom-color:var(--hairline-ink)}
body.page-id-224 .pulse-choose .pc-steps li::before{color:var(--gold-ink)}
/* CTAs: RECOMMENDED card = money action (gold face), the self-service
   card = secondary (hairline-ink outline). Countering the dark pc-cta base
   and the !important pc-cta:hover rule above IN KIND (same selector shape,
   later in file). */
body.page-id-224 .pulse-choose .pc-rec .pc-cta{
  background:var(--gold);border-color:var(--gold);color:var(--ink);
}
body.page-id-224 .pulse-choose .pc-card:not(.pc-rec) .pc-cta{
  background:transparent;border-color:var(--hairline-ink);color:var(--ink);
}
/* no .pc-card:hover .pc-cta rule here on purpose — the dark-mode block
   above already learned this lesson (see "hover belongs to the buttons,
   not the whole card" a few hundred lines up): a card-wide :hover on the
   CTA is what made the RECOMMENDED card's button visibly react to a
   hover anywhere in the card, while the self-service card's identical
   resting/hover values made it look like nothing happened. Direct
   .pc-cta:hover below is the only hover state either card gets. */
body.page-id-224 .pulse-choose .pc-rec .pc-cta:hover{
  background:transparent !important;border-color:var(--gold-ink) !important;color:var(--gold-ink) !important;
}
body.page-id-224 .pulse-choose .pc-card:not(.pc-rec) .pc-cta:hover{
  background:var(--gold) !important;border-color:var(--gold) !important;color:var(--ink) !important;
}
body.page-id-224 .pulse-choose .pc-alt{color:var(--ink-soft)}
body.page-id-224 .pulse-choose .pc-alt:hover{color:var(--gold-ink)}

/* ---- store notice unified (home treatment site-wide) ----
   The luxe-scoped bottom-pin above was widened to `body` (edit, not a new
   rule — see that block's comment). What's new here: Astra's store-notice
   JS still assumes the notice hangs over the top and reserves room for it by
   writing an inline `padding-top` onto <body> (class
   .ast-woocommerce-store-notice-hanged, ~57-60px depending on wrap). Now that
   the notice is fixed-bottom everywhere, that reserved space is dead — kill
   it so no gap opens above the header. !important beats the inline style. */
body.ast-woocommerce-store-notice-hanged{padding-top:0 !important}
/* ---- the builder's fixed bottom bars (2026-08-27) ----
   The package-builder plugin prints two position:fixed;bottom:0;z-index:100
   bars: .pulse-back-to-builder (product pages reached with ?from=builder) and
   .pulse-sticky-footer (the builder itself). Being fixed, neither reserves any
   space, so each sits on top of whatever ends the document.
   --pulse-fixed-bar-h is measured and published by the inline script in
   functions.php (CSS cannot measure a fixed element). Reserving it here as
   page padding is what stops the bar burying the footer; the store notice
   above rides the same value to stack above the bar rather than behind it.
   This replaces two hand-measured pixel constants (64px desktop / 96px under
   540px) that only ever knew about .pulse-sticky-footer — .pulse-back-to-builder
   was never in that selector, so the notice sat behind it on product pages. */
/* `html body`, not `body`: WordPress core prints global-styles-inline-css —
   which carries a bare `body{padding:0}` — inside <body>, so it lands after
   every head stylesheet and wins the source-order tiebreak against an equal
   specificity selector. It is emitted on some routes and not others (present
   on /build/, absent on a plain product page), so a bare `body` here fixed the
   product page and silently did nothing on the builder. Two element selectors
   outrank one; no !important needed. */
html body{padding-bottom:var(--pulse-fixed-bar-h,0px)}

/* ---- slim store header to home proportions (0.7.8, Logan 2026-07-30) ----
   Astra inlines min-height:100px on the bar + inner wrap + a line-height:100px
   on the woo-cart element; kill all three and let 1.1rem padding set the height,
   matching the luxe header's 1.25rem-around-a-.95rem-wordmark proportions. */
/* The store header IS the luxe header (0.7.10, Logan): fixed, smoky ink
   glass (the .scrolled treatment, permanent — store pages always have
   content behind it), wordmark left, cart + account right. Values copied
   from .luxe-header/.luxe-header.scrolled above. */
/* ---- container (0.8.1) — Astra's core main.min.css (not astra-addon, not
   this child theme) gave every .ast-container instance a max-width + centered
   gutters. header.php emits .ast-container twice (the header row wrap, and
   the #content wrap around #primary/.site-main) and footer.php closes both
   — the markup and every selector this stylesheet targets inside it
   (.ast-woocommerce-container, #primary spacing, etc.) assumed that base
   width constraint would keep existing. It didn't survive the 0.8.0
   standalone conversion, and its absence is the single root cause behind
   the full-bleed regressions Logan caught 2026-08-05: the get-started
   back-link/footer sitting at the raw viewport edge, the product gallery
   filling the whole viewport instead of a ~48%-wide column, checkout's
   two-column grid stretching edge to edge. Same recipe as the landing
   page's own .hero-content/.glove-inner (max-width:1220px + margin:auto +
   padding:var(--pad) side gutters) — restoring it here, once, fixes every
   page that nests content inside .ast-container instead of patching each
   surface separately. */
body:not(.luxe-landing) .ast-container{
  max-width:1220px;width:100%;margin:0 auto;
  padding:0 var(--pad);box-sizing:border-box;
}
/* Header wrap must NOT take the page-content .ast-container max-width — spans viewport with its own gutter, same recipe as .luxe-header. */
body:not(.luxe-landing) .ast-primary-header-bar .site-primary-header-wrap.ast-container{max-width:none;width:100%;padding:0 var(--pad)}
/* Base flex mechanics (0.8.0 standalone conversion) — .ast-builder-grid-row's
   display:flex and the header sections' row layout used to come from
   Astra's own main.min.css, not this child stylesheet; everything below
   this point only ever added modifiers (height/align-items/etc.) on top of
   that base. With Astra's CSS gone, the base layout itself has to live
   here or the wordmark/cart/account icons stack vertically instead of
   sitting in a row.
   0.8.1 fix: .site-primary-header-wrap must NOT also be display:flex.
   It carries .ast-container (see the container rule below) and is the
   OUTER width-constraining box; .ast-builder-grid-row is its only child.
   Making the wrap flex too turns the grid-row into a flex ITEM with no
   flex-grow, so it shrinks to its own content width (measured: 241px of
   a 1400px header) instead of filling the row — which is why the
   cart/account icons rendered glued to the wordmark instead of pinned
   right (Logan 2026-08-05). Only the grid-row needs display:flex. */
body:not(.luxe-landing) .ast-builder-grid-row{display:flex;align-items:center;justify-content:space-between}
body:not(.luxe-landing) .site-header-section-right{display:flex;align-items:center;gap:1.5rem}
body:not(.luxe-landing) .site-header{
  /* z-index 110: one tier above the builder's sticky step chrome (100,
     shop-builder.css) — the fixed header stays on top of any in-page sticky
     content everywhere, not just the accessories step above. The top:64px
     fix above is what actually stops the two from occupying the same pixels;
     this is the backstop if anything else ever pins itself to the header's
     top edge. */
  position:fixed;inset:0 0 auto 0;z-index:110;background:transparent;
}
body.admin-bar:not(.luxe-landing) .site-header{top:32px}
body:not(.luxe-landing) .ast-primary-header-bar{
  background:linear-gradient(rgba(15,15,17,.92), rgba(15,15,17,.78)) !important;
  backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
  border-bottom:1px solid rgba(241,236,226,.07);
}
/* fixed header overlays the flow — reserve its height above the content */
body:not(.luxe-landing) #content{padding-top:64px}
/* #primary top offset (0.8.1) — Astra used to inject its own post class
   (.ast-article-single) via a post_class filter that only runs while Astra
   is the active parent theme; that filter is gone in the 0.8.0 standalone
   conversion, so the class never appears in post_class() output anymore
   (confirmed: article.className is now just "post-224 page type-page
   status-publish hentry", no ast-* class at all). Every "single-page
   template (cart, checkout, archives, my-account, products) gets 106.8px
   of top padding for free" this stylesheet already documented and built on
   top of (see the get-started .light-mode section below) went with it —
   that's the missing breathing room behind every "content sits too close
   to the header" regression Logan caught on the category/product/cart/
   checkout pages 2026-08-05. #primary is the one wrapper every non-landing
   template (page.php/single.php/archive.php/index.php and the WC content
   wrapper in functions.php) emits unconditionally, so restoring it there
   once covers all of them; the get-started override below is updated to
   match on #primary too, since its own ast-article-single selector was
   equally dead. */
body:not(.luxe-landing) #primary{padding-top:2.5rem}
/* sticky footer (0.8.1) — Astra's #page carried min-height:100vh + a flex
   column so a short page's footer still sits at the viewport bottom
   instead of floating right after the content with dead ivory space
   below it inside a taller browser window (Logan 2026-08-05, get-started).
   #masthead is position:fixed so it never participates in this flex flow;
   #content growing to fill the leftover space is what pins the footer. */
body:not(.luxe-landing) #page{display:flex;flex-direction:column;min-height:100vh}
body:not(.luxe-landing) #content{flex:1 0 auto}

/* Astra stacks FIVE height sources on the header (bar min-height:100px, wrap
   min-height, grid-row min-height:80px, per-element padding:15px, cart
   line-height:2.7). Rather than whack each, pin the row to an explicit 64px
   flex line — home's luxe header measures ~66px. */
body:not(.luxe-landing) .ast-primary-header-bar,
body:not(.luxe-landing) .ast-primary-header-bar .site-primary-header-wrap{
  min-height:0 !important;padding-top:0 !important;padding-bottom:0 !important;
}
body:not(.luxe-landing) .ast-primary-header-bar .ast-builder-grid-row{
  min-height:0 !important;height:64px;align-items:center;
}
body:not(.luxe-landing) .ast-primary-header-bar .site-header-section,
body:not(.luxe-landing) .ast-primary-header-bar .ast-builder-layout-element{
  min-height:0 !important;height:auto !important;padding-top:0 !important;padding-bottom:0 !important;
  margin-top:0 !important;margin-bottom:0 !important;
}
body:not(.luxe-landing) .ast-primary-header-bar .ast-header-woo-cart,
body:not(.luxe-landing).ast-desktop .ast-primary-header-bar .ast-header-woo-cart,
body:not(.luxe-landing) .ast-primary-header-bar .ast-header-account{
  line-height:1 !important;
}
body:not(.luxe-landing) .ast-site-header-cart .ast-woo-header-cart-info-wrap{line-height:1.4 !important}

/* ---- my-account goes paper (0.7.8, 2026-07-30) ----
   The fourth stop on the ivory writing flow: login/register, dashboard,
   orders, addresses, payment methods, account details. `.woocommerce-account`
   is a class ON <body> for every My Account endpoint (login through
   edit-account) — never descend into it. Same .light law as builder/cart/
   checkout: --gold-ink is gold's only voice on ivory, gold-face buttons are
   the money action only (here: the login submit — the one "unlock" CTA).
   Site header/footer stay ink (already unconditional dark globally). */
body.woocommerce-account{background:var(--ivory);color:var(--ink)}
body.woocommerce-account #content h1,
body.woocommerce-account #content h2,
body.woocommerce-account #content h3{color:var(--ink);font-family:var(--serif);font-weight:300}
body.woocommerce-account #content a{color:var(--ink)}
body.woocommerce-account #content a:hover{color:var(--gold-ink)}

/* MyAccount-navigation — links ink-soft, active/hover gold-ink, hairline-ink
   separators. SVG icons use fill:currentColor so they follow the link color
   for free. !important guards against Astra's own account-nav customizer CSS.
   Icon+label markup itself now comes from the theme's own
   woocommerce/myaccount/navigation.php override (astra-addon's icon
   injection dies with the theme; WC's stock template only prints plain
   text). Width/row layout below is net-new — WC's default stylesheet gives
   this nav a 30%-wide float sidebar, not the narrower icon rail this store
   actually uses. */
body.woocommerce-account .woocommerce-MyAccount-navigation{width:230px;float:left}
body.woocommerce-account .woocommerce-MyAccount-navigation ul{margin:0;list-style:none;padding:0}
body.woocommerce-account .woocommerce-MyAccount-navigation-link{border-bottom:1px solid var(--hairline-ink)}
body.woocommerce-account .woocommerce-MyAccount-navigation-link a{
  display:flex;align-items:center;gap:.7rem;padding:.85rem 1rem;
  color:var(--ink-soft) !important;
}
body.woocommerce-account .woocommerce-MyAccount-navigation-link a svg{width:1rem;height:1rem;fill:currentColor}
body.woocommerce-account .woocommerce-MyAccount-navigation-link.is-active a{
  background:rgba(194,161,94,.12);
}
body.woocommerce-account .woocommerce-MyAccount-navigation-link.is-active a,
body.woocommerce-account .woocommerce-MyAccount-navigation-link a:hover{color:var(--gold-ink) !important}
@media (max-width:800px){
  body.woocommerce-account .woocommerce-MyAccount-navigation{width:100%;float:none;margin-bottom:1.5rem}
}

/* login/register forms — shared .woocommerce-form-row/.form-row markup
   covers both (register form fields inherit the same rules for free) */
body.woocommerce-account .woocommerce-form-row label,
body.woocommerce-account .form-row label{color:var(--ink-soft)}
/* doubles .woocommerce-account to out-specify the dark base rule above outright
   (both are body+:not/.class+element — an exact specificity tie otherwise,
   won only by source order) — mirrors why #order_review_heading needed its
   own ID anchor on checkout */
body.woocommerce-account.woocommerce-account input[type="text"],
body.woocommerce-account.woocommerce-account input[type="email"],
body.woocommerce-account.woocommerce-account input[type="tel"],
body.woocommerce-account.woocommerce-account input[type="password"],
body.woocommerce-account.woocommerce-account input[type="number"],
body.woocommerce-account.woocommerce-account input[type="search"],
body.woocommerce-account.woocommerce-account textarea,
body.woocommerce-account.woocommerce-account select{
  background:#fff;border:1px solid var(--hairline-ink);color:var(--ink);
}
/* line 782's ".woocommerce form .form-row input.input-text" (0,3,2) out-specifies
   the generic type-selector rule above — match its selector shape to win */
body.woocommerce-account .form-row input.input-text,
body.woocommerce-account .form-row textarea,
body.woocommerce-account .form-row select,
body.woocommerce-account #order_comments{
  background:#fff;border:1px solid var(--hairline-ink);color:var(--ink);
}
body.woocommerce-account input::placeholder,
body.woocommerce-account textarea::placeholder{color:var(--ink-soft)}
/* line 232's ".woocommerce input[type=checkbox]" (0,3,2) also needs matching */
body.woocommerce-account.woocommerce-account .woocommerce input[type=checkbox]{background:#fff;border:1px solid var(--hairline-ink)}
body.woocommerce-account input[type=checkbox]:checked{background:var(--gold);border-color:var(--gold)}
/* Woo's JS-injected show/hide password toggle (line 378) — quiet ink-soft text on paper */
body.woocommerce-account button.show-password-input{color:var(--ink-soft)}
body.woocommerce-account button.show-password-input:hover{color:var(--gold-ink)}
/* lost-password link */
body.woocommerce-account .woocommerce-LostPassword a{color:var(--ink-soft)}
body.woocommerce-account .woocommerce-LostPassword a:hover{color:var(--gold-ink)}
/* select2 (address country/state — dropdown appends to <body>, which carries
   the .woocommerce-account class, so this scoping still reaches it) */
body.woocommerce-account.woocommerce-account .select2-container--default .select2-selection--single{
  background:#fff;border:1px solid var(--hairline-ink);border-radius:0 !important;
}
body.woocommerce-account .select2-selection__rendered{color:var(--ink) !important}
body.woocommerce-account .select2-dropdown{background:#fff;border:1px solid var(--hairline-ink);color:var(--ink)}
body.woocommerce-account .select2-container--default .select2-search--dropdown .select2-search__field{
  background:#fff;border:1px solid var(--hairline-ink);color:var(--ink);
}

/* secondary buttons (Save address, Save changes, Add payment method,
   Cancel order, Browse products, kebab-menu items…) — same recipe as cart's
   secondary-button counter; hover (gold face/ink text) is already correct
   from the base dark rule, only resting color/border need restating */
body.woocommerce-account .woocommerce a.button:not(.show-password-input),
body.woocommerce-account .woocommerce button.button:not(.show-password-input),
body.woocommerce-account .woocommerce input.button:not(.show-password-input){
  color:var(--ink);border-color:var(--hairline-ink);
}
/* the login submit — the one money/unlock action on this surface: gold face
   at rest, same primary pattern as .pulse-btn--primary. !important because
   the secondary-button rule above out-specifies a plain class selector here. */
body.woocommerce-account .woocommerce-form-login__submit{
  background:var(--gold) !important;border-color:var(--gold) !important;color:var(--ink) !important;
}
body.woocommerce-account .woocommerce-form-login__submit:hover{
  background:transparent !important;border-color:var(--gold-ink) !important;color:var(--gold-ink) !important;
}

/* tables (orders, downloads, payment methods, view-order line items) all
   carry .shop_table — same counter shape as the cart's table override,
   including the border-color !important fight (line 426 carries !important) */
body.woocommerce-account table.shop_table{border-color:var(--hairline-ink);background:transparent}
body.woocommerce-account table.shop_table td,
body.woocommerce-account table.shop_table th{color:var(--ink-soft)}
body.woocommerce-account table.shop_table td,
body.woocommerce-account table.shop_table th{border-color:var(--hairline-ink) !important}
body.woocommerce-account table.shop_table .product-name a{color:var(--ink)}
/* the orders table itself is the primary read on this surface — full ink,
   not the ink-soft fallback used for downloads/payment-methods tables */
body.woocommerce-account table.woocommerce-orders-table td,
body.woocommerce-account table.woocommerce-orders-table th{color:var(--ink)}

/* search submit button was ivory-on-ivory (base .pulse-btn dark-surface rule ~1097
   never gets a paper counter here); same recipe as the .pulse-btn counters on
   checkout (~598) and single-product (~1394) */
body.woocommerce-account .pulse-btn{color:var(--ink);border-color:var(--hairline-ink)}
body.woocommerce-account .pulse-btn:hover{background:var(--gold);border-color:var(--gold);color:var(--ink)}
/* Astra's WC-compat CSS forces this cell to display:block, silently disabling the
   plugin's own vertical-align:middle (only applies to table-cell boxes) */
body.woocommerce-account table.woocommerce-orders-table td.woocommerce-orders-table__cell-order-actions{display:table-cell}
/* Astra's global .ast-article-inner{overflow-wrap:break-word} inherits into the
   100px TOTAL column and breaks inside digit strings; pin the amount, let
   "for N items" wrap at its natural space */
body.woocommerce-account table.woocommerce-orders-table td.woocommerce-orders-table__cell-order-total .woocommerce-Price-amount{white-space:nowrap}

/* .pulse-orders-search — white field; button now covered by the .pulse-btn
   paper counter above (was incorrectly assumed already-covered — that gap
   was the ivory-on-ivory bug) */
body.woocommerce-account .pulse-orders-search-input{background:#fff;border-color:var(--hairline-ink);color:var(--ink)}
body.woocommerce-account .pulse-orders-search-input::placeholder{color:var(--ink-soft)}
body.woocommerce-account .pulse-orders-search-clear{color:var(--ink-soft)}
body.woocommerce-account .pulse-orders-search-clear:hover{color:var(--gold-ink)}
body.woocommerce-account .pulse-orders-page-indicator,
body.woocommerce-account .pulse-order-support-note{color:var(--ink-soft)}

/* order-actions kebab menu — flip the ink-2 panel (lines 941-947) to a
   white paper panel; counter each !important rule in kind */
body.woocommerce-account .pulse-kebab-menu{background:#fff;border-color:var(--hairline-ink);box-shadow:none}
body.woocommerce-account .pulse-kebab-menu a.button,
body.woocommerce-account .pulse-kebab-menu a.woocommerce-button{color:var(--ink-soft) !important}
body.woocommerce-account .pulse-kebab-menu a.button:hover,
body.woocommerce-account .pulse-kebab-menu a.woocommerce-button:hover{
  background:rgba(194,161,94,.12) !important;color:var(--ink) !important;
}

/* view-order .pulse-ma-payments block — counter the dark .pulse-ma-* rules
   (lines 1089-1091, 1113-1114); balance-due is gold-ink, NOT raw gold on paper */
body.woocommerce-account .pulse-ma-payments-title{color:var(--ink)}
body.woocommerce-account .pulse-ma-balance-due{color:var(--gold-ink)}
body.woocommerce-account .pulse-ma-amount-paid{color:var(--ink-soft)}
body.woocommerce-account .pulse-ma-payments th,
body.woocommerce-account .pulse-ma-payments td{border-bottom:1px solid var(--hairline-ink)}
body.woocommerce-account .pulse-ma-total{color:var(--ink)}

/* Astra's compat CSS paints a grey #fbfbfb header band (.woocommerce-Address-title)
   and a bordered, browser-italic <address> box the paper block never reached */
body.woocommerce-account .woocommerce-Addresses .woocommerce-Address-title{background:#fff;border-color:var(--hairline-ink)}
/* action link — ink-soft resting, gold-ink hover; #content needed to beat the
   generic #content a rules at ~2104-2105 */
body.woocommerce-account #content .woocommerce-Address-title a.edit{color:var(--ink-soft)}
body.woocommerce-account #content .woocommerce-Address-title a.edit:hover{color:var(--gold-ink)}
/* font-style kills the browser UA default italic on <address> */
body.woocommerce-account .woocommerce-Address address{color:var(--ink-soft);font-style:normal;background:#fff;border-color:var(--hairline-ink)}

/* Woo notices — canonical paper recipe (checkout/cart) */
body.woocommerce-account .woocommerce-message,
body.woocommerce-account .woocommerce-info,
body.woocommerce-account .woocommerce-error{
  background-color:#fff;border:1px solid var(--hairline-ink);border-top:2px solid var(--gold);color:var(--ink-soft);
}
body.woocommerce-account .woocommerce-message::before,
body.woocommerce-account .woocommerce-info::before{color:var(--gold-ink)}
body.woocommerce-account .woocommerce-privacy-policy-text{color:var(--ink-soft)}

/* AJAX blockUI overlay — paper, not the global ink !important */
body.woocommerce-account .blockUI.blockOverlay{background:var(--ivory) !important}

/* plugin-era inline-navy signature catch (staging runs original plugins
   with inline styles; local runs de-skinned — cover both) */
body.woocommerce-account a[style*="#16435F"]{color:var(--ink-soft) !important}
body.woocommerce-account a[style*="#16435F"]:hover{color:var(--gold-ink) !important}

/* ---- contextual back links (0.7.11) — the checkout back-link voice,
   restated for paper (all surfaces that get one are paper now).
   !importants: the href can contain resume=browse, which the 0.4.x-era
   a[href*="resume=browse"] signature rule buttonizes; and the dark-era
   global body:not(.luxe-landing) a{ivory} outranks a bare class. ---- */
body:not(.luxe-landing) .luxe-back{margin:1.6rem 0 0}
body:not(.luxe-landing) .luxe-back a{
  font-family:var(--sans);font-weight:400 !important;font-size:.82rem !important;
  letter-spacing:.14em;text-transform:uppercase;text-decoration:none;
  color:var(--ink-soft) !important;background:transparent !important;
  border:none !important;padding:0 !important;display:inline-block;
  transition:color .3s ease;
}
body:not(.luxe-landing) .luxe-back a:hover{color:var(--gold-ink) !important}

/* ============================================================
   Global WC base the per-surface era never wrote (0.10.0) —
   surfaces nobody walked through rendered raw UA/WC defaults.
   ============================================================ */
/* fieldset/legend (edit-account "Password change") — browser groove box
   otherwise; legend gets the h3 display voice */
body:not(.luxe-landing) fieldset{
  border:1px solid var(--line);padding:1.2rem 1.4rem;margin:1.6rem 0;
}
body:not(.luxe-landing) fieldset legend{
  font-family:var(--serif);font-weight:300;font-size:1.4rem;color:var(--fg);
  padding:0 .6rem;margin-left:-.6rem;
}
/* my-account content pane — WC default floats it 68% right, stranding a gap
   against the theme's 230px nav rail */
body.woocommerce-account .woocommerce-MyAccount-content{
  float:right;width:calc(100% - 280px);
}
@media (max-width:800px){
  body.woocommerce-account .woocommerce-MyAccount-content{float:none;width:100%}
}
/* orders kebab trigger (⋯) — raw UA button until now */
body:not(.luxe-landing) .pulse-kebab-toggle{
  background:transparent;border:1px solid var(--line);color:var(--fg-soft);
  padding:.2rem .7rem;font-size:1rem;line-height:1.4;cursor:pointer;
  transition:border-color .3s ease, color .3s ease;
}
body:not(.luxe-landing) .pulse-kebab-toggle:hover,
body:not(.luxe-landing) .pulse-kebab-toggle[aria-expanded="true"]{
  border-color:var(--gold);color:var(--gold-role);
}
/* addresses cards — WC prints bare <address>; give both address blocks the
   same white sheet treatment the my-account block gave only some of them */
body.woocommerce-account .woocommerce-Address{margin-bottom:1.2rem}
body.woocommerce-account .woocommerce-Address address{padding:1rem 1.2rem}

/* ---- my-account round 2 (Logan staging review 2026-08-05) ---- */
/* kebab menu items are MENU ROWS, not buttons — the .button base chrome
   (border, 216px padded box in a 202px panel) overflowed and read broken */
body:not(.luxe-landing) .pulse-kebab-menu{padding:.3rem 0;min-width:190px}
body:not(.luxe-landing) .pulse-kebab-menu a.button,
body:not(.luxe-landing) .pulse-kebab-menu a.woocommerce-button{
  display:block;width:100%;box-sizing:border-box;
  background:transparent !important;border:none !important;
  padding:.55rem 1rem !important;text-align:left;
  font-size:.8rem;letter-spacing:.16em;
}
/* addresses: ONE sheet per address, header row flex (the floated edit link
   was offsetting the text), inner boxes go transparent */
body.woocommerce-account .woocommerce-Address{
  background:var(--panel);border:1px solid var(--line);padding:1.2rem 1.4rem;
  box-sizing:border-box; /* WC smallscreen sets width:100% — content-box padding overflows the viewport (the col2-set trap) */
}
body.woocommerce-account .woocommerce-Addresses .woocommerce-Address-title{
  background:transparent;border:none;border-bottom:1px solid var(--line);
  display:flex;flex-direction:column;align-items:flex-start;gap:.3rem;
  padding:0 0 .6rem;margin-bottom:.8rem;
}
@media (min-width:800px){
  body.woocommerce-account .woocommerce-Addresses .woocommerce-Address-title{
    flex-direction:row;align-items:baseline;justify-content:space-between;gap:1rem;
  }
}
body.woocommerce-account .woocommerce-Address-title h2,
body.woocommerce-account .woocommerce-Address-title h3{margin:0;font-size:1.5rem}
body.woocommerce-account .woocommerce-Address-title a.edit{
  float:none;flex-shrink:0;font-size:.8rem;letter-spacing:.14em;text-transform:uppercase;
}
body.woocommerce-account .woocommerce-Address address{
  background:transparent;border:none;padding:0;
}
/* two address cards side by side on desktop (WC's float layout collapsed
   inside the floated MyAccount-content pane) */
@media (min-width:800px){
  body.woocommerce-account .woocommerce-Addresses{display:grid;grid-template-columns:1fr 1fr;gap:1.5rem}
  /* WC core clearfixes .col2-set with ::before/::after{content:" ";display:table}
     — in a grid the ::before becomes an anonymous ITEM in cell (1,1), shoving
     Billing to column 2 and Shipping to row 2 (Logan 2026-08-05 offset) */
  body.woocommerce-account .woocommerce-Addresses::before,
  body.woocommerce-account .woocommerce-Addresses::after{content:none}
  body.woocommerce-account .woocommerce-Addresses .u-column1,
  body.woocommerce-account .woocommerce-Addresses .u-column2{width:100%;float:none;margin:0}
}
/* show-password toggle: compact single line, vertically centered in the
   field (was a 48x41 two-line block); kill WC's icon pseudo */
body:not(.luxe-landing) button.show-password-input{
  position:absolute;top:50%;right:.7rem;transform:translateY(-50%);
  height:auto;padding:0;line-height:1;font-size:.68rem;display:inline-flex;align-items:center;
}
body:not(.luxe-landing) button.show-password-input::before{display:none !important;content:none !important}
body:not(.luxe-landing) .password-input{position:relative;display:block;width:100%}
body:not(.luxe-landing) .password-input input{width:100%;box-sizing:border-box;padding-right:3.4rem}
