/* HNL Builder (B-UX-1A R2) — guided step flow matched to the locked visual direction.
   Scoped under .hnl-ppb-* / #hnl-pp-builder-root. body.hnl-ppb-page drives the theme break-out. */

/* ---- B1-Layout: break the builder out of Shoptimizer's two-column product wrapper ---- */
body.hnl-ppb-page .product-details-wrapper { display:block !important; width:100% !important; max-width:100% !important; }
body.hnl-ppb-page .summary.entry-summary { width:100% !important; max-width:100% !important; margin:0 !important; float:none !important; padding:0 !important; }
/* keep the stock title/rating readable, full width, above the hero */
body.hnl-ppb-page .summary.entry-summary .product_title { margin-top:0; }

/* R2 (C): floating cart bubble hidden on builder pages. Best-effort — FunnelKit's exact floating-
   bubble markup could not be verified against a real install from this environment; these are the
   commonly documented FunnelKit Cart floating-launcher selectors. CONFIRM against real DEV and
   adjust the selector list if the real markup differs. */
body.hnl-ppb-page .fkcart-floating,
body.hnl-ppb-page .fkcart-floating-cart,
body.hnl-ppb-page .fkcart-float-launcher,
body.hnl-ppb-page #fkcart-app .fkcart-icon-wrap,
body.hnl-ppb-page .xoo-wsc-basket-wrap,
body.hnl-ppb-page .xoo-wsc-basket { display:none !important; }

/* ---- R1.1.1 (item 1): make the hero the FIRST band. The Shoptimizer breadcrumb OUTPUT is removed
   via the confirmed hook chain in class-builder.php::maybe_setup()
   (remove_action('shoptimizer_content_top','shoptimizer_breadcrumbs',5) + the woocommerce_breadcrumb
   @10 it re-adds). This CSS is the scoped SAFETY NET (residual breadcrumb/archive-header markup) plus
   the Shoptimizer TOP-SPACING neutralizer. Scoped to the TRIPLE body class
   (single-product + hnl-ppb-page + hnl-ppb-has-hero) so it ONLY affects HNL builder product pages
   that render a hero — NOT normal products, NOT builder pages without a hero image. No broad
   has-based negation selectors; no global breadcrumb hiding; no Customizer change. ---- */
body.single-product.hnl-ppb-page.hnl-ppb-has-hero .woocommerce-breadcrumb:not(.hnl-pp-hero-breadcrumb),
body.single-product.hnl-ppb-page.hnl-ppb-has-hero nav.woocommerce-breadcrumb:not(.hnl-pp-hero-breadcrumb),
body.single-product.hnl-ppb-page.hnl-ppb-has-hero .shoptimizer-breadcrumb,
body.single-product.hnl-ppb-page.hnl-ppb-has-hero .site-breadcrumb,
body.single-product.hnl-ppb-page.hnl-ppb-has-hero .breadcrumbs,
body.single-product.hnl-ppb-page.hnl-ppb-has-hero .archive-header,
body.single-product.hnl-ppb-page.hnl-ppb-has-hero .page-header,
body.single-product.hnl-ppb-page.hnl-ppb-has-hero .entry-header { display:none !important; }
body.single-product.hnl-ppb-page.hnl-ppb-has-hero .site-content,
body.single-product.hnl-ppb-page.hnl-ppb-has-hero .site-main,
body.single-product.hnl-ppb-page.hnl-ppb-has-hero #primary,
body.single-product.hnl-ppb-page.hnl-ppb-has-hero .content-area,
body.single-product.hnl-ppb-page.hnl-ppb-has-hero .product-details-wrapper { padding-top:0 !important; margin-top:0 !important; }

/* R1.1.5 ROOT-CAUSE FIX: this variable block (and box-sizing below) was scoped ONLY to
   #hnl-pp-builder-root. Since R1.1.2/R1.1.3, the lightbox AND the mobile summary drawer are each
   rendered as a DOM PORTAL appended directly to <body> — i.e. SIBLINGS of #hnl-pp-builder-root, not
   descendants of it. Any var(--hnl-*) reference used inside either portal's own CSS (or inside
   sidebarMarkup()'s shared markup, which the drawer reuses) therefore had NO variable to resolve:
   background-color fell back to its initial value (transparent) — exactly "the drawer area looks
   semi-transparent and the product list bleeds through" — and color (an inherited property) fell back
   to whatever the surrounding page happened to inherit, not the intended near-black ink — exactly the
   lightbox close button reading "gray-on-gray/dark-on-dark". Extending this SAME selector to also cover
   both portal-root wrappers (siblings under <body>, not a global :root/body rule, so this stays scoped
   to only the three places this plugin actually renders) restores every var(--hnl-*) reference
   everywhere inside both portals in one fix — not just the two specifically reported symptoms, but
   also the lightbox prev/next buttons, thumbnail colors, and every icon/pill/border color inside the
   drawer's reused sidebar content, all of which shared the exact same silent failure. */
#hnl-pp-builder-root, .hnl-ppb-lightbox-portal-root, .hnl-ppb-drawer-portal-root {
	/* R2 (A): locked HNL palette — replaces the prior beige/cream/green treatment entirely. */
	/* R1.1 (1A/1B): locked NEUTRAL/BLACK direction. The former red/pink palette is remapped so every
	   button, active-step circle/line, selected-state border/fill, and large accent that used
	   var(--hnl-red)/var(--hnl-red-soft) now renders BLACK / neutral-gray. #850000 is reserved for
	   ICONS ONLY and is exposed as --hnl-icon. (The variable NAMES are kept to avoid churn across ~35
	   references; only their VALUES changed. --hnl-red-soft, previously pink #FFF1F1, is now a neutral
	   light gray so all former pink fills — subscribe card, free-shipping box, savings pills, "add 1
	   more" callout, drawer/summary fills — become neutral.) */
	--hnl-red:#141414; --hnl-red-deep:#000000; --hnl-red-soft:#F3F3F3;
	/* R1.1.3 (item 6): #850000 is no longer icon-only — it is now the HNL brand accent, permitted for
	   small UI emphasis, active states, step indicators, and helper/subtitle text (never for primary
	   button/CTA/Add-to-cart fills, large background fills, selected-card fills, drawer/surface fills,
	   the validation alert, product prices, or the main H1 — those all stay black/neutral, unchanged).
	   --hnl-icon is now an ALIAS of --hnl-brand (one source of truth for the #850000 value) so existing
	   icon-color rules keep working unchanged. */
	--hnl-brand:#850000; --hnl-brand-soft:#dfb8b8; --hnl-brand-glow:#8500001a;
	--hnl-icon:var(--hnl-brand);
	--hnl-ink:#101010; --hnl-charcoal:#2E2E2E; --hnl-gray:#6B6B6B;
	--hnl-divider:#E5E5E5; --hnl-soft-gray:#F7F7F7; --hnl-white:#FFFFFF;
	/* legacy variable names kept as aliases so nothing downstream needs re-pointing */
	--ppb-ink:var(--hnl-ink); --ppb-soft:var(--hnl-gray); --ppb-line:var(--hnl-divider);
	--ppb-card:var(--hnl-white); --ppb-paper:var(--hnl-soft-gray);
	--ppb-forest:var(--hnl-red); --ppb-forest-2:var(--hnl-red-deep);
	--ppb-clay:var(--hnl-red); --ppb-clay-soft:var(--hnl-red-deep); --ppb-good:var(--hnl-red-deep);
	display:block; margin:14px 0 0; color:var(--ppb-ink); font-size:14px; }
#hnl-pp-builder-root *, .hnl-ppb-lightbox-portal-root *, .hnl-ppb-drawer-portal-root * { box-sizing:border-box; }

/* ---- guided-flow shell — focused main step column + persistent right-side summary. ---- */
.hnl-ppb-shell { display:grid; grid-template-columns:1fr 320px; gap:28px; align-items:start; }
@media (max-width:860px) { .hnl-ppb-shell { grid-template-columns:1fr; gap:18px; } }

/* ---- B-UX-1B (Scope 1/3/4): page-level family hero — below the product title, above the builder.
   It renders in the product summary column, which body.hnl-ppb-page already forces to full width,
   so the hero spans the content area. Text left, family image right; compact side-by-side on mobile. ---- */
/* R1.1 (12): the hero is the product page's TOP BAND. It is a fixed-min-height band so the split
   reads as one complete section, and the image is absolutely positioned to COVER its half — top-
   aligned, cover-cropped — so it fills the band edge-to-edge instead of floating partway down.
   (The gap between the black nav and this band is the theme's breadcrumb/title spacing above the
   summary column; tighten those in the theme if a smaller gap is wanted — see DEV checklist.) */
.hnl-pp-hero { display:grid; grid-template-columns:minmax(0,1.05fr) minmax(0,0.95fr); align-items:stretch;
	min-height:360px; margin:0 0 12px; border-radius:14px; overflow:hidden; background:var(--hnl-soft-gray); }
.hnl-pp-hero-body { padding:40px 40px; display:flex; flex-direction:column; justify-content:center; gap:12px; }
.hnl-pp-hero-media { position:relative; min-height:220px; }
.hnl-pp-hero-img { position:absolute; inset:0; width:100%; height:100%; object-fit:cover; object-position:center; }
.hnl-pp-hero-title { margin:0; font-size:30px; line-height:1.08; color:var(--hnl-charcoal); font-weight:800; }
/* R1.1.1 (relocation): compact breadcrumb inside the hero left column, above the H1. Small, muted,
   neutral — icons stay #850000 elsewhere; this is text only. */
.hnl-pp-hero-breadcrumb { margin:0 0 8px; padding:0; font-size:12.5px; line-height:1.3; color:var(--hnl-gray); }
.hnl-pp-hero-breadcrumb a { color:var(--hnl-gray); text-decoration:none; }
.hnl-pp-hero-breadcrumb a:hover, .hnl-pp-hero-breadcrumb a:focus { color:var(--hnl-charcoal); text-decoration:underline; }
.hnl-pp-hero-heading { margin:0; font-size:18px; line-height:1.25; color:var(--hnl-charcoal); font-weight:600; }
.hnl-pp-hero-copy { margin:0; font-size:15px; line-height:1.5; color:var(--hnl-charcoal); max-width:44ch; }
.hnl-pp-hero-benefits { list-style:none; margin:6px 0 0; padding:0; display:flex; flex-wrap:wrap; gap:12px 24px; }
.hnl-pp-hero-benefit { font-size:12.5px; color:var(--hnl-charcoal); }
/* R1.1 (Issue 1): the hero renders OUTSIDE #hnl-pp-builder-root, where --hnl-red is not in scope, so
   var(--hnl-red) resolved to nothing and the CTA read as a faint/white anchor. Use the literal HNL
   dark red so the CTA is unambiguously a button regardless of scope or theme anchor styling. The
   .hnl-pp-hero ancestor qualifier raises specificity above bare theme `a` rules; !important on the
   two colors guards against aggressive theme anchor resets. The CTA is navigation only (scrolls to
   the builder) — it never selects a product, adds to cart, or bypasses validation. */
.hnl-pp-hero .hnl-pp-hero-cta { align-self:flex-start; margin-top:10px; display:inline-block; text-decoration:none;
	background:#141414 !important; color:#ffffff !important; font-weight:600; font-size:15px; line-height:1.2;
	padding:12px 24px; border:0; border-radius:9px; cursor:pointer; box-shadow:0 1px 2px rgba(0,0,0,0.12); }
.hnl-pp-hero .hnl-pp-hero-cta:hover, .hnl-pp-hero .hnl-pp-hero-cta:focus { background:#000000 !important; color:#ffffff !important; }
.hnl-pp-hero .hnl-pp-hero-cta:focus-visible { outline:2px solid #000000; outline-offset:2px; }
@media (max-width:860px) {
	/* R1.1.2: LOCKED mobile hero decision. Desktop/tablet (>860px) keeps the split grid above
	   UNCHANGED. Below 860px the hero becomes a genuine SINGLE-COLUMN stack — not a squeezed
	   two-column layout — so breadcrumb/title/copy never compete for width against the image or risk
	   crossing into it. We deliberately use this plugin's EXISTING single mobile breakpoint (860px —
	   the same one that already governs the sidebar, sticky summary bar, and drawer) rather than
	   introducing a second, inconsistent breakpoint: there is no other "tablet-specific" layout
	   anywhere else in this plugin, so splitting the hero's own mobile line at a different value (e.g.
	   767px) would create a dead zone where the summary bar/drawer are already "mobile" but the hero
	   still shows the old split. Below 860px = mobile everywhere in this builder, hero included.
	   DOM order (breadcrumb, H1, heading, copy, benefits, CTA, then the image) already matches the
	   REQUIRED mobile order exactly (see render_hero() in class-product-page.php), so a single grid
	   column stacks everything into that order with NO "order:" reshuffling and no z-index/text-shadow
	   trickery — the image is a separate row below the text, never behind or beneath it. */
	.hnl-pp-hero { grid-template-columns:1fr; min-height:0; margin-bottom:10px; }
	.hnl-pp-hero-body { grid-column:1; min-width:0; padding:18px 16px; gap:9px; }
	.hnl-pp-hero-breadcrumb { max-width:100%; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
	.hnl-pp-hero-title { font-size:21px; }
	.hnl-pp-hero-heading { font-size:15px; }
	.hnl-pp-hero-copy { font-size:13px; }
	.hnl-pp-hero-benefits { gap:8px 16px; }
	.hnl-pp-hero-cta { padding:10px 16px; font-size:13.5px; }
	/* Image: its own full-width row below the text (item 7), a fixed reasonable mobile height so it
	   never dominates the screen on a narrow device, cropped cleanly via the existing top-aligned
	   object-fit:cover mechanism (.hnl-pp-hero-img stays position:absolute;inset:0;object-fit:cover —
	   unchanged; only the box it fills gets an explicit mobile height here). */
	.hnl-pp-hero-media { grid-column:1; width:100%; position:relative; height:200px; min-height:0; }
}

.hnl-ppb-intro { color:var(--hnl-gray); font-size:14px; margin:2px 0 18px; }

/* compact gallery — a small supporting visual, never an oversized dedicated column */
.hnl-ppb-gallery--compact { display:flex; align-items:center; gap:10px; margin-bottom:14px; }
.hnl-ppb-gallery--compact .hnl-ppb-main { width:56px; height:56px; flex:0 0 auto; border-radius:10px; aspect-ratio:auto; }
.hnl-ppb-gallery--compact .hnl-ppb-thumbs { margin-top:0; }
.hnl-ppb-gallery--compact .hnl-ppb-thumb { width:32px; height:32px; border-radius:7px; }
.hnl-ppb-main { aspect-ratio:1/1; border-radius:14px; overflow:hidden; background:var(--hnl-soft-gray);
	display:grid; place-items:center; border:1px solid var(--hnl-divider); }
.hnl-ppb-main img { width:100%; height:100%; object-fit:cover; }
.hnl-ppb-noimg-lg { width:45%; height:45%; border-radius:50%; background:var(--hnl-divider); display:block; }
.hnl-ppb-thumbs { display:flex; gap:8px; margin-top:10px; flex-wrap:wrap; }
.hnl-ppb-thumb { width:56px; height:56px; border-radius:9px; overflow:hidden; border:1.5px solid var(--hnl-divider);
	background:var(--hnl-white); cursor:pointer; padding:0; }
.hnl-ppb-thumb img { width:100%; height:100%; object-fit:cover; }
.hnl-ppb-thumb.is-active { border-color:var(--hnl-red); box-shadow:inset 0 0 0 1px var(--hnl-red); }

/* build card (main step column) — clean white, thin gray border, no cream card fill */
.hnl-ppb-builder { border:1px solid var(--hnl-divider); background:var(--hnl-white); border-radius:14px; padding:20px; }

/* ---- R2 (B): four-step progress rail — numbered circles + connecting line, red = active/done ---- */
.hnl-ppb-stepnav { display:flex; align-items:flex-start; margin:0 0 22px; }
.hnl-ppb-stepnav-item { display:flex; flex-direction:column; align-items:center; gap:8px; border:0; background:none; font:inherit;
	padding:0; color:var(--hnl-gray); cursor:default; flex:1 1 auto; position:relative; }
.hnl-ppb-stepnav-item.is-reachable { cursor:pointer; }
.hnl-ppb-stepnav-num { display:inline-flex; align-items:center; justify-content:center; width:28px; height:28px; border-radius:50%;
	background:var(--hnl-white); border:1.5px solid var(--hnl-divider); color:var(--hnl-gray); font-size:13px; font-weight:600; flex:0 0 auto; z-index:1; }
.hnl-ppb-stepnav-item.is-done .hnl-ppb-stepnav-num,
.hnl-ppb-stepnav-item.is-active .hnl-ppb-stepnav-num { background:var(--hnl-brand); border-color:var(--hnl-red); color:var(--hnl-white); }
.hnl-ppb-stepnav-item.is-active .hnl-ppb-stepnav-label { color:var(--hnl-brand); font-weight:600; }
.hnl-ppb-stepnav-item.is-done .hnl-ppb-stepnav-label { color:var(--hnl-ink); }
.hnl-ppb-stepnav-label { font-size:13px; text-align:center; white-space:nowrap; }
.hnl-ppb-stepnav-item:not(:last-child)::after { content:''; position:absolute; top:14px; left:calc(50% + 20px); width:calc(100% - 24px);
	height:1px; background:var(--hnl-divider); z-index:0; }
.hnl-ppb-stepnav-item.is-done:not(:last-child)::after { background:var(--hnl-brand-soft); }
@media (max-width:520px) {
	.hnl-ppb-stepnav-label { display:none; }
	.hnl-ppb-stepnav-num { width:22px; height:22px; font-size:11.5px; }
	.hnl-ppb-stepnav-item:not(:last-child)::after { top:11px; left:calc(50% + 14px); }
}

/* ---- R2 (C): accordion steps — active step expanded; not-yet-reached collapsed with a plain
   description; already-completed steps collapsed with a dynamic summary + Edit affordance. ---- */
.hnl-ppb-accordion-step { border:1px solid var(--hnl-divider); border-radius:12px; margin-bottom:10px; overflow:hidden;
	/* R1.1 (Issue 2): the admin-configured Desktop builder scroll offset (default 120px) drives the
	   desktop landing position — automatic measurement under-estimated the real black header. The
	   measured var and 120px remain as fallbacks. The mobile rule below is unchanged (mobile keeps
	   --hnl-pp-scroll-offset / 80px), so mobile does not regress. */
	scroll-margin-top:var(--hnl-pp-desktop-scroll-offset, var(--hnl-pp-scroll-offset, 120px)); }
@media (max-width:860px) {
	/* R4 (#2): the mobile site header is ~70px tall and sticky/fixed — without this offset,
	   scrollIntoView({block:'start'}) aligns the step's top edge with the very top of the
	   viewport, landing it directly UNDER the header. B-UX-1B: the measured offset overrides this
	   when available; 80px stays as the mobile fallback. */
	.hnl-ppb-accordion-step { scroll-margin-top:var(--hnl-pp-scroll-offset, 80px); }
}
.hnl-ppb-accordion-step:last-child { margin-bottom:0; }
.hnl-ppb-accordion-step.is-active { border-color:var(--hnl-brand-soft); }
.hnl-ppb-accordion-head { display:flex; align-items:flex-start; justify-content:space-between; gap:10px; padding:14px 16px;
	cursor:pointer; background:none; border:0; width:100%; font:inherit; text-align:left; color:inherit; }
.hnl-ppb-accordion-step.is-collapsed .hnl-ppb-accordion-head { cursor:pointer; }
.hnl-ppb-accordion-step.is-active .hnl-ppb-accordion-head { cursor:default; }
.hnl-ppb-accordion-eyebrow { font-size:11.5px; font-weight:600; color:var(--hnl-brand); text-transform:uppercase; letter-spacing:.02em; margin-bottom:2px; }
.hnl-ppb-accordion-title { font-size:16px; font-weight:600; margin:0; color:var(--hnl-ink); }
.hnl-ppb-accordion-desc { font-size:13px; color:var(--hnl-gray); margin-top:3px; }
.hnl-ppb-accordion-summary { font-size:13px; color:var(--hnl-gray); margin-top:3px; }
.hnl-ppb-accordion-chevron { flex:0 0 auto; color:var(--hnl-gray); font-size:13px; margin-top:2px; }
.hnl-ppb-accordion-edit { flex:0 0 auto; border:1px solid var(--hnl-divider); background:var(--hnl-white); color:var(--hnl-red);
	font:inherit; font-weight:600; font-size:12.5px; border-radius:8px; padding:6px 12px; cursor:pointer; }
.hnl-ppb-accordion-body { padding:0 16px 18px; }

/* per-step Prev/Continue footer */
.hnl-ppb-step-footer { display:flex; justify-content:space-between; gap:10px; margin-top:18px; }
.hnl-ppb-step-footer button { font:inherit; font-weight:600; font-size:14px; border-radius:10px; padding:12px 20px; cursor:pointer; }
.hnl-ppb-step-prev { border:1.5px solid var(--hnl-divider); background:var(--hnl-white); color:var(--hnl-ink); }
.hnl-ppb-step-next { border:0; background:var(--hnl-red); color:var(--hnl-white); margin-left:auto; }
.hnl-ppb-step-next:hover { background:var(--hnl-red-deep); }

/* ---- R2 (E): persistent desktop right-side BOX SUMMARY — groups/counts/total/savings preview
   only. The full Today/Renewal $ breakdown lives in Step 4, not here. ---- */
.hnl-ppb-sidebar { position:sticky; top:var(--hnl-pp-sidebar-offset, 120px); }
@media (max-width:860px) { .hnl-ppb-sidebar { display:none; } }
.hnl-ppb-sidebar-inner { border:1px solid var(--hnl-divider); background:var(--hnl-white); border-radius:14px; padding:18px; }
.hnl-ppb-side-h { font-size:16px; font-weight:600; margin:0 0 14px; display:flex; align-items:center; justify-content:space-between; }
.hnl-ppb-side-icon { width:34px; height:34px; border-radius:50%; background:var(--hnl-red-soft); color:var(--hnl-icon);
	display:flex; align-items:center; justify-content:center; font-size:15px; flex:0 0 auto; }
.hnl-ppb-side-group-row { display:flex; align-items:center; gap:10px; padding:8px 0; border-bottom:1px solid var(--hnl-divider); }
.hnl-ppb-side-thumb { width:40px; height:40px; border-radius:8px; background:var(--hnl-soft-gray); flex:0 0 auto; overflow:hidden; border:1px solid var(--hnl-divider); }
.hnl-ppb-side-thumb img { width:100%; height:100%; object-fit:cover; }
.hnl-ppb-side-group-info { flex:1 1 auto; min-width:0; }
.hnl-ppb-side-group-name { font-size:13.5px; font-weight:600; color:var(--hnl-ink); }
.hnl-ppb-side-group-count { font-size:14px; color:var(--hnl-gray); }
.hnl-ppb-side-group-price { font-size:13.5px; font-weight:600; color:var(--hnl-ink); flex:0 0 auto; }
.hnl-ppb-side-empty { font-size:13px; color:var(--hnl-gray); padding:8px 0; }
.hnl-ppb-side-total-row { display:flex; justify-content:space-between; font-size:13.5px; font-weight:600; padding:10px 0 2px; }
/* ---- B-SUM-1: Your box summary selected-product preview strip ---- */
.hnl-ppb-side-total-right { display:inline-flex; align-items:center; gap:10px; }
/* See all / Close all is an ACCENT control, so it is one of the approved #850000 uses
   (var(--hnl-brand)); it is not a button fill, a price, or a heading. */
.hnl-ppb-side-strip-toggle { background:none; border:0; padding:0; cursor:pointer; font:inherit; font-size:12.5px;
	font-weight:600; color:var(--hnl-brand); text-decoration:none; }
.hnl-ppb-side-strip-toggle:hover { text-decoration:underline; }
.hnl-ppb-side-strip-wrap { margin:8px 0 2px; }
.hnl-ppb-side-strip { display:flex; gap:8px; overflow-x:auto; scroll-behavior:smooth; -webkit-overflow-scrolling:touch;
	padding-bottom:4px; scrollbar-width:thin; }
.hnl-ppb-side-strip::-webkit-scrollbar { height:4px; }
.hnl-ppb-side-strip::-webkit-scrollbar-thumb { background:var(--hnl-divider); border-radius:2px; }
.hnl-ppb-side-strip:focus-visible { outline:2px solid var(--hnl-brand); outline-offset:2px; border-radius:8px; }
/* DESKTOP SIDEBAR: exactly three cards visible by layout — each card is a third of the strip's own
   width minus the two 8px gaps, so the 4th onward sit off-view behind the arrows/scroll. */
.hnl-ppb-side-strip-card { flex:0 0 calc((100% - 16px) / 3); min-width:0; }
/* MOBILE DRAWER: do NOT force three-up — fixed-width cards that scroll horizontally instead.
   Qualified with the drawer-body ancestor rather than relying on source order, since the drawer
   reuses sidebarMarkup() verbatim and both copies coexist in the DOM. */
.hnl-ppb-drawer-body .hnl-ppb-side-strip-card { flex:0 0 84px; }
.hnl-ppb-side-strip-thumb { width:100%; aspect-ratio:1 / 1; border-radius:8px; background:var(--hnl-soft-gray);
	border:1px solid var(--hnl-divider); overflow:hidden; }
.hnl-ppb-side-strip-thumb img { width:100%; height:100%; object-fit:cover; display:block; }
/* Product names use normal ink — brand red stays reserved for the See all / Close all accent. */
.hnl-ppb-side-strip-name { margin-top:5px; font-size:11px; line-height:1.3; font-weight:500; color:var(--hnl-ink);
	text-align:center; overflow-wrap:anywhere; }
.hnl-ppb-side-strip-nav { display:flex; justify-content:center; gap:20px; margin-top:6px; }
.hnl-ppb-side-strip-arrow { background:none; border:0; cursor:pointer; padding:2px 10px; line-height:1; font-size:15px;
	color:var(--hnl-ink); border-radius:6px; }
.hnl-ppb-side-strip-arrow:hover { background:var(--hnl-soft-gray); }
.hnl-ppb-side-strip-arrow:focus-visible { outline:2px solid var(--hnl-brand); outline-offset:1px; }
.hnl-ppb-side-shipping { display:flex; align-items:flex-start; gap:10px; background:var(--hnl-red-soft); border-radius:10px; box-shadow:0 0 10px 4px var(--hnl-brand-glow);
	padding:12px; margin:14px 0; }
.hnl-ppb-side-shipping-icon { color:var(--hnl-icon); font-size:16px; flex:0 0 auto; margin-top:1px; }
.hnl-ppb-side-shipping-title { font-size:14px; font-weight:600; color:var(--hnl-ink); }
.hnl-ppb-side-shipping-sub { font-size:14px; color:var(--hnl-gray); }
.hnl-ppb-side-savings-h { font-size:13px; font-weight:600; margin:16px 0 8px; }
.hnl-ppb-side-savings-row { display:flex; align-items:center; justify-content:space-between; font-size:14px; padding:4px 0; }
.hnl-ppb-side-savings-pill { background:var(--hnl-red-soft); color:var(--hnl-red-deep); font-size:11px; font-weight:600;
	border:1.5px solid var(--hnl-brand-soft); border-radius:999px; padding:3px 9px; white-space:nowrap; }
.hnl-ppb-side-tiers-link { background:none; border:0; color:var(--hnl-red); font:inherit; font-size:12.5px; font-weight:600;
	cursor:pointer; padding:6px 0 0; }
.hnl-ppb-side-howworks { margin-top:18px; padding-top:14px; border-top:1px solid var(--hnl-divider); }
.hnl-ppb-side-howworks-h { font-size:13px; font-weight:600; margin-bottom:10px; }
.hnl-ppb-side-hw-row { display:flex; align-items:flex-start; gap:10px; margin-bottom:12px; }
.hnl-ppb-side-hw-row:last-child { margin-bottom:0; }
.hnl-ppb-side-hw-icon { width:30px; height:30px; border-radius:50%; background:var(--hnl-red-soft); color:var(--hnl-icon);
	display:flex; align-items:center; justify-content:center; font-size:13px; flex:0 0 auto; }
.hnl-ppb-side-hw-title { font-size:12.5px; font-weight:600; }
.hnl-ppb-side-hw-sub { font-size:13px; color:var(--hnl-gray); }

/* ---- B-UX-1B (Scope 5): mobile sticky SUMMARY bar — item count + subtotal + "View summary".
   Replaces the old CTA-centric sticky bar. Mobile-only (desktop uses the persistent sidebar).
   Tapping it opens the bottom drawer. Because navigation is now IN-PANEL (Continue on steps 1-3,
   Add to cart on the review step), the in-panel review submit is NO LONGER hidden on mobile. ---- */
.hnl-ppb-summbar { display:none; }
@media (max-width:860px) {
	.hnl-ppb-summbar { display:flex; align-items:center; justify-content:space-between; gap:12px;
		position:fixed; left:0; right:0; bottom:0; z-index:9000; cursor:pointer;
		background:var(--hnl-white); border-top:1px solid var(--hnl-divider); padding:12px 16px;
		box-shadow:0 -6px 16px rgba(0,0,0,0.10); }
	.hnl-ppb-summbar-left { display:flex; align-items:center; gap:10px; min-width:0; }
	.hnl-ppb-summbar-thumb { width:34px; height:34px; flex:0 0 auto; border-radius:7px; overflow:hidden;
		background:var(--hnl-soft-gray); border:1px solid var(--hnl-divider); display:block; }
	.hnl-ppb-summbar-thumb img { width:100%; height:100%; object-fit:cover; display:block; }
	.hnl-ppb-summbar-meta { display:flex; flex-direction:column; line-height:1.2; min-width:0; }
	.hnl-ppb-summbar-count { font-size:13px; font-weight:600; color:var(--hnl-charcoal); }
	.hnl-ppb-summbar-subtotal { font-size:12.5px; color:var(--hnl-gray); }
	.hnl-ppb-summbar-view { display:inline-flex; align-items:center; gap:5px; flex:0 0 auto;
		color:var(--hnl-red); font-weight:600; font-size:13.5px; white-space:nowrap; }
	.hnl-ppb-summbar-caret { font-size:10px; }
	/* R3 (#9) carried: reserve room so the fixed bar never covers the in-panel Continue/Add/Back. */
	#hnl-pp-builder-root.has-sticky .hnl-ppb-main-col { padding-bottom:84px; }
}

/* ---- B-UX-1B (Scope 6): mobile bottom summary drawer. Its body reuses sidebarMarkup() verbatim. ---- */
/* R1.1.3 (item 3): raised to match the lightbox's ultra-high z-index (was 9500) — with the drawer now
   a body portal this is purely defensive, guaranteeing it can never render under any theme element
   regardless of that theme's own z-index choices. */
.hnl-ppb-drawer-overlay { position:fixed; inset:0; z-index:2147483000; background:rgba(0,0,0,0.55); display:flex; align-items:flex-end; }
/* R1.1.3 (item 3): max-height gained a `dvh` companion (kept `vh` as the fallback). On a real phone,
   at initial page load before the first scroll, the browser's own address-bar/toolbar chrome is still
   expanded, so the plain `vh` unit (which represents the LARGEST possible viewport, i.e. assumes the
   toolbar will eventually collapse) computes LARGER than what is actually visible on-screen at that
   moment — an 85vh-tall panel could therefore render partly under that still-expanded toolbar. `dvh`
   tracks the CURRENTLY visible viewport instead, so the panel is correctly sized even before any
   scroll happens. A small safe-area-aware top inset is added too, as extra breathing room near a
   notch/dynamic-island on very short viewports.
   R1.1.5: background is now the LITERAL #ffffff (was var(--hnl-white), which — see the R1.1.5 note on
   the palette block above — silently resolved to nothing once this panel became part of a body portal,
   the actual cause of the "semi-transparent, product list bleeds through" bug). opacity:1 is explicit
   and redundant on top of the palette-scope fix, exactly per the owner-approved direction, so this
   panel can never be transparent regardless of any other cascading rule. */
.hnl-ppb-drawer { background:#ffffff; opacity:1; width:100%; max-height:85vh; max-height:85dvh; overflow-y:auto; position:relative;
	border-radius:16px 16px 0 0; padding:8px 16px 16px; padding-top:max(8px, env(safe-area-inset-top, 0px)); box-shadow:0 -10px 30px rgba(0,0,0,0.20); }
/* R1.1 (Issue 3): the slide-up entry animation runs ONLY on the render that first opens the drawer
   (.is-opening). Re-renders while the drawer stays open — e.g. toggling "View all discount tiers" —
   rebuild the drawer DOM without this class, so the drawer no longer appears to re-open/flash. */
.hnl-ppb-drawer.is-opening { animation:hnl-ppb-drawer-up 0.22s ease-out; }
@keyframes hnl-ppb-drawer-up { from { transform:translateY(100%); } to { transform:translateY(0); } }
.hnl-ppb-drawer-handle { width:40px; height:4px; border-radius:999px; background:var(--hnl-divider); margin:6px auto 10px; }
/* R1.1.3 (item 3): bumped from 32px to a full 44px tap target (consistent with the lightbox close).
   R1.1.5: color hardened to the literal #101010 (was var(--hnl-gray), silently broken for the same
   portal-scope reason as the panel background above) so the drawer's own close X is guaranteed
   visible/tappable per the ticket's explicit requirement, not just repaired incidentally by the scope
   fix. */
.hnl-ppb-drawer-close { position:absolute; top:8px; right:12px; width:44px; height:44px; border:0; background:transparent;
	font-size:24px; line-height:1; color:#101010; opacity:1; cursor:pointer; display:flex; align-items:center; justify-content:center; }
.hnl-ppb-drawer-continue { width:100%; margin-top:12px; padding:13px 16px; border:0; border-radius:10px;
	background:#141414; color:#ffffff; font-weight:600; font-size:15px; cursor:pointer; }
.hnl-ppb-drawer-continue:hover { background:#000000; }

.hnl-ppb-step { margin:0 0 16px; }
.hnl-ppb-step:last-of-type { margin-bottom:0; }
.hnl-ppb-step-helper { font-size:13px; color:var(--hnl-gray); margin:0 0 12px; }
.hnl-ppb-step--muted { opacity:.7; }
.hnl-ppb-gate { font-size:13px; color:var(--hnl-gray); border:1px dashed var(--hnl-divider); border-radius:10px; padding:12px; text-align:center; }
/* R5 (#1): required-selection inline error — never a silent block, always a clear visible prompt. */
/* R1.1.3 (item 4): OWNER-APPROVED validation-alert styling, applied exactly as specified. This
   specific pink-tinted fill is a DELIBERATE, EXPLICITLY-SCOPED exception to the "no pink fills"
   direction — it is allowed ONLY for this one validation/error alert class. It must not be copied to
   any other component (selected states, buttons, summary cards, free-shipping/add-more callouts all
   stay black/neutral — see the R1.1 palette lock, unchanged). #850000 is NOT used here (border is
   plain black, matching the owner's spec, not the brand accent). */
.hnl-ppb-step-error { font-size:15px; font-weight:600; color:var(--hnl-ink); background:#fff2f2;
	border:1px solid #000000; border-left:7px solid #000000;
	border-radius:9px; padding:10px 12px 10px 10px; margin-bottom:12px; scroll-margin-top:var(--hnl-pp-desktop-scroll-offset, var(--hnl-pp-scroll-offset, 80px)); }
/* R1.1 (Issue 2): validation-error scroll uses the SAME configured desktop builder offset on desktop
   (so a blocked Continue lands the error below the header); mobile keeps the measured/80px fallback. */
@media (max-width:860px) { .hnl-ppb-step-error { scroll-margin-top:var(--hnl-pp-scroll-offset, 80px); } }
/* R6.1 (#2): the error receives programmatic focus so screen readers announce it; suppress the
   default focus ring so the guided UI (which has no other visible outlines) doesn't sprout one. */
.hnl-ppb-step-error:focus { outline:none; }
/* R5 Addendum: search no-results state. */
.hnl-ppb-no-results { font-size:13px; color:var(--hnl-gray); text-align:center; padding:20px 12px;
	border:1px dashed var(--hnl-divider); border-radius:10px; }

/* size */
.hnl-ppb-sizes { display:flex; gap:10px; }
.hnl-ppb-size { flex:1; border:1.5px solid var(--hnl-divider); background:var(--hnl-white); border-radius:10px; padding:12px 14px; cursor:pointer;
	font:inherit; text-align:left; color:var(--hnl-ink); position:relative; }
.hnl-ppb-size-nm { display:block; font-weight:600; font-size:14.5px; }
.hnl-ppb-size-px { display:block; font-size:12px; color:var(--hnl-gray); margin-top:2px; }
.hnl-ppb-size.is-active { border-color:var(--hnl-red); box-shadow:inset 0 0 0 1px var(--hnl-red); }
.hnl-ppb-size-note { font-size:12px; color:var(--hnl-gray); margin:10px 2px 0; }
.hnl-ppb-size-badge { position:absolute; top:-7px; right:-7px; background:var(--hnl-red); color:var(--hnl-white); font-size:11px;
	font-weight:700; line-height:1; border-radius:999px; padding:4px 6px; box-shadow:0 0 0 2px var(--hnl-white); }
.hnl-ppb-size-check { position:absolute; top:10px; right:10px; width:22px; height:22px; border-radius:50%; border:1.5px solid var(--hnl-divider);
	background:var(--hnl-white); }
.hnl-ppb-size.is-active .hnl-ppb-size-check { background:var(--hnl-red); border-color:var(--hnl-red); color:var(--hnl-white);
	display:flex; align-items:center; justify-content:center; font-size:12px; }
/* R6 (#1): selector-group cards (e.g. Tea Thyme scents) squeezed into a single flex row clip on
   narrow screens. On mobile, wrap them — two per row where they fit, collapsing to full width for a
   long label — so every option stays readable and tappable and nothing is cut off. min-width caps
   the row at two so a third can never squeeze in; padding-right reserves room for the check circle
   (absolute, top/right) so the label never runs under it; overflow-wrap breaks a long label inside
   the card instead of overflowing. The Continue button sits in the step footer and is untouched. */
@media (max-width:860px) {
	.hnl-ppb-sizes { flex-wrap:wrap; }
	.hnl-ppb-size { flex:1 1 calc(50% - 5px); min-width:calc(50% - 5px); padding-right:38px; }
	.hnl-ppb-size-nm { overflow-wrap:anywhere; }
}

/* ---- R3 (#3): product grid — DESKTOP uses larger card-based layout (mockup direction); MOBILE
   keeps R2's compact rows. Same DOM/class structure both ways; CSS Grid areas do the rearranging,
   so no separate markup is needed per breakpoint. ---- */
.hnl-ppb-grid { display:grid; grid-template-columns:repeat(3, 1fr); gap:12px; }
/* R4 (#1): correct responsive breakpoints — 3 columns is the desktop default; a narrower
   desktop/tablet-wide window drops to 2 columns so cards never get too cramped; the existing
   860px breakpoint below switches to mobile's compact rows entirely (unchanged). */
@media (max-width:900px) and (min-width:861px) { .hnl-ppb-grid { grid-template-columns:repeat(2, 1fr); } }

/* R4 Addendum: real batch-reveal pagination for long lists (6 desktop / 5 mobile per batch) —
   no scroll box, no max-height crop, on EITHER breakpoint: only the currently-visible batch (plus
   any selected items outside it — see selection-safety in scentsMarkup()) is ever rendered, so
   the page always scrolls naturally with no nested scroll trap. The explicit "Showing X of Y"
   cue and "Show N more" / "Show fewer" control are never scrollbar-dependent. */
.hnl-ppb-grid-cap-note { display:flex; align-items:center; justify-content:space-between; gap:10px;
	margin-top:10px; padding-top:10px; border-top:1px solid var(--hnl-divider); font-size:12.5px; color:var(--hnl-gray); }
.hnl-ppb-show-more { border:1px solid var(--hnl-divider); background:var(--hnl-white); color:var(--hnl-red);
	font:inherit; font-weight:600; font-size:12.5px; border-radius:8px; padding:7px 14px; cursor:pointer; flex:0 0 auto; }
.hnl-ppb-show-more:hover { background:var(--hnl-red-soft); }

/* R4 Addendum (optional search, families with >12 products): client-side name filter only. */
.hnl-ppb-search-wrap { margin-bottom:10px; }
.hnl-ppb-search { width:100%; border:1.5px solid var(--hnl-divider); border-radius:9px; padding:9px 12px;
	font:inherit; font-size:13.5px; color:var(--hnl-ink); background:var(--hnl-white); }
.hnl-ppb-search:focus { outline:none; border-color:var(--hnl-red); }

.hnl-ppb-card { border:1px solid var(--hnl-divider); border-radius:12px; background:var(--hnl-white); padding:14px;
	display:grid; gap:6px 8px;
	grid-template-columns:1fr auto auto;
	grid-template-areas:
		"price price check"
		"name  name  name"
		"tags  tags  tags"
		"img   img   img"
		"control control control"; }
.hnl-ppb-card.is-active { border-color:var(--hnl-brand-soft); box-shadow:inset 0 0 0 1px var(--hnl-brand-soft), 0 0 10px 4px var(--hnl-brand-glow); }
.hnl-ppb-card-tags { grid-area:tags; display:flex; flex-wrap:wrap; gap:4px; min-height:1px; }
.hnl-ppb-tag { font-size:10.5px; font-weight:600; color:var(--hnl-charcoal); background:var(--hnl-soft-gray);
	border:1px solid var(--hnl-divider); border-radius:999px; padding:2px 8px; white-space:nowrap; }
.hnl-ppb-price { grid-area:price; font-size:14px; font-weight:700; color:var(--hnl-red); align-self:center; }
/* B-MOB-1 (A1): on DESKTOP a uniform-price group keeps the single price in the step header and the
   per-card price is hidden — visually identical to the prior build, where this cell rendered empty.
   The mobile block below re-shows it (and drops the header price there instead). */
.hnl-ppb-price--uniform { visibility:hidden; }
.hnl-ppb-card-check { grid-area:check; justify-self:end; align-self:center; width:24px; height:24px; border-radius:50%;
	border:1.5px solid var(--hnl-divider); background:var(--hnl-white); display:flex; align-items:center; justify-content:center;
	font-size:13px; color:var(--hnl-white); }
.hnl-ppb-card.is-active .hnl-ppb-card-check { background:var(--hnl-red); border-color:var(--hnl-red); }
.hnl-ppb-name { grid-area:name; font-weight:600; font-size:14px; line-height:1.25; text-align:left; }
.hnl-ppb-img { grid-area:img; width:100%; aspect-ratio:1/1; border-radius:9px; background:var(--hnl-soft-gray);
	display:grid; place-items:center; overflow:hidden; position:relative; border:1px solid var(--hnl-divider); cursor:zoom-in; }
.hnl-ppb-img img { width:100%; height:100%; object-fit:cover; }
.hnl-ppb-noimg { width:40%; height:40%; border-radius:50%; background:var(--hnl-divider); display:block; }
.hnl-ppb-card-control { grid-area:control; }
.hnl-ppb-add { border:0; background:var(--hnl-red); color:var(--hnl-white); font:inherit; font-weight:600; font-size:13px;
	border-radius:9px; padding:9px 16px; cursor:pointer; width:100%; }
.hnl-ppb-add:hover { background:var(--hnl-red-deep); }
.hnl-ppb-oos { font-size:12px; color:var(--hnl-gray); text-align:center; padding:8px 0; }
.hnl-ppb-stepper { display:flex; align-items:center; justify-content:space-between; border:1.5px solid var(--hnl-red);
	border-radius:9px; overflow:hidden; width:100%; }
.hnl-ppb-stepper button { border:0; background:var(--hnl-red-soft); width:36px; height:36px; font-size:16px; cursor:pointer;
	color:var(--hnl-red); font:inherit; flex:0 0 auto; }
.hnl-ppb-stepper button:active { background:#ffe0e0; }
.hnl-ppb-val { font-weight:700; font-size:14px; color:var(--hnl-red); flex:1 1 auto; text-align:center; }

/* B-MOB-1 (A1): mobile — product-forward vertical showcase (name over image over a single control
   row), replacing the prior 48px thumbnail row. Balanced variant: a ~170px image stage keeps ~2
   cards per viewport, richer than the old row but far less scroll than one-product-per-screen.
   Desktop (>860px, the base rules above) is untouched. */
@media (max-width:860px) {
	.hnl-ppb-grid { grid-template-columns:1fr; gap:12px; border:0; }
	.hnl-ppb-card { border:1px solid var(--hnl-divider); border-radius:14px; background:var(--hnl-white); padding:0; overflow:hidden;
		/* Vertical stack. The final row is a 2-column strip: the left column holds the price+badge
		   cluster, the right column holds Add+/stepper. Price, badge and control are separate DOM
		   siblings, so they're placed onto this shared row by named areas rather than wrapped in one
		   flex box (which would need markup changes). "tags" sits under the name; when absent it
		   collapses to zero height. */
		grid-template-columns:1fr auto;
		grid-template-areas:
			"name    name"
			"tags    tags"
			"img     img"
			"pricebx control"; align-items:center; gap:0; }
	.hnl-ppb-card.is-active { background:var(--hnl-white); border-color:var(--hnl-brand-soft);
		box-shadow:0 0 0 1px var(--hnl-brand-soft) inset; }
	/* product name — prominent, centered, above the image (Pic 2). Full title as-is; no transform. */
	.hnl-ppb-name { grid-area:name; font-size:17px; font-weight:700; line-height:1.2; text-align:center;
		align-self:auto; padding:14px 14px 8px; letter-spacing:-.01em; }
	/* image stage — large, label legible; contain (not cover) so the whole stick shows.
	   position:relative makes it the containing block for the scarcity overlay below. */
	.hnl-ppb-img { grid-area:img; width:auto; height:170px; aspect-ratio:auto; border-radius:0; margin:0 14px 12px;
		border:1px solid var(--hnl-divider); background:var(--hnl-soft-gray); position:relative; overflow:hidden; }
	/* B-MOB-IMG-Y-1: per-family vertical nudge of the card image on mobile only. The var is set
	   inline on #hnl-pp-builder-root per family; unset/0 => translateY(0px) => current layout.
	   The stage's overflow:hidden clips any part pushed past the edge. Desktop rule (outside this
	   @media) has no transform, so desktop is unchanged. */
	.hnl-ppb-img img { object-fit:contain; transform:translateY(var(--hnl-ppb-mobile-card-img-y, 0px)); }
	/* LEFT of the control row: just the price, in normal flow (no absolute pull). */
	.hnl-ppb-price { grid-area:pricebx; align-self:center; justify-self:start;
		font-size:18px; font-weight:700; color:var(--hnl-red); padding:0 0 14px 14px; }
	.hnl-ppb-price--uniform { visibility:visible; }
	/* R1.2: scarcity badge is a STABLE top-left overlay ON the image stage. The .hnl-ppb-badge already
	   lives inside .hnl-ppb-img (the markup emits it there), so it anchors to the fixed-size stage and
	   cannot be clipped or collide with the price — unlike the R1.1 absolute-above-price pull, which
	   vanished at real mobile metrics. The separate .hnl-ppb-card-badge pill is hidden on mobile. */
	.hnl-ppb-img .hnl-ppb-badge { display:inline-flex; position:absolute; top:8px; left:8px; z-index:2;
		align-items:center; font-size:10.5px; font-weight:700; line-height:1; padding:4px 8px; border-radius:99px;
		box-shadow:0 1px 3px rgba(16,16,16,.16); }
	.hnl-ppb-img .hnl-ppb-badge-low { background:#fff5e6; color:#a3681a; border:1px solid #f0d9af; }
	.hnl-ppb-img .hnl-ppb-badge-oos { background:var(--hnl-soft-gray); color:var(--hnl-gray); border:1px solid var(--hnl-divider); }
	.hnl-ppb-grid .hnl-ppb-card-badge { display:none; }
	.hnl-ppb-check, .hnl-ppb-card-check { display:none; }
	/* product tags render under the name, centered. */
	.hnl-ppb-card-tags { display:flex; grid-area:tags; justify-content:center; margin:-2px 0 2px; gap:4px; flex-wrap:wrap; }
	.hnl-ppb-tag { font-size:10px; padding:1px 7px; }
	/* RIGHT of the control row: Add+ / stepper. */
	.hnl-ppb-card-control { grid-area:control; justify-self:end; align-self:center; padding:0 14px 14px 0; }
	.hnl-ppb-card-control .hnl-ppb-add { width:auto; padding:11px 22px; font-size:14px; }
	.hnl-ppb-stepper button { width:42px; height:44px; font-size:18px; }
	.hnl-ppb-val { min-width:38px; }
	/* B-MOB-1 (A1): drop the price from the step header on MOBILE — the card now owns the price, so
	   showing it here too would repeat it. The size label (Regular/Jumbo) stays visible. Desktop keeps
	   both, unchanged. */
	.hnl-ppb-header-price { display:none; }
	.hnl-ppb-header-sep { display:none; }
}

/* R3 addendum + R1.1.1 (item 4) + R1.1.3 (items 1-2) + R1.1.4: image lightbox.
   R1.1.4 ROOT-CAUSE FIX: .hnl-ppb-lightbox-img previously used max-height:100% — a PERCENTAGE relative
   to the stage/modal. The modal's height was only ever constrained by max-height:90dvh (no explicit
   `height`), so its actual computed height was content-driven ("auto"). When a percentage-height
   descendant's own content is what drives that ancestor's auto height, the browser hits a genuine
   circular dependency and — per spec — treats the percentage as non-resolving, i.e. NO constraint at
   all: the image then rendered at its full intrinsic size, ballooning the stage/modal, which the
   modal's overflow:hidden then clipped unpredictably (the "huge white canvas" / "image missing or
   mispositioned" symptom). This ONLY appeared to work at <=600px because that breakpoint alone gave
   the modal an EXPLICIT height:100dvh (a genuinely definite size), which let the percentage resolve —
   which is exactly why the bug flipped precisely at the 600/601 boundary.
   THE FIX: the image's max-height is now an ABSOLUTE, VIEWPORT-DERIVED value — calc(100dvh - 190px) —
   instead of a percentage through the flex chain. This has NO dependency on whatever the modal/stage's
   own computed height happens to be, so it is correct at every width identically; there is no longer
   any breakpoint-specific override for the modal/image at all (the old @media (max-width:600px) block
   that gave the modal a special full-viewport `height` — the source of the discontinuity — is REMOVED
   entirely). The modal also gained an explicit `width` (not just max-width) for the same robustness on
   the horizontal axis. The close button is UNCHANGED from R1.1.3 — position:fixed, viewport-anchored,
   independent of the modal's size, which was already correct and is preserved as-is. */
.hnl-ppb-lightbox-overlay { position:fixed; inset:0; background:rgba(0,0,0,0.72); z-index:2147483000;
	display:flex; align-items:center; justify-content:center; }
.hnl-ppb-lightbox-modal { box-sizing:border-box; width:min(920px, calc(100vw - 32px));
	max-height:calc(100dvh - 48px); background:#ffffff; border-radius:12px;
	display:flex; flex-direction:column; overflow:hidden; }
/* R1.1.5: background/color hardened to literal #ffffff / #141414 (were var(--hnl-white)/var(--hnl-ink),
   silently broken once this button became part of a body portal — see the R1.1.5 note on the palette
   block above; that resolved to a transparent circle over the dark overlay with an inherited, likely
   dark/gray, glyph color, i.e. exactly "too faint... gray-on-gray or dark-on-dark"). opacity:1 is
   explicit so it can never be dimmed by any other cascading rule. */
.hnl-ppb-lightbox-close { position:fixed;
	top:max(12px, env(safe-area-inset-top, 0px)); right:max(12px, env(safe-area-inset-right, 0px));
	width:44px; height:44px; border-radius:999px;
	border:1px solid rgba(0,0,0,0.12); background:#ffffff; color:#141414; opacity:1; font-size:22px; line-height:1;
	cursor:pointer; display:flex; align-items:center; justify-content:center; box-shadow:0 6px 18px rgba(0,0,0,0.18);
	z-index:2147483002; }
.hnl-ppb-lightbox-stage { position:relative; display:flex; align-items:center; justify-content:center;
	flex:1 1 auto; min-height:0; overflow:hidden; padding:24px; }
.hnl-ppb-lightbox-img { display:block; width:auto; height:auto; max-width:100%;
	max-height:calc(100dvh - 190px); object-fit:contain; border-radius:8px; }
.hnl-ppb-lightbox-nav { position:absolute; top:50%; transform:translateY(-50%); width:44px; height:44px; border-radius:50%;
	border:1px solid var(--hnl-divider); background:rgba(255,255,255,0.92); color:var(--hnl-ink); font-size:22px; line-height:1;
	cursor:pointer; display:flex; align-items:center; justify-content:center; z-index:2; box-shadow:0 2px 8px rgba(0,0,0,0.15); }
.hnl-ppb-lightbox-prev { left:6px; }
.hnl-ppb-lightbox-next { right:6px; }
.hnl-ppb-lightbox-count { position:absolute; bottom:8px; left:50%; transform:translateX(-50%);
	background:rgba(16,16,16,0.6); color:#fff; font-size:12px; padding:3px 10px; border-radius:999px; }
.hnl-ppb-lightbox-thumbs { flex:0 0 auto; display:flex; justify-content:center; gap:8px; overflow-x:auto;
	width:100%; padding:12px 16px 16px; -webkit-overflow-scrolling:touch; }
.hnl-ppb-lightbox-thumb { flex:0 0 auto; width:54px; height:54px; padding:0; border-radius:7px; overflow:hidden;
	border:2px solid transparent; background:var(--hnl-soft-gray); cursor:pointer; }
.hnl-ppb-lightbox-thumb.is-active { border-color:var(--hnl-red); }
.hnl-ppb-lightbox-thumb img { width:100%; height:100%; max-height:none; border-radius:0; object-fit:cover; }
/* R1.1.4: the previous @media (max-width:600px) block here gave the modal a special full-viewport
   `height:100dvh` on mobile ONLY — that discrepancy (an explicit height at <=600px vs. only max-height
   above it) was the exact mechanism behind the 600/601 breakpoint discontinuity (see the lightbox rules
   above). Removed entirely: the unified width:min(920px, calc(100vw - 32px)) / max-height:calc(100dvh -
   48px) modal and the independent calc(100dvh - 190px) image sizing above already satisfy every mobile
   requirement (close visible, modal never under browser chrome, thumbnails usable) at every width
   identically, so no responsive override remains for the lightbox at all. */

/* R4 Addendum: background scroll lock while the lightbox is open. This CSS layer alone is
   sufficient on desktop; JS additionally applies a position:fixed technique for mobile Safari,
   where overflow:hidden alone does not reliably block touch-scroll. */
html.hnl-ppb-lightbox-open, body.hnl-ppb-lightbox-open { overflow:hidden !important; height:100%; }

/* plan */
.hnl-ppb-plans { display:flex; gap:9px; }
.hnl-ppb-pt { flex:1; border:1.5px solid var(--hnl-divider); background:var(--hnl-white); border-radius:10px; padding:10px 12px; cursor:pointer;
	font:inherit; text-align:center; color:var(--hnl-ink); }
.hnl-ppb-pt-nm { display:block; font-weight:600; font-size:13px; }
.hnl-ppb-pt-sub { display:block; font-size:11px; color:var(--hnl-brand); margin-top:1px; }
.hnl-ppb-pt.is-active { border-color:var(--hnl-brand-soft); background:var(--hnl-red-soft); box-shadow:inset 0 0 0 1px var(--hnl-brand-soft), 0 0 10px 4px var(--hnl-brand-glow); }
.hnl-ppb-intervals { margin-top:12px; }
.hnl-ppb-int-label { font-size:12px; color:var(--hnl-gray); margin-bottom:6px; }
.hnl-ppb-int-row { display:flex; gap:8px; flex-wrap:wrap; }
.hnl-ppb-int { border:1.5px solid var(--hnl-divider); background:var(--hnl-white); border-radius:9px; padding:8px 12px; cursor:pointer;
	font:inherit; font-size:12.5px; color:var(--hnl-ink); }
.hnl-ppb-int.is-active { border-color:var(--hnl-red); background:var(--hnl-red-soft); color:var(--hnl-red-deep); font-weight:600; box-shadow:0 0 10px 4px var(--hnl-brand-glow); }

/* savings ladder */
.hnl-ppb-ladder { display:flex; gap:7px; margin:14px 0 0; }
.hnl-ppb-rung { flex:1; text-align:center; font-size:11.5px; color:var(--hnl-gray); border:1px solid var(--hnl-divider);
	border-radius:9px; padding:7px 4px; background:var(--hnl-white); }
.hnl-ppb-rung b { display:block; font-size:12.5px; color:var(--hnl-ink); margin-bottom:1px; }
.hnl-ppb-rung.is-active { border-color:var(--hnl-red); background:var(--hnl-red-soft); color:var(--hnl-red-deep); }
.hnl-ppb-rung.is-active b { color:var(--hnl-red-deep); }
.hnl-ppb-nudge { font-size:12.5px; color:var(--hnl-red-deep); background:var(--hnl-red-soft); border:1px solid var(--hnl-divider); border-radius:10px;
	padding:9px 11px; margin-top:10px; }
.hnl-ppb-nudge--best { color:var(--hnl-red-deep); background:var(--hnl-red-soft); border-color:var(--hnl-divider); }
.hnl-ppb-ladder--mixed { margin-top:14px; display:flex; flex-direction:column; gap:12px; }
.hnl-ppb-ladder-group .hnl-ppb-ladder { margin-top:6px; }
.hnl-ppb-ladder-group-h { font-size:12px; font-weight:700; color:var(--hnl-red); text-transform:uppercase; letter-spacing:.02em; }

/* ---- R2 (E): Step 4 — the ONLY place the full Today/Renewal breakdown is shown ---- */
.hnl-ppb-summary { margin-top:16px; padding-top:14px; border-top:1px solid var(--hnl-divider); }
.hnl-ppb-sum-line { display:flex; justify-content:space-between; align-items:baseline; margin-bottom:12px; }
.hnl-ppb-sum-label { font-size:13px; color:var(--hnl-gray); }
.hnl-ppb-sum-total { font-weight:600; font-size:19px; }
.hnl-ppb-submit { display:block; width:100%; border:0; background:var(--hnl-red); color:var(--hnl-white); font:inherit;
	font-weight:600; font-size:16px; border-radius:10px; padding:14px; cursor:pointer; }
.hnl-ppb-submit:hover { background:var(--hnl-red-deep); }
.hnl-ppb-submit:disabled { background:var(--hnl-divider); color:var(--hnl-gray); cursor:not-allowed; }
.hnl-ppb-line-note { font-size:11.5px; color:var(--hnl-gray); text-align:center; margin-top:10px; }
.hnl-ppb-error { font-size:12.5px; color:var(--hnl-red-deep); background:var(--hnl-red-soft); border:1px solid var(--hnl-divider); border-radius:9px;
	padding:8px 10px; margin-top:10px; text-align:center; }

/* Two-line subscription quote (Today / Renews at) */
.hnl-ppb-quote-line { display:block; }
.hnl-ppb-quote-today { font-weight:600; }
.hnl-ppb-quote-renews { font-size:12.5px; color:var(--hnl-gray); margin-top:2px; }
.hnl-ppb-quote-group { text-align:right; margin-bottom:6px; padding-bottom:6px; border-bottom:1px dashed var(--hnl-divider); }
.hnl-ppb-quote-group-h { font-size:11px; font-weight:700; color:var(--hnl-gray); text-transform:uppercase; letter-spacing:.02em; }
.hnl-ppb-quote-grand { margin-top:2px; }

/* B-Stock: stock states — untouched behavior, palette aligned */
.hnl-ppb-card.is-unavailable { cursor:pointer; background:var(--hnl-soft-gray); }
.hnl-ppb-card.is-unavailable .hnl-ppb-img,
.hnl-ppb-card.is-unavailable .hnl-ppb-name,
.hnl-ppb-card.is-unavailable .hnl-ppb-price,
.hnl-ppb-card.is-unavailable .hnl-ppb-oos { opacity:0.55; filter:grayscale(0.3); }
.hnl-ppb-card.is-unavailable .hnl-ppb-name,
.hnl-ppb-card.is-unavailable .hnl-ppb-price { color:var(--hnl-gray); }
.hnl-ppb-badge { position:absolute; top:4px; left:4px; font-size:9.5px; font-weight:700;
	padding:2px 5px; border-radius:6px; letter-spacing:0.02em; text-transform:uppercase; }
.hnl-ppb-badge-oos { background:var(--hnl-soft-gray); color:var(--hnl-gray); border:1px solid var(--hnl-divider); }
.hnl-ppb-badge-low { background:#fff5e6; color:#a3681a; border:1px solid #f0d9af; }
/* R6 (#4): compact stock pill shown UNDER the title on mobile. The mobile card media query places
   it in the badge grid area; desktop keeps the in-image badge instead and hides this pill.
   R6.2: the pill's default display is inline-flex and it is hidden ONLY on desktop via a
   min-width:861px query. (Previously the base rule set display:none, which — sitting AFTER the
   max-width:860px block in source order at equal specificity — overrode the mobile reveal and hid
   the pill on mobile too. The two breakpoints are mutually exclusive, so there is no longer any
   source-order cascade conflict at any width.) */
.hnl-ppb-card-badge { display:inline-flex; width:fit-content; align-items:center; font-size:10.5px; font-weight:700;
	line-height:1; letter-spacing:0.02em; text-transform:uppercase; padding:3px 8px; border-radius:999px; }
@media (min-width:861px) { .hnl-ppb-card-badge { display:none; } }
.hnl-ppb-card-badge-oos { background:var(--hnl-soft-gray); color:var(--hnl-gray); border:1px solid var(--hnl-divider); }
.hnl-ppb-card-badge-low { background:#fff5e6; color:#a3681a; border:1px solid #f0d9af; }
.hnl-ppb-oos { font-size:12px; color:var(--hnl-gray); font-weight:600; }
.hnl-ppb-stepper button[disabled] { opacity:0.4; cursor:not-allowed; }

/* B-Stock: above-grid notice + card-level message + affected-card highlight. */
.hnl-ppb-card-msg { font-size:12px; color:var(--hnl-red-deep); background:var(--hnl-red-soft); border:1px solid var(--hnl-divider);
	border-radius:8px; padding:7px 9px; margin-top:8px; line-height:1.35; font-weight:600; opacity:1; }
/* B-Stock: form-level notice (submit/network/stale only — NOT normal OOS clicks). */
.hnl-ppb-form-notice { font-size:12.5px; color:var(--hnl-red-deep); background:var(--hnl-red-soft); border:1px solid var(--hnl-divider);
	border-radius:9px; padding:8px 10px; margin-top:10px; text-align:center; }

/* B-Stock: click feedback = one-shot pulse (border + badge emphasis), no text, no shift. */
.hnl-ppb-card.is-pulse { animation:hnlppbPulse 0.7s ease-out; }
@keyframes hnlppbPulse {
	0%   { box-shadow:0 0 0 0 rgba(214,0,0,0.0); }
	30%  { box-shadow:0 0 0 3px rgba(214,0,0,0.35); }
	100% { box-shadow:0 0 0 0 rgba(214,0,0,0.0); }
}
.hnl-ppb-card.is-pulse .hnl-ppb-badge-oos {
	background:var(--hnl-red-deep); color:var(--hnl-white); border-color:var(--hnl-red-deep); transition:all 0.2s ease; }

/* ---- R1.1 (1C): line-icon glyphs as CSS masks over bundled local SVG files (assets/icons/*.svg).
   The mask's alpha defines the glyph; background-color:currentColor paints it, so the color comes
   from the parent's color (var(--hnl-icon) = #850000) and the surrounding badge/surface stays
   neutral, never pink. URLs are relative to this stylesheet (assets/css/ -> ../icons/). No external
   icon CDN/dependency. ---- */
.hnl-ppb-ic { width:1em; height:1em; display:inline-block; vertical-align:-0.15em; background-color:currentColor;
	-webkit-mask-repeat:no-repeat; mask-repeat:no-repeat; -webkit-mask-position:center; mask-position:center;
	-webkit-mask-size:contain; mask-size:contain; }
/* R1.1.3 (item 5): mask-image now uses an INLINE BASE64 DATA URI for each icon (generated from the
   exact bundled assets/icons/*.svg files below, byte-for-byte) instead of a separate url(../icons/
   NAME.svg) file reference. This makes icon RENDERING independent of whether the host allows direct
   .svg file requests: the diagnosis found direct SVG URLs returning 403 (a common hardened-host
   policy that blocks .svg file serving by extension), which would ALSO have blocked these exact
   CSS mask requests, since they were the SAME file requests. A data URI carries the icon's bytes
   INSIDE builder.css itself — which is already served successfully (nothing renders at all
   otherwise) — so there is no separate request left to be blocked. The .svg files themselves are
   STILL bundled (unchanged) for direct-URL verification once the narrow assets/icons/.htaccess
   (or an equivalent host-level allow) is applied; this CSS no longer depends on that succeeding. */
.hnl-ppb-ic--box     { -webkit-mask-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2Utd2lkdGg9IjEuNyIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cGF0aCBkPSJNMyA3bDktNCA5IDR2MTBsLTkgNC05LTR6Ii8+PHBhdGggZD0iTTMgN2w5IDQgOS00Ii8+PHBhdGggZD0iTTEyIDExdjEwIi8+PC9zdmc+Cg=="); mask-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2Utd2lkdGg9IjEuNyIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cGF0aCBkPSJNMyA3bDktNCA5IDR2MTBsLTkgNC05LTR6Ii8+PHBhdGggZD0iTTMgN2w5IDQgOS00Ii8+PHBhdGggZD0iTTEyIDExdjEwIi8+PC9zdmc+Cg=="); }
.hnl-ppb-ic--refresh { -webkit-mask-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2Utd2lkdGg9IjEuNyIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cGF0aCBkPSJNMjAgOGE4IDggMCAxIDAgLjYgNiIvPjxwYXRoIGQ9Ik0yMCAzdjVoLTUiLz48L3N2Zz4K"); mask-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2Utd2lkdGg9IjEuNyIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cGF0aCBkPSJNMjAgOGE4IDggMCAxIDAgLjYgNiIvPjxwYXRoIGQ9Ik0yMCAzdjVoLTUiLz48L3N2Zz4K"); }
.hnl-ppb-ic--truck   { -webkit-mask-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2Utd2lkdGg9IjEuNyIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cGF0aCBkPSJNMyA2aDExdjlIM3oiLz48cGF0aCBkPSJNMTQgOWgzLjVMMjEgMTJ2M2gtN3oiLz48Y2lyY2xlIGN4PSI3IiBjeT0iMTgiIHI9IjEuNyIvPjxjaXJjbGUgY3g9IjE3LjUiIGN5PSIxOCIgcj0iMS43Ii8+PC9zdmc+Cg=="); mask-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2Utd2lkdGg9IjEuNyIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cGF0aCBkPSJNMyA2aDExdjlIM3oiLz48cGF0aCBkPSJNMTQgOWgzLjVMMjEgMTJ2M2gtN3oiLz48Y2lyY2xlIGN4PSI3IiBjeT0iMTgiIHI9IjEuNyIvPjxjaXJjbGUgY3g9IjE3LjUiIGN5PSIxOCIgcj0iMS43Ii8+PC9zdmc+Cg=="); }
.hnl-ppb-ic--gift    { -webkit-mask-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2Utd2lkdGg9IjEuNyIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cGF0aCBkPSJNNCAxMWgxNnY5SDR6Ii8+PHBhdGggZD0iTTMgN2gxOHY0SDN6Ii8+PHBhdGggZD0iTTEyIDd2MTMiLz48cGF0aCBkPSJNMTIgN0MxMSA0IDkgMy41IDggNC41UzguNSA3IDEyIDd6Ii8+PHBhdGggZD0iTTEyIDdjMS0zIDMtMy41IDQtMi41UzE1LjUgNyAxMiA3eiIvPjwvc3ZnPgo="); mask-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2Utd2lkdGg9IjEuNyIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cGF0aCBkPSJNNCAxMWgxNnY5SDR6Ii8+PHBhdGggZD0iTTMgN2gxOHY0SDN6Ii8+PHBhdGggZD0iTTEyIDd2MTMiLz48cGF0aCBkPSJNMTIgN0MxMSA0IDkgMy41IDggNC41UzguNSA3IDEyIDd6Ii8+PHBhdGggZD0iTTEyIDdjMS0zIDMtMy41IDQtMi41UzE1LjUgNyAxMiA3eiIvPjwvc3ZnPgo="); }
.hnl-ppb-ic--repeat  { -webkit-mask-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2Utd2lkdGg9IjEuNyIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cGF0aCBkPSJNMTcgMmw0IDQtNCA0Ii8+PHBhdGggZD0iTTMgMTFWOWE0IDQgMCAwIDEgNC00aDE0Ii8+PHBhdGggZD0iTTcgMjJsLTQtNCA0LTQiLz48cGF0aCBkPSJNMjEgMTN2MmE0IDQgMCAwIDEtNCA0SDMiLz48L3N2Zz4K"); mask-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2Utd2lkdGg9IjEuNyIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cGF0aCBkPSJNMTcgMmw0IDQtNCA0Ii8+PHBhdGggZD0iTTMgMTFWOWE0IDQgMCAwIDEgNC00aDE0Ii8+PHBhdGggZD0iTTcgMjJsLTQtNCA0LTQiLz48cGF0aCBkPSJNMjEgMTN2MmE0IDQgMCAwIDEtNCA0SDMiLz48L3N2Zz4K"); }
.hnl-ppb-ic--bag     { -webkit-mask-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2Utd2lkdGg9IjEuNyIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cGF0aCBkPSJNNiA3aDEybDEgMTNINXoiLz48cGF0aCBkPSJNOSA3VjUuNWEzIDMgMCAwIDEgNiAwVjciLz48L3N2Zz4K"); mask-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2Utd2lkdGg9IjEuNyIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cGF0aCBkPSJNNiA3aDEybDEgMTNINXoiLz48cGF0aCBkPSJNOSA3VjUuNWEzIDMgMCAwIDEgNiAwVjciLz48L3N2Zz4K"); }
.hnl-ppb-ic--check   { -webkit-mask-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2Utd2lkdGg9IjEuNyIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cGF0aCBkPSJNMjAgNkw5IDE3bC01LTUiLz48L3N2Zz4K"); mask-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2Utd2lkdGg9IjEuNyIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cGF0aCBkPSJNMjAgNkw5IDE3bC01LTUiLz48L3N2Zz4K"); }
.hnl-ppb-side-hw-icon { display:flex; align-items:center; justify-content:center; font-size:15px; }
.hnl-ppb-side-hw-icon .hnl-ppb-ic { width:17px; height:17px; }
.hnl-ppb-side-shipping-icon { display:inline-flex; }
.hnl-ppb-side-shipping-icon .hnl-ppb-ic { width:18px; height:18px; }
.hnl-ppb-side-icon .hnl-ppb-ic { width:16px; height:16px; }
/* Step 3 purchase cards: icon glyph in #850000 above the label. */
.hnl-ppb-pt-icon { display:block; color:var(--hnl-icon); margin-bottom:6px; line-height:0; }
.hnl-ppb-pt-icon .hnl-ppb-ic { width:22px; height:22px; }
/* Discount nudge: neutral surface, #850000 icon, text next to it. */
.hnl-ppb-nudge { display:flex; align-items:center; gap:8px; }
.hnl-ppb-nudge-ic { display:inline-flex; color:var(--hnl-icon); flex:0 0 auto; }
.hnl-ppb-nudge-ic .hnl-ppb-ic { width:18px; height:18px; }

/* ---- R1.1 (8): typography polish (CSS-only; no admin font controls). Appended so these win at
   equal specificity. All selectors verified present; ".hnl-ppb-step small" targets the existing
   group-header <small> inside the step container. ---- */
.hnl-ppb-accordion-eyebrow { font-size:16.5px; }
.hnl-ppb-size-px { font-size:16px; }
.hnl-ppb-size-note { font-size:15px; }
.hnl-ppb-step small { font-size:125%; }
.hnl-ppb-accordion-summary { font-size:16px; }
.hnl-ppb-pt-sub { font-size:16px; }
.hnl-ppb-pt-nm { font-size:16px; }
.hnl-ppb-int-label { font-size:16px; font-weight:600; margin-top:16px; margin-bottom:16px; }
.hnl-ppb-rung { font-size:15px; }
