.hh-comfort-set{
    --bg: #14161B;
    --panel: #1C1F26;
    --panel-raised: #23262E;
    --hairline: #34383F;
    --brass: #B8874A;
    --brass-bright: #D3A667;
    --steel-blue: #55707F;
    /* Discount-green pair, same relationship as brass/brass-bright above:
       --deal-green is the fill/border tone (also .addon-add.added's exact
       background), --deal-green-bright is a punchier, more saturated
       foreground for plain green TEXT that sits directly on the dark page
       - see the callout comment a few lines down for why this second
       shade exists. */
    --deal-green: #3E5A3F;
    --deal-green-bright: #5DB660;
    --text: #F1EDE6;
    --text-dim: #A6ABB4;
    --text-faint: #6C7078;
    --radius-card: 2px;
    --radius-pill: 999px;
    --maxw: 1180px;
  }

  .hh-comfort-set, .hh-comfort-set *{box-sizing:border-box;}
  /* overflow-anchor:none is here because the "smart" compact header
     below changes its own height on scroll (collapsing the nav on the way
     down), and without this, the browser's scroll-anchoring feature tries
     to compensate for that height change by nudging window.scrollY, which
     re-fires the scroll listener and creates a rapid feedback loop
     (confirmed - visible as constant flicker between the compact/full
     states). Turning anchoring off removes that feedback loop entirely.
     overflow-x:clip is back for a narrower reason than before: the
     dvw-based breakout below is mathematically exact, but at certain
     browser zoom levels Chromium's layout engine rounds the breakout's
     dvw-based width and its ancestor's percentage-based width to
     sub-pixel device units independently, and the two can land a hair
     apart - enough for Chrome to show a horizontal scrollbar (it does
     this for any overflow above zero, even a fraction of a pixel), even
     though nothing is actually misaligned on screen. That's a zoom-
     rounding artifact, not a layout bug, and no formula can zero it out
     at literally every possible zoom fraction. "clip" (never "hidden")
     is the safe way to absorb it: unlike hidden, it does not force the
     other axis to auto-compute, so it never turns html/body into a
     scroll container and never breaks position:sticky (confirmed earlier
     via isolated Playwright testing on this exact header) - and it never
     hides real content either, since nothing is ever meant to render
     past the true viewport edge in the first place; it only ever
     swallows this invisible sub-pixel remainder. */
  html, body{ overflow-x:clip; overflow-anchor:none; }
  /* Same safety net, extended to cover the one theme-specific case where
     it's actually needed: on this store's live theme (Shopify's
     "Horizon"), html/body are deliberately never the scrolling element
     on desktop - Horizon's own CSS hands that job to .page-wrapper
     instead (confirmed directly against the theme's files) - so the
     clip above, while harmless, provides no protection there at all.
     This line is that same protection, on the element that actually
     needs it on this theme. Bare/unscoped, like the html,body rule
     above, since .page-wrapper is an ANCESTOR the theme renders, not a
     descendant this snippet owns - inert (matches nothing) on any theme
     without this class, so it's safe to ship unconditionally. */
  .page-wrapper{ overflow-x:clip; }
  html{scroll-behavior:smooth;}
  /* ---------- Custom auto-hide scrollbar (all widths) ----------
     A restyled NATIVE scrollbar can only ever be recoloured/resized through
     scrollbar-color/-width and ::-webkit-scrollbar* - it can't fade while
     idle, sit inset from the true edge, or start below the sticky header,
     since none of that is reachable through those properties; a native
     scrollbar always draws flush against the full height of whichever box
     is scrolling. Getting all three means hiding the real one everywhere
     and drawing a small fixed-position div of our own instead
     (#hhScrollThumb, created and kept in sync with the real scroll
     position by the JS near the top of the <script> block below) - real
     scrolling itself (wheel, trackpad, keyboard, touch) is completely
     unaffected, only the native visual chrome is swapped out, and
     click/touch-drag is reimplemented on the replacement so nothing
     usable is lost.
     Both html and .page-wrapper are hidden, unconditionally, because
     which one is the real scroll host on THIS theme depends on viewport
     width: Horizon hands scrolling to .page-wrapper only from 990px up
     (see the overflow-x:clip comment above) and leaves it to html/body
     below that - hiding both, at every width, covers whichever one is
     actually active without needing to know which that is; the JS side
     of this figures that same thing out live (hhGetScrollHost) rather
     than assuming a breakpoint too.
     body is included alongside html/.page-wrapper as a defensive extra -
     standards-mode browsers scroll via document.scrollingElement (html),
     not body, but this costs nothing if body never actually needs it.
     -ms-overflow-style is old Edge/IE's equivalent of scrollbar-width -
     harmless, ignored everywhere else. None of this can be guaranteed
     100% universal: a few mobile browser engines keep drawing a minimal
     native scroll indicator on the page itself (as opposed to an ordinary
     internal scrolling div, which every engine tested here fully honours
     this on) regardless of what CSS asks for, as a deliberate
     discoverability floor - if a hairline sliver still shows through on a
     specific device after this, that's most likely what's left, not a
     sign this rule isn't being applied.
     !important added on both rules below after actually pulling this
     theme's own base.css and finding it carries its OWN global scrollbar
     rule - a bare, unscoped `::-webkit-scrollbar{width:20px}` with a
     20px-wide, foreground-coloured (not brand-gold) thumb, meant for
     ordinary internal scrolling elements site-wide. A same-element,
     more-specific selector like html::-webkit-scrollbar already wins
     against that on specificity alone without needing !important, so
     this shouldn't change anything by itself - it's cheap insurance
     against a persistent report of a grey edge that's now known to
     plausibly be exactly this theme rule's grey/foreground colour
     showing through somewhere our own hiding rule isn't fully landing,
     for a reason not yet pinned down. */
  html, body, .page-wrapper{
    scrollbar-width:none !important;
    -ms-overflow-style:none;
  }
  html::-webkit-scrollbar, body::-webkit-scrollbar, .page-wrapper::-webkit-scrollbar{ display:none !important; }
  #hhScrollThumb{
    position:fixed;
    right:1px;
    width:6px;
    min-height:36px;
    border-radius:999px;
    /* Back to the site's own brand gold/brass (the same #D3A667/#B8874A
       pair the header border/nav CTA use, via --brass-bright/--brass)
       rather than the brighter, more saturated gold tried previously -
       that looked off-brand next to the page's actual buttons. Hardcoded
       here rather than var(--brass-bright)/var(--brass): those custom
       properties are declared on .hh-comfort-set's own scope, and this
       thumb is deliberately appended straight to <body> (not as a
       descendant of .hh-comfort-set) so its position:fixed coordinates
       are always relative to the real viewport - so the vars are out of
       scope here and would silently compute the whole property to
       nothing. Same reason the pre-existing native-scrollbar CSS below
       already hardcodes these two colours instead of using var(). */
    background:linear-gradient(180deg, #D3A667, #B8874A);
    box-shadow:0 0 0 1px rgba(0,0,0,0.35);
    opacity:0;
    pointer-events:auto;
    cursor:grab;
    /* Above the sticky header (z-index 50) so it stays visible once
       scrolled; below the toast/sticky-cart-bar (100/200) and well below
       the cart drawer (300/301) so it never competes with anything more
       important - moot for the drawer anyway since it's hidden outright
       while that's open (see hhSuppressScrollThumb in the script). */
    z-index:60;
    transition:opacity .3s ease, width .15s ease;
  }
  /* pointer-events stay on even at opacity:0, deliberately - hovering right
     at the true edge (where a scrollbar would be) reveals it even if nothing
     has been scrolled yet, same "hover the edge" affordance overlay
     scrollbars are known for; it's only a few px wide so the odds of this
     getting in the way of an actual click/tap on page content are
     negligible. */
  #hhScrollThumb:hover, #hhScrollThumb.is-active{ width:9px; opacity:1 !important; }
  #hhScrollThumb.is-visible{ opacity:0.85; }
  #hhScrollThumb:active{ cursor:grabbing; }
  /* Mobile/tablet: thinner (reduced thickness, same fully-rounded pill
     shape - border-radius is untouched). Was pulled inward to 6px as a
     defensive measure against a suspected residual native scroll
     indicator, but that didn't actually change the reported gap - so
     whatever it is isn't fixed by repositioning this thumb - moved back
     out to 1px (matching desktop's own inset), then in by 3px again to
     4px per a later request, this time explicitly NOT tied to chasing
     the gap itself (the actual gap cause was found and fixed elsewhere -
     see fixFullBleedEdges' scrollbar-gutter-aware SAFETY_MARGIN_PX);
     nudged 2px further right (right:4px -> 2px) per a later request -
     mobile-only, desktop's own inset is untouched. */
  @media (max-width: 989px){
    #hhScrollThumb{ right:2px; width:4px; }
    #hhScrollThumb:hover, #hhScrollThumb.is-active{ width:5px; }
  }
  @media (prefers-reduced-motion: reduce){ #hhScrollThumb{ transition:opacity .15s ease; } }
  .hh-comfort-set{
    margin:0;
    background:var(--bg);
    color:var(--text);
    font-family:'Manrope', sans-serif;
    font-weight:400;
    line-height:1.55;
    -webkit-font-smoothing:antialiased;
    /* Full-bleed breakout: most Shopify themes wrap page content in their
       own max-width, padded container, which was clipping this
       component's "full width" section bands to that inner column and
       leaving the theme's own background showing as grey gaps down both
       sides. This classic trick ignores that ancestor and stretches the
       whole component to the true viewport width regardless of how deep
       it sits in the theme's markup; .hh-wrap (inside each section) is
       what still centres and caps the actual content at --maxw. */
    position:relative;
    /* Absorbs this element's OWN edge, on top of the existing html/body/
       .page-wrapper safety net above - added alongside fixFullBleedEdges'
       new mobile-only extra pixel of gap-closing margin (see the script),
       so that deliberate, slightly-generous overshoot can never itself
       read as a nested horizontal scroll/clip boundary here. "clip", not
       "hidden", for the same reason as the html/body rule: it never turns
       this element into a scroll container or disturbs anything sticky
       inside it, and never hides real content - the full-bleed section
       bands inside are already sized to this element's own (corrected)
       width, so nothing legitimate ever reaches past this edge for it to
       cut off. */
    overflow-x:clip;
    /* Full-bleed breakout. Percentages here resolve against this
       element's own containing block (the theme's padded content
       column); dvw resolves against the true, current visible viewport.
       So `50% - 50dvw` is exactly how far this element's edge already
       sits from the real viewport edge, applied as a margin on both
       sides - on an auto-width block that pulls it flush with the
       viewport with zero overshoot, at any zoom level, and keeps
       tracking correctly if mobile browser chrome (the URL bar) changes
       the viewport mid-visit.
       This alone is provably not exact wherever the page has a
       space-taking scrollbar (most desktop Windows/Linux browsers, and
       macOS set to always show scrollbars): dvw is defined against the
       OUTER window width, which INCLUDES that scrollbar, while a block's
       own natural containing-block width does not - so this edge lands
       slightly past the actual visible/scrollable area on any such
       desktop, wide enough on its own to force a second, horizontal
       scrollbar. How much of that lands on which edge depends on exactly
       how this element's ancestors centre it, which isn't safe to
       assume from CSS alone (checked directly against this store's live
       theme - see below) - so rather than guess a split here, the exact
       remaining correction, on whichever edge(s) actually need it, is
       measured and applied directly in JS after layout (fixFullBleedEdges,
       near the top of the <script> block below), re-measured on
       resize. overflow-x:clip above stands as a safety net regardless. */
    margin-inline: calc(50% - 50dvw);
    /* Removes the browser's own default tap-highlight (the flash of a
       plain bluish/grey rectangle Chrome/Safari draw over whatever was
       tapped) everywhere in this component, in favour of the deliberate
       :active press-scale below - set on every button/link individually
       too, just below, since WebKit's tap-highlight isn't guaranteed to
       respect an ancestor's value on every version. */
    -webkit-tap-highlight-color: transparent;
  }
  /* ---------- Press feedback (replaces the default mobile tap-highlight) ---------- */
  /* A quick, gentle scale-down on press - works for an actual touch tap AND
     a mouse click. Driven by JS toggling .is-pressed (see hhClearPress and
     the pointerdown/up/cancel listeners near the top of the script) rather
     than the native :active pseudo-class - :active is known to get
     visually "stuck" in its pressed-down look on mobile Safari after a
     long press, or when the element it's on gets hidden/disabled mid-touch
     (exactly what happens to the clear-cart bin, which can vanish the
     instant a tap clears the cart) - JS gives every path that can end a
     press (a normal release, a cancelled touch, a long-press context menu,
     the pointer dragging off the element, the tab losing focus, or the
     button being hidden/disabled by app logic) a reliable way to clear it.
     A handful of elements already carry their OWN transform for real
     positioning (centring a floating badge, etc.) - those get their own
     composed .is-pressed override right next to their base rule instead of
     this generic one, so a plain scale() here can never silently replace a
     transform something else actually needs to keep its position.
     .add-to-cart already had its own (subtler, since it's a large
     prominent button) scale on press from before this pass - untouched,
     and still wins here on specificity regardless. */
  .hh-comfort-set button,
  .hh-comfort-set a{
    -webkit-tap-highlight-color: transparent;
  }
  .hh-comfort-set button.is-pressed,
  .hh-comfort-set a.is-pressed{
    transform:scale(0.95);
  }
  .hh-comfort-set h1,.hh-comfort-set h2,.hh-comfort-set h3,.hh-comfort-set .display{
    font-family:'Libre Caslon Display', serif;
    font-weight:400;
    line-height:1.08;
    margin:0;
    letter-spacing:-0.01em;
  }
  .hh-comfort-set a{color:inherit; text-decoration:none;}
  .hh-comfort-set img{max-width:100%; display:block;}
  .hh-comfort-set .hh-wrap{max-width:var(--maxw); margin:0 auto; padding:0 32px;}
  @media (max-width: 640px){ .hh-comfort-set .hh-wrap{padding:0 20px;} }

  .hh-comfort-set :focus-visible{outline:2px solid var(--brass-bright); outline-offset:3px;}

  /* ---------- NAV ---------- */
  .hh-comfort-set header.site{
    position:sticky; top:0; z-index:50;
    background:rgba(20,22,27,0.92);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    /* Permanent gold/brass border - stays put whether the header is at
       full height or collapsed to its compact scrolled state below. */
    border-bottom:1px solid var(--brass);
    /* Slight, smooth curve on the bottom corners only - the top edge sits
       flush against the viewport, so only the trailing edge is rounded. */
    border-bottom-left-radius:16px;
    border-bottom-right-radius:16px;
    /* Drop shadow along the header's bottom edge is now permanent rather
       than something that only appears once .scrolled is toggled on - it's
       what gives the bar a distinct, "resting on top of the page" look
       right from the very first paint, at the top of the page, not just
       once you've scrolled past the hero. First pass at this shadow used
       rgba(0,0,0,0.45)/0.18-opacity brass on a near-black background
       (#14161B) - measured after the fact at only ~5-8 out of 255 per
       channel difference from the page behind it, i.e. technically
       rendering but essentially invisible on screen. Brass hairline
       opacity roughly doubled and the drop shadow's blur/opacity both
       pushed up (verified via rendered pixel-diff to land around ~14-16
       per channel now, a real, perceivable dark edge) while keeping the
       same tucked-under, no-vertical-drift shape so it still reads as a
       deliberate, tasteful lift rather than a heavy generic shadow. */
    box-shadow:
      0 1px 0 rgba(211,166,103,0.45),
      0 18px 32px -6px rgba(0,0,0,0.85);
  }
  .hh-comfort-set .hh-nav{
    position:relative;
    display:flex; align-items:center; justify-content:space-between;
    height:72px;
    transition:height 0.25s ease, padding 0.25s ease;
  }
  /* "Free delivery" note: sits pinned to the right edge of the header bar,
     independent of whatever nav-links/nav-cta are doing as they fade out,
     so its alignment stays clean no matter how narrow the screen gets.
     Hidden by default - only ever shown in the compact scrolled state, on
     both mobile and desktop.
     The visibility transition is deliberately split, with a different
     delay in each direction: scrolling down (fading IN) flips to
     `visibility:visible` immediately so the very first moment of the
     fade-in is actually visible; scrolling back up (fading OUT) keeps
     `visibility:visible` for the whole opacity fade and only flips to
     hidden right at the end, so the fade-out is genuinely seen instead of
     the element vanishing the instant the class changes (a zero-duration
     `visibility` transition otherwise applies its end value instantly in
     both directions).
     right:84px, not the original 14px: the emblem now sits at the header's
     true far right edge on desktop (see .hh-logo-mark - order:4, moved
     there this round), occupying the space this note used to sit in -
     confirmed via a direct measurement that the emblem's own left edge
     sits ~66px in from the row's right edge even at its smaller compact
     size, so 84px gives the note a clean ~18px gap clear of it instead of
     sitting directly underneath. This is the one knock-on desktop change
     the new far-right emblem required; nothing else about the note (or
     anything else on desktop) changed. */
  .hh-comfort-set .free-delivery-note{
    /* A <button> now (was a plain <span>) so it can open the cart drawer
       on tap/click - reset to look identical to the old label rather than
       a default button, and see .is-pressed further down for why its own
       press-scale is folded into this same transform instead of relying
       on the generic .hh-comfort-set button.is-pressed rule (that rule's
       plain scale() would otherwise just replace this positioning
       transform outright - same reasoning as .sticky-cart-bar__clear). */
    appearance:none; background:transparent; border:0; margin:0; padding:0;
    font:inherit; cursor:pointer;
    position:absolute;
    top:50%; right:84px;
    transform:translateY(-50%) translateX(6px);
    font-size:12px;
    font-weight:700;
    letter-spacing:0.04em;
    text-transform:uppercase;
    color:var(--brass-bright);
    white-space:nowrap;
    opacity:0;
    visibility:hidden;
    pointer-events:none;
    transition:opacity 0.35s cubic-bezier(0.32,0.72,0,1),
      transform 0.35s cubic-bezier(0.32,0.72,0,1),
      visibility 0s linear 0.35s;
  }
  .hh-comfort-set header.site.hh-compact .free-delivery-note{
    opacity:1;
    visibility:visible;
    pointer-events:auto;
    transform:translateY(-50%) translateX(0);
    transition:opacity 0.35s cubic-bezier(0.32,0.72,0,1),
      transform 0.35s cubic-bezier(0.32,0.72,0,1),
      visibility 0s linear 0s;
  }
  /* Only reachable while it's actually visible/interactive (the compact-
     header state above already gates pointer-events:auto to that state),
     so this only ever needs the ONE combined transform.
     No scale() added on top of it, unlike the page-wide .is-pressed rule
     (see -webkit-tap-highlight-color at the top of this file) - a real
     <button> sitting in the header's top-right corner, this is exactly
     where a finger lands to start a vertical scroll of the whole page,
     and pointerdown (which is what applies .is-pressed) fires before the
     browser can tell a scroll from a tap. A brief zoom-out/in right where
     the thumb is about to drag read as the page reacting to the touch,
     not as button feedback, so it's removed entirely here - same call
     already made for .faq-item__trigger.is-pressed further down. */
  .hh-comfort-set header.site.hh-compact .free-delivery-note.is-pressed{
    transform:translateY(-50%) translateX(0);
  }
  @media (max-width: 780px){
    .hh-comfort-set .free-delivery-note{ font-size:10.5px; right:12px; }
  }
  @media (prefers-reduced-motion: reduce){
    .hh-comfort-set .free-delivery-note{ transition:none; }
    .hh-comfort-set .hh-logo-mark svg{ transition:none; }
    .hh-comfort-set .free-delivery-note-mobile{ transition:none; }
  }
  /* Wordmark + emblem lockup. The emblem (.hh-logo-mark) is one shared
     element repositioned per breakpoint via flex `order` rather than two
     separate markup copies - see the max-width:780px block below for its
     mobile position. Desktop: reordered to sit LAST (order:4, past
     .nav-cta's default 0), i.e. the far right of the entire bar, inside
     .hh-wrap's existing page-wide side padding so it's already
     "proportionally indented" the same amount as every other section's
     content edge rather than needing a one-off margin. Mobile: sits at
     the opposite end from the wordmark, taking over the slot the "Shop
     now" button used to occupy there (see .nav-cta{display:none} below -
     "Shop now" is mobile-only removed, desktop keeps it untouched). */
  .hh-comfort-set .hh-logo-mark{
    display:flex; align-items:center; flex:none;
    order:4;
    margin-left:28px;
    color:var(--brass);
  }
  .hh-comfort-set .hh-logo-mark svg{
    display:block; width:46px; height:46px;
    transition:width 0.25s ease, height 0.25s ease;
  }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .hh-logo-mark:hover{ color:var(--brass-bright); }
  }
  .hh-comfort-set header.site.hh-compact .hh-logo-mark svg{ width:34px; height:34px; }
  .hh-comfort-set .brand-mark{
    /* Sized up, more openly tracked, with a brass accent on the ampersand
       and trademark mark - brings the header wordmark closer in feel to
       the standalone logo lockup (hearth-hue-logo-lockup.png), which uses
       the same open tracking + brass sup accent at a larger display size. */
    font-family:'Libre Caslon Display', serif; font-size:27px; letter-spacing:0.02em;
    transition:font-size 0.25s ease;
  }
  .hh-comfort-set .brand-mark .brand-amp{ color:var(--brass-bright); }
  .hh-comfort-set .brand-mark sup{font-size:12px; color:var(--brass-bright);}
  /* Mobile-only free-delivery line, shown/hidden with .hh-compact exactly
     like the desktop .free-delivery-note above (same opacity/visibility
     fade technique) - but centred in the header bar via position:absolute
     rather than pinned to the wordmark or an edge, since with the wordmark
     on the left and the (now much larger, far-right) emblem on the right,
     leaving the middle of the bar empty read as a big dead gap once
     scrolled. Sits completely out of the mobile flex row's flow, so it
     never competes for space with the wordmark or emblem either side of
     it. display:none at this width by default (all its real styling lives
     in the max-width:780px block below) - desktop never renders it at
     all. */
  .hh-comfort-set .free-delivery-note-mobile{ display:none; }
  /* Smart compact mode: once the visitor scrolls down past the hero, the
     nav links + CTA collapse away and the bar itself shrinks so it stays
     out of the way while scrolling - but it never disappears, and the
     brand name is always what's left, so people always know what site
     they're on. Scrolling back up (or returning near the top) restores
     the full header. Toggled via JS (header.site.hh-compact below).
     .nav-links and .nav-cta each carry their OWN full `transition`
     shorthand, repeated in full again on their own compact-state rule
     below (rather than one declaration shared between the base and
     compact states, or between the two elements) - two rules of equal or
     higher specificity that each set the `transition` shorthand on the
     same element don't merge property-by-property, the later one simply
     replaces the earlier one's whole list. That previously left
     .nav-cta's width/padding/border-color collapse (see the PC-only block
     below) with no active transition at all, so it snapped instantly
     instead of animating. Each pair also mirrors the .free-delivery-note
     delayed-visibility technique above, so the fade is actually visible
     in both directions rather than the element just vanishing. */
  .hh-comfort-set .nav-links{
    display:flex; gap:36px; font-size:14px; color:var(--text-dim);
    overflow:hidden; white-space:nowrap;
    opacity:1; transform:translateY(0); visibility:visible;
    transition:opacity 0.35s cubic-bezier(0.32,0.72,0,1),
      transform 0.35s cubic-bezier(0.32,0.72,0,1),
      max-height 0.35s cubic-bezier(0.32,0.72,0,1),
      margin 0.35s cubic-bezier(0.32,0.72,0,1),
      width 0.35s cubic-bezier(0.32,0.72,0,1),
      gap 0.35s cubic-bezier(0.32,0.72,0,1),
      visibility 0s linear 0s;
  }
  /* Gated to real hover devices - see the addon-card/feature-cell comments
     further down for why: a tap on a touchscreen can trigger (and, worse,
     get visually stuck showing) a :hover style, since touch has no
     continuous pointer to naturally move it off again. */
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .nav-links a:hover{color:var(--text);}
  }
  .hh-comfort-set .nav-cta{
    font-size:13px; padding:10px 20px; border:1px solid var(--brass);
    color:var(--brass-bright); border-radius:var(--radius-pill);
    overflow:hidden; white-space:nowrap;
    opacity:1; transform:translateY(0); visibility:visible;
    transition:opacity 0.35s cubic-bezier(0.32,0.72,0,1),
      transform 0.35s cubic-bezier(0.32,0.72,0,1),
      max-height 0.35s cubic-bezier(0.32,0.72,0,1),
      margin 0.35s cubic-bezier(0.32,0.72,0,1),
      padding 0.35s cubic-bezier(0.32,0.72,0,1),
      width 0.35s cubic-bezier(0.32,0.72,0,1),
      border-color 0.35s cubic-bezier(0.32,0.72,0,1),
      visibility 0s linear 0s;
  }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .nav-cta:hover{background:var(--brass); color:#15171C;}
  }
  .hh-comfort-set header.site.hh-compact .hh-nav{ height:52px; }
  .hh-comfort-set header.site.hh-compact .brand-mark{ font-size:18px; }
  .hh-comfort-set header.site.hh-compact .nav-links{
    opacity:0; transform:translateY(-6px);
    pointer-events:none; visibility:hidden;
    transition:opacity 0.35s cubic-bezier(0.32,0.72,0,1),
      transform 0.35s cubic-bezier(0.32,0.72,0,1),
      max-height 0.35s cubic-bezier(0.32,0.72,0,1),
      margin 0.35s cubic-bezier(0.32,0.72,0,1),
      width 0.35s cubic-bezier(0.32,0.72,0,1),
      gap 0.35s cubic-bezier(0.32,0.72,0,1),
      visibility 0s linear 0.35s;
  }
  .hh-comfort-set header.site.hh-compact .nav-cta{
    opacity:0; transform:translateY(-6px);
    pointer-events:none; visibility:hidden;
    transition:opacity 0.35s cubic-bezier(0.32,0.72,0,1),
      transform 0.35s cubic-bezier(0.32,0.72,0,1),
      max-height 0.35s cubic-bezier(0.32,0.72,0,1),
      margin 0.35s cubic-bezier(0.32,0.72,0,1),
      padding 0.35s cubic-bezier(0.32,0.72,0,1),
      width 0.35s cubic-bezier(0.32,0.72,0,1),
      border-color 0.35s cubic-bezier(0.32,0.72,0,1),
      visibility 0s linear 0.35s;
  }
  /* PC only: once compact, "Shop now" AND the nav links both fully collapse
     (width/padding/margin/gap to zero, not just faded to invisible) so they
     vacate their slot in the header row entirely, exactly like the nav
     links row does on mobile via its own max-height collapse below - the
     "4 Days Free Delivery" note is left as their clean, unambiguous
     replacement instead of invisible elements still reserving space next
     to it. Before this, .nav-links only had opacity/visibility toggled here,
     so - unlike .nav-cta - it kept its full ~336px flex-item width reserved
     in the header row even while invisible, leaving a dead gap between the
     brand mark and the free-delivery note that mobile's true collapse never
     had. Genuinely animates (see the transition fix above) instead of
     snapping to zero width instantly. */
  @media (min-width: 781px){
    .hh-comfort-set header.site.hh-compact .nav-cta{
      width:0; padding-left:0; padding-right:0; margin-left:0; margin-right:0;
      border-color:transparent;
    }
    .hh-comfort-set header.site.hh-compact .nav-links{
      width:0; margin-left:0; margin-right:0; gap:0;
    }
  }
  @media (max-width: 780px){
    .hh-comfort-set .hh-nav{ height:auto; flex-wrap:wrap; padding:14px 6px; gap:12px; }
    .hh-comfort-set .nav-links{ gap:16px; font-size:12.5px; flex-wrap:wrap; order:3; width:100%; max-height:200px; }
    /* gap:0 here matters as much as the padding: .nav-links collapses to
       0 height when compact but stays a second flex line (flex-wrap), and
       flex row-gap still inserts space *before* a zero-height line just
       as it would a real one - left at the base rule's 12px, that phantom
       gap landed entirely below the visible logo/wordmark row (10px top
       padding vs 10px+12px under it), which is exactly why the brand
       title/logo read as sitting too high once collapsed. Zeroing it
       restores a symmetric 10px above/below. */
    .hh-comfort-set header.site.hh-compact .hh-nav{ height:auto; padding:10px 6px; gap:0; }
    .hh-comfort-set header.site.hh-compact .nav-links{ max-height:0; opacity:0; margin:0; overflow:hidden; }
    /* "Shop now" is removed entirely on mobile (replaced by the emblem -
       see .hh-logo-mark above) rather than just hidden once compact the
       way it used to be - desktop's .nav-cta is completely untouched by
       this rule (it lives outside this max-width block) and keeps working
       exactly as it always has. */
    .hh-comfort-set .nav-cta{ display:none; }
    /* The emblem swaps sides here: desktop has it at order:4 (far right of
       the whole bar); on mobile it moves to order:2, which - with
       .nav-links pinned to order:3/width:100% (so it always wraps onto
       its own full row below) and "Shop now" removed above - lands it as
       the sole item sharing the top row with .brand-mark, in the same
       right-hand slot "Shop now" used to sit in. Twice the old mobile
       size (28px -> 56px) and no longer shrinks in the compact state -
       the header's mobile height barely changes on scroll (it's already
       height:auto/flex-wrap here, unlike desktop's fixed 72px->52px
       collapse), so there's no real space pressure forcing it smaller the
       way there is on desktop. */
    .hh-comfort-set .hh-logo-mark{ order:2; margin-left:14px; }
    .hh-comfort-set .hh-logo-mark svg{ width:56px; height:56px; }
    .hh-comfort-set header.site.hh-compact .hh-logo-mark svg{ width:56px; height:56px; }
    /* The original right-edge note (.free-delivery-note) is retired on
       mobile - that edge is the emblem's job now. Desktop is untouched:
       .free-delivery-note keeps working exactly as before, this rule only
       ever applies at/under 780px. */
    .hh-comfort-set .free-delivery-note{ display:none; }
    /* Centred version of the free-delivery note - see the comment above
       .free-delivery-note-mobile further up for why it's centred rather
       than tucked under the wordmark. Same show-on-scroll opacity/
       visibility fade the desktop note uses (mirrored here, not
       reinvented), just positioned via left/top:50% + a translate instead
       of pinned to the right edge. */
    .hh-comfort-set .free-delivery-note-mobile{
      /* Same <span>-to-<button> reset as .free-delivery-note above. */
      appearance:none; background:transparent; border:0; margin:0; padding:0;
      font:inherit; cursor:pointer;
      display:block;
      position:absolute;
      left:50%; top:50%;
      transform:translate(-50%, -50%);
      font-size:10px;
      font-weight:700;
      letter-spacing:0.04em;
      text-transform:uppercase;
      color:var(--brass-bright);
      white-space:nowrap;
      opacity:0;
      visibility:hidden;
      pointer-events:none;
      transition:opacity 0.3s cubic-bezier(0.32,0.72,0,1),
        visibility 0s linear 0.3s;
    }
    .hh-comfort-set header.site.hh-compact .free-delivery-note-mobile{
      opacity:1;
      visibility:visible;
      pointer-events:auto;
      transition:opacity 0.3s cubic-bezier(0.32,0.72,0,1),
        visibility 0s linear 0s;
    }
    /* Same removal as the desktop .free-delivery-note.is-pressed above,
       and for the same reason - this one sits centred in the mobile
       header's top bar, another spot a finger commonly lands on to start
       scrolling the page, so no scale() is layered on its own transform. */
    .hh-comfort-set header.site.hh-compact .free-delivery-note-mobile.is-pressed{
      transform:translate(-50%, -50%);
    }
  }
  @media (max-width: 380px){
    .hh-comfort-set .nav-links{ gap:10px; font-size:11.5px; }
  }
  /* "About Us" in the header: desktop / wide-tablet only. On phones the nav
     row is already full, and just above the 780px mobile breakpoint the bar
     is too tight for a fourth link next to "Shop now", so it hides up to
     960px wide. It's always in the footer too. */
  @media (max-width: 960px){
    .hh-comfort-set .nav-links .nav-about{ display:none; }
  }
  @media (prefers-reduced-motion: reduce){
    .hh-comfort-set .nav-links, .hh-comfort-set .nav-cta{ transition:none; }
  }
  /* Used only for an instant, non-animated internal height measurement
     (hhMeasureHeaderFullHeight() in the script below) - never toggled as
     part of the real scroll-driven compact/expand behaviour above. The
     animating property on a full swing back to the top is .nav-links'
     own max-height/opacity/etc (not a height on the header itself - see
     the comment above .nav-links), so this has to blanket every
     descendant, not just header.site. Forces any transition inside the
     header off so a class change made purely to measure its full height
     resolves to its final layout instantly, even if a *real* compact/
     expand transition happens to be mid-flight at that exact moment -
     exactly what a fast fling back to the top triggers, since the
     ResizeObserver-driven recalculation below can land while the header
     is still genuinely animating. Without this, measuring mid-transition
     just read whatever partial, interpolated height that instant
     happened to show - caching it, then correcting to the true full
     height a moment later once a later recalculation ran after the
     transition actually finished. That late correction is what looked
     like the sticky bar "pushing the thumb back" once it regained its
     full height. */
  .hh-comfort-set header.site.hh-measuring,
  .hh-comfort-set header.site.hh-measuring *{
    transition:none !important;
  }

  /* ---------- HERO ---------- */
  /* Each major section below now gets its own full-bleed background band
     (alternating --bg / --panel) so sections read as visually distinct
     instead of one continuous slab of colour running top to bottom. The
     centred, max-width content still lives one level in, on .hh-wrap -
     splitting "section" (full-width band) from "content" (centred column)
     the same way the header/footer already did. */
  .hh-comfort-set .hero{
    position:relative;
    padding:88px 0 96px;
    overflow:hidden;
    background:var(--bg);
  }
  .hh-comfort-set .hero .hh-wrap{
    display:grid;
    grid-template-columns: 1.05fr 0.95fr;
    align-items:center;
    gap:48px;
  }
  .hh-comfort-set .hero::before{
    content:"";
    position:absolute; inset:0;
    background:
      radial-gradient(ellipse 700px 500px at 78% 30%, rgba(184,135,74,0.14), transparent 60%);
    pointer-events:none;
  }
  .hh-comfort-set .kicker{
    color:var(--brass-bright);
    font-size:14px;
    font-weight:600;
    margin-bottom:18px;
  }
  .hh-comfort-set .hero h1{
    font-size:clamp(38px, 4.6vw, 60px);
    max-width:12.5ch;
  }
  .hh-comfort-set .hero h1 em{ font-style:italic; color:var(--brass-bright); }
  .hh-comfort-set .hero p.lede{
    margin-top:22px;
    font-size:18px;
    color:var(--text-dim);
    max-width:46ch;
  }
  .hh-comfort-set .hero-stats{
    display:flex; gap:40px; flex-wrap:wrap;
    margin-top:36px;
    padding-top:28px;
    border-top:1px solid var(--hairline);
  }
  .hh-comfort-set .hero-stats div strong{
    display:block; font-family:'Libre Caslon Display', serif;
    font-size:26px; color:var(--text);
  }
  .hh-comfort-set .hero-stats div span{ font-size:13px; color:var(--text-faint); }
  /* Phones: the three hero stats sit on ONE row (they used to wrap onto
     several lines at desktop size). Equal-width columns, smaller figures and
     captions, and a hairline between columns so the row still reads as a
     tidy strip. Captions may wrap to two lines inside their column; the
     figures themselves never wrap. */
  @media (max-width: 560px){
    .hh-comfort-set .hero-stats{
      flex-wrap:nowrap; gap:0; justify-content:space-between;
      margin-top:26px; padding-top:18px;
    }
    .hh-comfort-set .hero-stats > div{ flex:1 1 0; min-width:0; padding:0 10px; }
    .hh-comfort-set .hero-stats > div:first-child{ padding-left:0; }
    .hh-comfort-set .hero-stats > div:last-child{ padding-right:0; }
    .hh-comfort-set .hero-stats > div + div{ border-left:1px solid var(--hairline); }
    .hh-comfort-set .hero-stats div strong{ font-size:19px; white-space:nowrap; line-height:1.15; }
    .hh-comfort-set .hero-stats div > strong + span{ display:block; margin-top:3px; font-size:11px; line-height:1.35; }
    /* Phones only: the hero price drops its ".00" (shows "R590"). Hidden with
       CSS rather than removed from the markup, so the live price sync keeps
       working and desktop still shows the full "R590.00". */
    .hh-comfort-set .hero-stats .decimal-sep,
    .hh-comfort-set .hero-stats sup{ display:none; }
  }
  @media (max-width: 360px){
    .hh-comfort-set .hero-stats > div{ padding:0 7px; }
    .hh-comfort-set .hero-stats div strong{ font-size:17px; }
    .hh-comfort-set .hero-stats div > strong + span{ font-size:10.5px; }
  }
  .hh-comfort-set .hero-media{ position:relative; }
  .hh-comfort-set .hero-media img{
    width:100%; border-radius:4px;
    border:1px solid var(--hairline);
  }
  /* Was a solid, bordered pill floating with a fixed 18px margin from the
     image's own edges - reworked into a caption bar flush against the
     image's bottom edge instead, its background fading out (via a
     vertical gradient, not a hard box edge) as it moves up away from the
     text and toward the open middle of the photo. Stretches the full
     image width (left/right:0) rather than staying a compact pill, so
     the fade has room to actually read as a graduated dissolve rather
     than a visible cutoff line. border-radius matches the image's own
     (var(--radius-card) is 2px elsewhere on the page, but this specific
     image uses a slightly larger 4px - matched here so the gradient's
     bottom corners don't overhang the image's own rounded corners).
     pointer-events:none since it now overlays a meaningful portion of
     the image itself, not just a small corner badge - nothing beneath it
     is interactive on this hero image, but this keeps it that way. */
  .hh-comfort-set .hero-media .tag{
    position:absolute; left:0; right:0; bottom:0;
    background:linear-gradient(to top,
      rgba(15,17,21,0.85) 0%,
      rgba(15,17,21,0.55) 45%,
      rgba(15,17,21,0) 100%);
    padding:36px 20px 14px;
    font-size:13px; color:var(--text-dim);
    border:none; border-radius:0 0 4px 4px;
    pointer-events:none;
  }
  @media (max-width: 900px){
    .hh-comfort-set .hero{padding-top:56px;}
    .hh-comfort-set .hero .hh-wrap{grid-template-columns:1fr;}
  }

  /* ---------- BUY BOX ---------- */
  /* scroll-margin-top keeps the sticky header (up to 72px tall) from
     covering the top of this section when the sticky-bar's price text is
     tapped to jump here (see .sticky-cart-bar__scroll-target in the
     script) - sized for the header's taller, un-scrolled state, so it
     errs on the side of a touch of extra clearance rather than ever
     landing underneath it. */
  .hh-comfort-set section.buy{ padding:64px 0 88px; background:var(--panel); scroll-margin-top:88px; }
  .hh-comfort-set .buybox{
    display:grid;
    grid-template-columns: 1.1fr 0.9fr;
    gap:0;
    border:1px solid var(--hairline);
    /* One shade lighter than the section's own --panel band behind it,
       so the card still reads as a distinct card rather than blending
       into its section. */
    background:var(--panel-raised);
    border-radius:4px;
    overflow:hidden;
  }
  /* Defensive hardening, not the fix for the reported stutter (that's in
     the script - see selectGalleryMedia's decode-before-reveal comment).
     A CSS grid item's default automatic min-width is "auto", which in
     some engines/conditions can be resolved from an unconstrained child's
     intrinsic content size - in principle letting a very oddly-
     proportioned image/video drag this column (and the thumbnails/text
     riding along in it) wider than the fr values above intend. The fixed
     aspect-ratio + overflow:hidden on .gallery-main already prevents this
     in every browser tested here, but pinning min-width to 0 removes the
     dependency on that entirely and costs nothing, so it stays in as a
     safety net against engines/conditions not covered by that testing.
  */
  .hh-comfort-set .gallery{ padding:36px; border-right:1px solid var(--hairline); min-width:0; }
  .hh-comfort-set .gallery-main{
    position:relative;
    border:1px solid var(--hairline); border-radius:3px; overflow:hidden;
    aspect-ratio: 4/3.1; background:#0F1115;
    width:100%; min-width:0;
  }
  /* ---------- Crossfade media layers ----------
     Shared by the main gallery and both accessory cards. Every image/
     video the viewer has ever shown stays exactly where it was stacked
     (position:absolute, inset:0, all the same size) rather than being
     replaced via innerHTML - swapping to a new slide APPENDS one more
     layer on top, already fully opaque underneath layers included, so
     there is never a moment where the box falls back to its own dark
     background showing through (the old fade-to-black-then-back approach
     could briefly do exactly that). The new layer starts invisible
     (.is-entering) and is flipped to opaque by the script a frame later,
     so the transition below is what actually animates the crossfade;
     once it's finished every other layer underneath is removed - see
     selectGalleryMedia. Video is handled by first crossfading its poster
     in as a plain image exactly like a photo, then swapping that settled
     layer for a real <video> with the same poster once fully visible -
     imperceptible, since the video initially looks identical to the
     image that was already sitting there.
     0.9s must match HH_MEDIA_TRANSITION_MS in the script. */
  .hh-comfort-set .gallery-main .media-layer, .hh-comfort-set .addon-media .media-layer{
    position:absolute; inset:0; width:100%; height:100%; object-fit:cover; display:block;
    transition:opacity 0.9s cubic-bezier(0.4,0,0.2,1);
  }
  .hh-comfort-set .gallery-main .media-layer.is-entering, .hh-comfort-set .addon-media .media-layer.is-entering{
    opacity:0;
  }
  .hh-comfort-set .gallery-thumbs{ display:flex; flex-wrap:wrap; gap:10px; margin-top:12px; } /* wraps onto extra rows when a product has up to 12 photos + 2 videos */
  .hh-comfort-set .gallery-thumbs button{
    position:relative;
    padding:0; border:1px solid var(--hairline); background:#0F1115;
    width:72px; height:56px; border-radius:2px; cursor:pointer; overflow:hidden;
    /* border-color matches HH_MEDIA_TRANSITION_MS below so the "in focus"
       border eases in at the same slow, deliberate pace as the image
       crossfade itself, rather than snapping to the new thumbnail ahead
       of the picture. transform added so the shared page-wide .is-pressed
       press-scale (see near -webkit-tap-highlight-color at the top of
       this file) eases smoothly here too, same 0.7s bespoke curve as the
       other touch-feedback elements above - it had no transition of its
       own before, so a tap/click on a thumbnail snapped straight to
       scale(0.95) and back with no easing at all. */
    transition:border-color 0.9s cubic-bezier(0.4,0,0.2,1),
      transform 0.7s cubic-bezier(0.32,0.72,0,1);
  }
  .hh-comfort-set .gallery-thumbs button.active{ border-color:var(--brass); }
  .hh-comfort-set .gallery-thumbs img{ width:100%; height:100%; object-fit:cover; transition:transform 0.25s ease; }
  /* Small centred play triangle overlaid on any thumbnail whose media is a
     video, in both the main gallery and the two accessory cards' compact
     strips below - shared by both via one class rather than duplicated
     per context. Purely a visual cue; the actual swap-to-video behaviour
     is driven by the button's data-type attribute, not this element. */
  .hh-comfort-set .media-thumb-play{
    position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
    background:rgba(15,17,21,0.45); color:#fff; pointer-events:none;
  }
  .hh-comfort-set .media-thumb-play svg{ width:13px; height:13px; display:block; }
  /* Small autoplay-slideshow toggle, bottom-right corner of its own image
     (main gallery + both accessory cards - see the shared script). Both
     icons are always in the DOM; .is-paused just swaps which one is
     visible, rather than the JS rewriting the SVG each toggle. */
  .hh-comfort-set .gallery-slideshow-btn{
    position:absolute; bottom:10px; right:10px; z-index:2;
    display:flex; align-items:center; justify-content:center;
    width:32px; height:32px; padding:0; border-radius:50%;
    background:rgba(15,17,21,0.55); border:1px solid rgba(255,255,255,0.25);
    color:#fff; cursor:pointer;
    transition:background 0.15s ease, border-color 0.15s ease;
  }
  .hh-comfort-set .gallery-slideshow-btn svg{ width:13px; height:13px; display:block; }
  .hh-comfort-set .gallery-slideshow-btn .icon-play{ display:none; }
  .hh-comfort-set .gallery-slideshow-btn.is-paused .icon-pause{ display:none; }
  .hh-comfort-set .gallery-slideshow-btn.is-paused .icon-play{ display:block; }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .gallery-slideshow-btn:hover{ background:var(--brass); border-color:var(--brass); color:#15171C; }
  }
  /* Smaller on narrow/mobile widths, where the accessory cards especially
     are a lot more compact - a 32px badge reads oversized next to a
     44x34px thumbnail. */
  @media (max-width: 780px){
    .hh-comfort-set .gallery-slideshow-btn{ width:26px; height:26px; bottom:8px; right:8px; }
    .hh-comfort-set .gallery-slideshow-btn svg{ width:11px; height:11px; }
  }
  /* Gentle zoom-forward on hover for the small thumbnails only - the main
     (large) image is untouched. overflow:hidden on the button above keeps
     the zoomed image cropped to the thumbnail's frame. */
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .gallery-thumbs button:hover img{ transform:scale(1.08); }
  }

  .hh-comfort-set .buy-info{ padding:40px; min-width:0; }
  .hh-comfort-set .buy-info h2{ font-size:30px; max-width:16ch; }
  .hh-comfort-set .product-subnote{ margin-top:8px; font-size:13px; color:var(--text-dim); }
  /* Compact rating badge sat right in the buy box, between the title/
     subnote and the price - so the aggregate score is visible the moment
     a shopper is deciding whether to buy, not only once they've scrolled
     all the way down past FEATURES to REVIEWS SUMMARY. Reuses the exact
     same hh_review_summary_score/count variables (now assigned once near
     the very top of the file, precisely so this earlier-rendering badge
     can read them too) as the other two instances further down the page,
     so all three numbers stay in sync automatically - see the REVIEW
     SCORE comment in the mainblock up top. The whole
     strip is one link straight down to the review cards, same explicit
     scrollIntoView handling as the "reviews" word in the summary strip
     below (see reviewsJumpLinks in the script file). */
  .hh-comfort-set .buybox-rating{
    display:inline-flex; align-items:center; gap:6px;
    margin-top:10px;
    text-decoration:none; cursor:pointer;
  }
  /* Opts this link out of the page-wide .is-pressed press-scale (see
     transform:scale(0.95) near -webkit-tap-highlight-color at the top of
     this file) - same reasoning as .free-delivery-note.is-pressed and
     .faq-item__trigger.is-pressed elsewhere in this file: this badge
     sits right at the top of the buy box, a natural spot to start
     scrolling the page from, and pointerdown (which applies .is-pressed)
     fires before the browser knows a touch will become a scroll rather
     than a tap - so the scale-down could flash on every scroll started
     here, not just on an actual tap through to the reviews. */
  .hh-comfort-set .buybox-rating.is-pressed{ transform:none; }
  .hh-comfort-set .reviews-stars.reviews-stars--xs .star-wrap{ width:13px; height:13px; }
  .hh-comfort-set .reviews-stars.reviews-stars--xs svg{ width:13px; height:13px; }
  .hh-comfort-set .buybox-rating__score{
    font-size:13px; font-weight:700; color:var(--text);
  }
  .hh-comfort-set .buybox-rating__count{
    font-size:13px; color:var(--text-dim);
    /* 0.7s bespoke ease (matches .foot-links a/.faq-item__question/
       .view-cart-btn) instead of the previous quick 0.15s snap, so a
       scroll started right on the rating badge barely tints the "12
       reviews" text before it eases back, rather than flashing it. */
    transition:color 0.7s cubic-bezier(0.32,0.72,0,1);
  }
  /* The parentheses are part of .buybox-rating__count's own text (so they
     inherit its colour/hover transition without extra markup), but the
     underline is scoped to this inner span instead - wrapping only "12
     reviews" - so the brackets themselves stay un-underlined. */
  .hh-comfort-set .buybox-rating__count-text{
    text-decoration:underline; text-underline-offset:2px;
  }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .buybox-rating:hover .buybox-rating__count{ color:var(--brass-bright); }
  }
  /* Mirrors the desktop :hover colour above as touch feedback instead of
     the (already removed, see .buybox-rating.is-pressed further up) press
     -scale - touch devices have no real :hover, so without this a tap on
     the underlined "12 reviews" text had no colour feedback of its own. */
  @media (hover: none){
    .hh-comfort-set .buybox-rating.is-pressed .buybox-rating__count{ color:var(--brass-bright); }
  }
  .hh-comfort-set .price-row{ display:flex; align-items:baseline; gap:12px; margin-top:16px; }
  .hh-comfort-set .price{ font-family:'Libre Caslon Display', serif; font-size:34px; color:var(--brass-bright); }
  /* Cents ride as a smaller, raised, grey-toned superscript everywhere
     EXCEPT inside the cart drawer, which intentionally uses plain,
     standard decimals instead (see formatPricePlain/moneyPlain in the
     script) - so the cart-drawer classes are deliberately left out of
     this selector list. */
  .hh-comfort-set .price sup, .hh-comfort-set .addon-price sup, .hh-comfort-set .hero-stats sup,
  .hh-comfort-set .sticky-cart-bar__total sup, .hh-comfort-set .sticky-cart-bar__other sup,
  .hh-comfort-set .price .decimal-sep, .hh-comfort-set .addon-price .decimal-sep, .hh-comfort-set .hero-stats .decimal-sep,
  .hh-comfort-set .sticky-cart-bar__total .decimal-sep, .hh-comfort-set .sticky-cart-bar__other .decimal-sep{
    font-size:0.55em; font-weight:600; vertical-align:text-top;
    color:var(--text-faint);
  }
  .hh-comfort-set .price-note{ font-size:13px; color:var(--text-faint); }

  /* Simplified, always-visible callout for the real "Full Cabin Comfort
     7% Off" automatic discount (see COMFORT_SET_DISCOUNT_PCT in the
     script) - deliberately a soft green rather than the page's usual
     brass/gold, so it reads at a glance as a distinct "you can save
     here" signal rather than blending into the gold price/CTA styling
     used everywhere else.

     Every discount-related green on this page comes from the same
     --deal-green/--deal-green-bright pair (Sizo's call: one consistent
     green family throughout, not several close-but-different shades) -
     but which of the two applies depends on what the colour sits on top
     of, same as this page already does for --brass/--brass-bright:
       - On a solid green FILL (.addon-add.added, #comfortDealAddBtn's
         hover/added/pressed states, this pill's own background) the
         text/icon on top stays the very light #CDE0CD - that's
         .addon-add.added's own exact text colour, and reads cleanly
         against the darker fill behind it.
       - Standing alone directly on the dark page/panel with no fill
         behind it (this button's idle state, the bundle savings line
         below), #CDE0CD is too pale/desaturated to read as "green" at a
         glance - it lands closer to off-white. --deal-green-bright is
         the same hue at higher saturation, so it's still clearly the
         same discount-green family without needing a fill to carry it,
         and without tipping into neon.
     The one deliberate exception is the EFT payment badge below in the
     footer - that's a payment-network mark on its own light chip, same
     as the untouched VISA/Mastercard colours beside it, not a discount
     signal, so it keeps its own brand green rather than joining this
     pair.

     Shows the discounted PER-SET price rather than a lump total - a
     shopper glancing at this next to the regular price sees exactly what
     each set would cost them, which is a more concrete, immediately
     actionable hook than an aggregate saving figure. */
  .hh-comfort-set .bulk-discount-note{
    display:inline-flex; align-items:center; gap:7px;
    margin:12px 0 0; padding:8px 14px;
    background:rgba(62,90,63,0.18);
    border:1px solid rgba(62,90,63,0.5);
    border-radius:var(--radius-pill);
    font-size:12.5px; font-weight:700; color:#CDE0CD;
  }
  .hh-comfort-set .bulk-discount-note svg{ width:14px; height:14px; flex-shrink:0; }

  .hh-comfort-set .variant-block{ margin-top:30px; }
  .hh-comfort-set .variant-label{ font-size:13px; color:var(--text-dim); margin-bottom:12px; }
  .hh-comfort-set .swatches{ display:flex; gap:10px; flex-wrap:wrap; }
  .hh-comfort-set .swatch{
    display:inline-flex; align-items:center; gap:9px;
    /* Was 1px solid var(--hairline) - that outer ring read as a grey border
       around the gold/black swatch itself; kept the 1px width so padding
       and alignment stay pixel-identical, just made invisible. */
    border:1px solid transparent;
    padding:8px 16px 8px 8px;
    border-radius:var(--radius-pill);
    font-size:13px; color:var(--text); background:transparent;
  }
  .hh-comfort-set .swatch .dot{ width:16px; height:16px; min-width:16px; border-radius:50%; background:#101114; box-shadow:0 0 0 2px var(--brass) inset; flex-shrink:0; }
  .hh-comfort-set .swatch-name{ white-space:nowrap; }
  .hh-comfort-set .swatch-note{ margin-top:8px; font-size:12.5px; color:var(--text-faint); }

  .hh-comfort-set .qty-row{ display:flex; align-items:center; gap:16px; flex-wrap:wrap; margin-top:28px; }
  .hh-comfort-set .stepper{ display:flex; align-items:center; border:1px solid var(--hairline); border-radius:var(--radius-pill); }
  .hh-comfort-set .stepper button{ background:none; border:none; color:var(--text); width:38px; height:38px; font-size:16px; cursor:pointer; }
  .hh-comfort-set .stepper button:disabled{ opacity:0.35; cursor:default; }
  .hh-comfort-set .stepper span{ min-width:24px; text-align:center; font-size:15px; }

  .hh-comfort-set .add-to-cart{
    margin-top:26px; width:100%;
    background:var(--brass); color:#151318;
    border:none; padding:17px 20px;
    font-size:15px; font-weight:700; letter-spacing:0.01em;
    border-radius:var(--radius-pill);
    cursor:pointer;
    transition:background 0.15s ease, transform 0.05s ease;
  }
  /* Gated to real hover devices - a long press (or a tap that slides off)
     on a touchscreen can trigger and then get visually "stuck" showing a
     :hover style, since touch never fires a continuous hover-out the way
     a mouse leaving the button does. Reported specifically on the Add to
     Cart buttons staying highlighted after release; the underlying
     .is-pressed press-scale effect (see near -webkit-tap-highlight-color
     above) was already fixed separately and isn't this - this is :hover
     itself sticking, a different mechanism, same "touch has no real
     hover" root cause. */
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .add-to-cart:hover{ background:var(--brass-bright); }
  }
  .hh-comfort-set .add-to-cart.is-pressed{ transform:scale(0.99); }
  .hh-comfort-set .add-to-cart:disabled{ opacity:0.65; cursor:default; }
  /* "Coming soon" state (product not available in Shopify): a calm, muted
     disabled button in place of Add to Cart, the +/- stepper tucked away (its
     markup stays in the page because the script still looks it up), and the
     "adds N sets" helper line swapped for the launching-soon note. */
  .hh-comfort-set .add-to-cart.is-soldout,
  .hh-comfort-set .addon-add.is-soldout{
    background:transparent; border:1px solid var(--hairline);
    color:var(--text-dim); opacity:1; cursor:not-allowed;
  }
  .hh-comfort-set .qty-row.is-soldout .stepper{ display:none; }
  .hh-comfort-set .qty-row.is-soldout .add-to-cart{ flex:1; }
  .hh-comfort-set .qty-row.is-soldout + .add-to-cart-note{ display:none; }
  /* "Launching soon" notice at the top of the hero - only rendered while the
     Comfort Set is unavailable in Shopify; disappears by itself once stock
     is added. */
  .hh-comfort-set .launch-soon{
    display:inline-flex; align-items:center; flex-wrap:wrap; gap:6px 10px;
    padding:8px 16px; margin-bottom:22px;
    border:1px solid var(--brass); border-radius:var(--radius-pill);
    background:rgba(184,135,74,0.08); font-size:12.5px; color:var(--text-dim);
  }
  .hh-comfort-set .launch-soon__dot{
    width:8px; height:8px; border-radius:50%; background:var(--brass-bright);
    box-shadow:0 0 0 0 rgba(211,166,103,0.6); animation:hhLaunchPulse 2.4s ease-out infinite;
  }
  .hh-comfort-set .launch-soon strong{ color:var(--brass-bright); letter-spacing:0.08em; text-transform:uppercase; font-size:11.5px; }
  .hh-comfort-set .launch-soon a{ color:var(--brass-bright); text-decoration:underline; text-underline-offset:2px; }
  @keyframes hhLaunchPulse{
    0%{ box-shadow:0 0 0 0 rgba(211,166,103,0.55); }
    70%{ box-shadow:0 0 0 9px rgba(211,166,103,0); }
    100%{ box-shadow:0 0 0 0 rgba(211,166,103,0); }
  }
  @media (prefers-reduced-motion: reduce){
    .hh-comfort-set .launch-soon__dot{ animation:none; }
  }
  .hh-comfort-set .soldout-note{ font-size:13px; color:var(--text-dim); margin-top:10px; line-height:1.5; }
  .hh-comfort-set .soldout-note a{ color:var(--brass-bright); text-decoration:underline; text-underline-offset:2px; }
  /* Sized to sit beside the qty stepper (which is ~38px tall) instead of
     the button's usual full-width slot. */
  .hh-comfort-set .add-to-cart--inline{
    margin-top:0; width:auto; flex:1;
    padding:11px 18px; font-size:14px;
  }
  /* Same colour treatment as the header's "Shop now" pill (.nav-cta) -
     outlined brass instead of the solid-filled Add to Cart button - sized
     to fill the full-width slot the Add to Cart button vacated here. */
  /* A short, light rule that sits just above the "View Cart" button,
     giving it a touch more visual separation from the Add to Cart note
     above without a full-width line across the whole buy-box. */
  .hh-comfort-set .view-cart-divider{
    width:56px; height:1px; margin:34px auto 0;
    background:var(--hairline);
    opacity:0.6;
  }
  /* Was a full-width text pill ("View Cart") - one of several stacked
     full-width shapes in an already busy buy-box column (Add to Cart,
     this, the qty stepper row above). Shrunk to a small centred icon
     button instead, matching the same visual language as the mobile
     cart-fab (see .cart-fab further down) rather than repeating another
     full-width bar - the aria-label keeps it just as clear to assistive
     tech, and the badge (mirrors .cart-fab__badge) keeps the live item
     count visible without needing the word "Cart" spelled out here too. */
  .hh-comfort-set .view-cart-btn{
    position:relative;
    display:flex; align-items:center; justify-content:center;
    width:46px; height:46px; margin:18px auto 0;
    background:transparent; color:var(--brass-bright);
    border:1px solid var(--brass);
    border-radius:50%;
    cursor:pointer;
    /* Colour/fill eased to the same slower, bespoke 0.7s curve as the
       other touch-feedback elements below (policy links, FAQ titles,
       "12 reviews") - see their own .is-pressed rules for why: a gentle
       settle rather than an instant snap, so a finger only brushing this
       on its way to scroll barely registers colour before it's gone.
       transform (the press-scale) is deliberately kept and only slightly
       slowed, not smoothed to match - this is the one control on the
       page meant to read as "tap me", so its zoom stays punchy on
       purpose. */
    transition:background 0.7s cubic-bezier(0.32,0.72,0,1),
      color 0.7s cubic-bezier(0.32,0.72,0,1),
      transform 0.22s ease;
  }
  .hh-comfort-set .view-cart-btn svg{ width:20px; height:20px; display:block; }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .view-cart-btn:hover{ background:var(--brass); color:#15171C; }
  }
  .hh-comfort-set .view-cart-btn__badge{
    position:absolute; top:-6px; right:-6px;
    min-width:18px; height:18px; padding:0 4px;
    border-radius:999px;
    background:var(--panel-raised); color:var(--brass-bright);
    border:1px solid var(--brass);
    font-size:10.5px; font-weight:700;
    display:none; align-items:center; justify-content:center;
    line-height:1;
  }
  /* Reflects what pressing "Add to Cart" will actually do right now - the
     +/- stepper above doesn't commit anything on its own, only this button
     does, so the wording (and count) here is kept live with every stepper
     press (see updateAddToCartNote). */
  .hh-comfort-set .add-to-cart-note{
    margin-top:10px; font-size:12px; color:var(--text-faint); text-align:center;
  }
  .hh-comfort-set .cart-scroll-hint{
    margin-top:14px; font-size:12px; color:var(--text-faint); text-align:center;
  }
  .hh-comfort-set .buy-meta{
    display:flex; justify-content:center;
    margin-top:16px; font-size:12.5px; color:var(--text-faint);
  }

  @media (max-width: 860px){
    .hh-comfort-set .buybox{ grid-template-columns:1fr; }
    .hh-comfort-set .gallery{ border-right:none; border-bottom:1px solid var(--hairline); }
  }

  /* ---------- REVIEWS SUMMARY ----------
     PLACEHOLDER SECTION - see the big comment at the top of the actual
     HTML block below (search "PLACEHOLDER CONTENT") before touching any
     of the mock numbers this styles. The CSS itself isn't placeholder -
     it stays as-is once real data replaces the markup. The twelve
     review cards this used to sit above now live in their own section
     near the footer (search "REVIEW CARDS ----------" further down) -
     this section is just the score/stars/count strip plus the "reviews"
     link that jumps down to them. */
  /* Padding trimmed from the original 64/80px (sized for the score cluster
     stacked below the text, a taller block) down to a symmetric 56px now
     that the cluster sits beside the text on one row instead - the section
     is visually shorter than it used to be, so the old bottom padding read
     as a dead gap before the next section's own top padding kicked in. */
  .hh-comfort-set section.reviews{ padding:56px 0; background:var(--bg); }

  /* Score cluster sits beside the section-head text rather than stacked
     below it - .section-head is shared across several sections (see its
     own rule further down), so its margin-bottom is zeroed out here,
     scoped to .reviews-header only, rather than touching the shared
     class itself. flex-wrap lets the cluster drop to its own line once
     the row can't fit both side by side (tablet/mobile), at which point
     .reviews-header's own gap (tightened in the max-width:620px query
     below) becomes the only spacing between them - no more of the old
     52px block-margin gap. */
  /* Demo-preview flag on the two ratings displays (REVIEWS SUMMARY strip
     and REVIEW CARDS header) - both currently show hand-written mock
     score/count/testimonial content (see the PLACEHOLDER CONTENT comment
     in the main file, right above the reviews section), not real
     customer reviews yet. A small, visible on-page label rather than
     only a code comment, so it can't accidentally be mistaken for a
     genuine rating by anyone looking at the live page before the
     Judge.me swap happens - remove this class from both spots (and this
     rule) the moment that swap is done. Deliberately understated - a
     small dashed-outline tag rather than a loud banner, so it reads as
     an honest disclosure rather than an alarming warning; brass-toned to
     stay on-brand rather than a jarring red/yellow "warning" colour. */
  .hh-comfort-set .hh-demo-note{
    display:inline-flex; align-items:center; gap:6px;
    margin-top:10px;
    padding:4px 10px;
    border:1px dashed var(--brass);
    border-radius:999px;
    font-size:11px;
    font-weight:600;
    letter-spacing:0.04em;
    text-transform:uppercase;
    color:var(--brass-bright);
    background:rgba(211,166,103,0.08);
    white-space:nowrap;
  }
  .hh-comfort-set .hh-demo-note svg{ width:12px; height:12px; flex-shrink:0; }

  .hh-comfort-set .reviews-header{
    display:flex; align-items:center; justify-content:flex-start;
    gap:56px; flex-wrap:wrap;
  }
  .hh-comfort-set .reviews-header .section-head{ margin-bottom:0; }
  .hh-comfort-set .reviews-header .reviews-summary{ flex-shrink:0; }

  .hh-comfort-set .reviews-summary{
    display:flex; align-items:center; gap:20px;
    flex-wrap:wrap;
  }
  .hh-comfort-set .reviews-summary__score{
    font-family:'Libre Caslon Display', serif; font-size:52px; color:var(--brass-bright);
    line-height:1;
    /* No manual offset here on purpose - rendered against the real Libre
       Caslon Display woff2 (fetched locally and checked at 5x scale with
       ruler lines against the star tips and caption baseline, since this
       sandbox can't reach Google Fonts to eyeball it directly), the glyph
       already sits correctly against align-items:center with no nudge
       needed. A small negative margin-top was tried here first based on
       measuring a live screenshot, but that screenshot's "4.8" was most
       likely rendering in a fallback serif (font not yet loaded/applied
       at capture time) rather than the real Libre Caslon Display - the
       nudge measured from it made the real-font version slightly worse
       (pushed the glyph above the star tips). If it still reads off on
       the live page after a hard refresh, re-check the computed
       font-family on this element first before re-tuning the offset. */
  }
  .hh-comfort-set .reviews-summary__detail{ display:flex; flex-direction:column; gap:6px; }
  .hh-comfort-set .reviews-stars{ display:flex; gap:3px; }
  .hh-comfort-set .reviews-stars svg{ width:18px; height:18px; }
  .hh-comfort-set .reviews-stars svg.is-filled{ fill:var(--brass-bright); }
  .hh-comfort-set .reviews-stars svg.is-empty{ fill:var(--hairline); }
  /* Part-filled star (the aggregate-score row only - see the comment by
     its markup). Two stacked, identically-sized svgs rather than one:
     star-bg is the always-visible empty/grey star, star-fg is the same
     star shape in gold, clipped from the right edge down to
     --star-clip-right (a percentage set per star in the liquid loop) so
     the gold portion fills left-to-right like a tiny progress bar.
     --star-clip-right is NOT simply "100% - fill%": this star path
     doesn't touch the edges of its own 24x24 viewBox - it sits inset
     about 9.17% on the left and 8.5% on the right (checked by rendering
     the path alone and measuring its actual pixel extent). Clipping
     against the full 0-100% box would waste the first ~9% and last
     ~8.5% of every star's travel on that dead padding, which crushes
     the visible range - e.g. 80% and 96% fill both end up reading as
     "basically full" instead of visibly different. The liquid loop
     below maps its 0-100% score fraction onto the star's REAL 9.17%
     -91.5% span instead, so --star-clip-right already IS the finished
     inset value (no calc() needed here). */
  .hh-comfort-set .reviews-stars .star-wrap{ position:relative; display:inline-block; width:18px; height:18px; }
  .hh-comfort-set .reviews-stars .star-wrap svg{ position:absolute; top:0; left:0; }
  .hh-comfort-set .reviews-stars .star-bg{ fill:var(--hairline); }
  .hh-comfort-set .reviews-stars .star-fg{ fill:var(--brass-bright); clip-path:inset(0 var(--star-clip-right) 0 0); }
  .hh-comfort-set .reviews-summary__count{ font-size:13.5px; color:var(--text-dim); }
  /* Jump link down to the REVIEW CARDS section (see its scroll-margin-top
     further down, which is what actually keeps the sticky header from
     covering the cards' heading when this is clicked). Underlined like
     .foot-credits' inline links rather than the site's other, plain nav
     links, since this one sits inline inside a sentence of grey caption
     text and needs its own visual signal that it's clickable there. */
  .hh-comfort-set .reviews-summary__link{
    color:var(--brass-bright); text-decoration:underline; text-underline-offset:2px;
    transition:color 0.2s ease;
  }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .reviews-summary__link:hover{ color:var(--text); }
  }

  /* .reviews-header wraps to two lines below ~900px (once the text block
     plus the score cluster plus their 56px gap no longer fit one row) -
     that 56px, read as vertical space between the wrapped lines, is far
     more than a stacked layout needs, so it's cut down here for every
     width where the wrap actually happens, not just the narrower
     max-width:620px range below (which only handles the score's own
     smaller phone-sized type). */
  @media (max-width: 900px){
    .hh-comfort-set .reviews-header{ gap:20px; align-items:flex-start; }
  }

  @media (max-width: 620px){
    .hh-comfort-set .reviews-summary{ gap:14px; }
    .hh-comfort-set .reviews-summary__score{ font-size:42px; }
  }

  /* ---------- FEATURES ---------- */
  .hh-comfort-set section.features{ padding:64px 0 100px; background:var(--bg); }
  .hh-comfort-set .section-head{ max-width:640px; margin-bottom:52px; }
  .hh-comfort-set .section-head .kicker{ margin-bottom:14px; }
  .hh-comfort-set .section-head h2{ font-size:clamp(28px,3vw,38px); }
  .hh-comfort-set .section-head p{ margin-top:14px; color:var(--text-dim); font-size:16px; max-width:56ch; }

  .hh-comfort-set .feature-grid{
    display:grid; grid-template-columns:repeat(4,1fr); gap:1px;
    background:var(--hairline); border:1px solid var(--hairline); border-radius:4px; overflow:hidden;
  }
  .hh-comfort-set .feature-cell{
    background:var(--panel); padding:32px 26px; border:1px solid transparent;
    position:relative; overflow:hidden;
  }
  /* Subtle focus line that replaces the old gold hover border below: a
     short grey bar centred on the card's bottom edge, hidden until the
     card is hovered (desktop) or scroll-selected (mobile), eased in/out
     with a smooth scale+fade so moving from one card to the next reads as
     a gentle crossfade rather than a hard swap. Desktop-only now (see the
     max-width:780px block further down, which turns this off entirely on
     mobile in favour of the per-card icon there instead) - 2px is this
     line's original desktop thickness, restored after an earlier mobile
     request to halve it turned out to affect both devices at once.
     bottom:-1px rather than 0: the cell's own 1px (transparent) border
     sits just outside its padding box, which is what bottom:0 aligns
     to - so at 0 the bar actually stops one pixel short of the card's
     real, visible bottom edge. -1px pushes it that one pixel further,
     so it lands flush against the edge instead of floating just above
     it. */
  .hh-comfort-set .feature-cell::after{
    content:"";
    position:absolute; left:50%; bottom:-1px;
    width:40px; height:2px;
    background:var(--text-dim);
    transform:translateX(-50%) scaleX(0);
    opacity:0;
    transition:transform 0.4s cubic-bezier(0.4,0,0.2,1), opacity 0.4s ease;
  }
  .hh-comfort-set .feature-cell h3{ font-family:'Manrope'; font-weight:700; font-size:16px; margin-bottom:10px; color:var(--text); transition:color 0.6s ease; }
  .hh-comfort-set .feature-cell p{ font-size:14px; color:var(--text-dim); margin:0; }
  /* Per-card icon: desktop hides it completely (that device keeps the
     caret bar above and its own hover treatment untouched) - see the
     max-width:780px block further down for its real, mobile-only
     styling and position. */
  .hh-comfort-set .feature-cell__icon{ display:none; }
  @media (max-width: 900px){ .hh-comfort-set .feature-grid{ grid-template-columns:repeat(2,1fr); } }
  @media (max-width: 560px){ .hh-comfort-set .feature-grid{ grid-template-columns:1fr; } }
  /* Mobile-only: only the one card currently in scroll-focus
     (.is-inview-selected, driven by cardObserver/updateActiveCard in the
     script - same signal the caret bar below each card already used)
     shows its full description; the other three fade theirs down to
     nothing, drawing the eye without literally deleting the text.
     Deliberately NOT collapsing each card's height any more (that was
     tried twice - the CSS grid-template-rows 0fr/1fr trick, restored,
     then reconsidered here for real): changing a card's own height as
     focus moves down the page also changes the .feature-grid container's
     total height on every scroll-driven focus change, which shifts every
     card below it, including - on the very next scroll frame - which
     card updateActiveCard now judges nearest the viewport's centre.
     That's a mild feedback loop, and it's very likely what read as
     "unsettling": the layout moving slightly under the exact gesture
     (scrolling) that's driving it, no matter how well-eased any one
     transition is. Each card is a fixed height now (driven once by its
     real content, never toggled), so the page never moves on its own -
     only opacity, colour and a touch of scale change below, none of
     which affect layout at all. See the .is-inview-selected block near
     the caret bar further down for the richer "in focus" treatment this
     was paired with, to make a fixed-height card still feel alive
     without any of it coming from a size change. */
  @media (max-width: 780px){
    .hh-comfort-set .feature-cell__desc-wrap > p{
      opacity:0;
      transition:opacity 0.5s ease;
    }
    .hh-comfort-set .feature-cell.is-inview-selected .feature-cell__desc-wrap > p{
      opacity:1;
      transition:opacity 0.65s ease 0.15s;
    }
  }
  @media (prefers-reduced-motion: reduce){
    .hh-comfort-set .feature-cell__desc-wrap > p{ transition:none; }
  }

  /* ---------- SPEC SHEET ---------- */
  .hh-comfort-set section.specs{ padding:64px 0 100px; background:var(--panel); }
  .hh-comfort-set .spec-sheet{
    /* Explicit --bg so the sheet reads as its own card against the
       section's lighter --panel band, and so its odd/even row shading
       below still contrasts correctly. */
    background:var(--bg);
    border:1px solid var(--hairline); border-radius:4px; overflow:hidden;
  }
  .hh-comfort-set .spec-row{
    display:grid; grid-template-columns: 1fr 1fr 1.6fr;
    border-bottom:1px solid var(--hairline);
    padding:20px 28px;
    gap:20px;
  }
  .hh-comfort-set .spec-row:last-child{ border-bottom:none; }
  .hh-comfort-set .spec-row:nth-child(odd){ background:var(--panel); }
  .hh-comfort-set .spec-row .k{ font-weight:700; font-size:14.5px; }
  .hh-comfort-set .spec-row .v{ font-size:14.5px; color:var(--brass-bright); }
  .hh-comfort-set .spec-row .d{ font-size:14px; color:var(--text-dim); }
  /* Desktop / tablet: every row shares ONE height. Each .spec-row is its own
     little grid, so a row whose description wraps onto two lines (Core, Care)
     used to come out taller than its one-line neighbours. Making the sheet
     itself a grid with equal auto-rows (1fr) sizes every row to the tallest
     one, whatever the copy is later edited to, and align-items:center keeps
     each row's label / value / description vertically centred inside it.
     text-wrap:balance evens out two-line descriptions so they don't leave a
     lonely last word (older browsers just ignore it). Phone (<=760px) is
     untouched: rows stack there and are meant to size to their content. */
  @media (min-width: 761px){
    .hh-comfort-set .spec-sheet{ display:grid; grid-auto-rows:1fr; }
    .hh-comfort-set .spec-row{ align-items:center; }
    .hh-comfort-set .spec-row .d{ line-height:1.5; text-wrap:balance; }
  }
  @media (max-width: 760px){
    .hh-comfort-set .spec-row{ grid-template-columns:1fr; gap:6px; padding:16px 20px; }
    /* Stacked single-column rows read differently from the three-up
       desktop grid - k/v/d sit one above another instead of side by
       side, so desktop's sizing (tuned for that wide layout) reads a
       touch large stacked on a narrow screen. Scaled down a notch each,
       keeping the same k/v ≈ d relationship (label and value still
       slightly larger and bolder/brass than the supporting description)
       rather than flattening them all to one size. */
    .hh-comfort-set .spec-row .k{ font-size:13px; }
    .hh-comfort-set .spec-row .v{ font-size:13px; }
    .hh-comfort-set .spec-row .d{ font-size:12.5px; }
  }

  /* Collapsed-by-default spec sheet (mobile only - see the max-width:760px
     block further down, same breakpoint .spec-row already stacks at).
     .spec-sheet-wrap itself is just a positioning shell; on desktop it's
     functionally invisible - the trigger stays display:none (set inside
     the mobile media query, so it never applies above 760px) and the
     panel is forced permanently open (see the min-width:761px override
     below), so nothing here changes desktop's appearance at all. */
  .hh-comfort-set .spec-sheet-wrap{ position:relative; }
  .hh-comfort-set .spec-sheet__trigger{
    display:none; /* shown only inside the mobile media query below */
    width:100%; align-items:center; justify-content:space-between;
    gap:16px; padding:16px 20px; margin-bottom:14px;
    background:var(--bg); border:1px solid var(--brass); border-radius:4px;
    color:var(--brass-bright); font-family:inherit;
    font-size:13.5px; font-weight:700; letter-spacing:0.01em;
    cursor:pointer; text-align:left;
  }
  /* Press feedback used to be a colour swap (brass fill, dark text) on
     touch devices only, with the generic scale-down opted out of
     entirely (transform:none) - a full-width row with content pinned to
     both ends read the generic press-scale as a janky pinch rather than
     a tap response. Replaced with a gentle, symmetric zoom instead: a
     modest scale rather than the sitewide default's more noticeable
     0.95, to keep that same "not a pinch" read, and a slow, deliberate
     0.7s in BOTH directions (declared once here rather than only on
     .is-pressed) so pressing down and releasing feel like one smooth
     out-and-back motion rather than a quick snap-down and a separately-
     timed snap-back. Split from .spec-sheet__trigger-icon's own
     transition below so the chevron's open/close flip keeps its own
     snappier, unrelated timing. */
  .hh-comfort-set .spec-sheet__trigger{
    transition:background 0.2s ease, color 0.2s ease, transform 0.7s cubic-bezier(0.32,0.72,0,1);
  }
  .hh-comfort-set .spec-sheet__trigger.is-pressed{ transform:scale(0.97); }
  .hh-comfort-set .spec-sheet__trigger-icon{
    transition:transform 0.3s cubic-bezier(0.32,0.72,0,1);
  }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .spec-sheet__trigger:hover{ background:var(--brass); color:#15171C; }
  }
  /* Text swaps closed/open purely in CSS (same pattern this file already
     uses for .reviews-show-more__more/__less) rather than JS rewriting
     textContent - one less thing toggleSpecSheet needs to touch. Used to
     be a flat display:none/inline swap (instant, since display can't be
     transitioned), then a plain opacity crossfade, then a slower up/down
     pair - now a snappier 0.4s, with the direction flipped the other way
     and given its own little story instead of a generic symmetric swap:
       - OPENING: "View full..." drops away downward as the sheet expands
         (it's the one sitting there being replaced, so it's the one that
         visibly gives way) while "Hide..." slides down into its place
         from just above - both travelling the same way the eye is
         already moving as the panel below unfurls open.
       - CLOSING: the reverse story, not just the reverse direction -
         "Hide..." rises back up and out (it did its job, so it exits
         upward rather than retracing the same downward path), while
         "View full..." slides back into place from below, arriving at
         the top the way it would if it had been waiting just out of
         sight the whole time the sheet was open.
     Both labels stay in the DOM the whole time, stacked exactly on top of
     each other (the closed one stays in normal flow, sizing the row; the
     open one is absolutely positioned over it). visibility is toggled
     alongside opacity/transform on a matching delay - instant on the way
     IN (so a label starts participating in the accessibility tree and
     can be read the moment it starts arriving) but held until the motion
     fully finishes on the way OUT (so the disappearing label doesn't get
     read by a screen reader, or clicked through by a mouse, while it's
     only visually gone). */
  .hh-comfort-set .spec-sheet__trigger-text{ position:relative; }
  .hh-comfort-set .spec-sheet__trigger-label--closed{
    opacity:1; visibility:visible; transform:translateY(0);
    transition:opacity 0.4s ease, transform 0.4s cubic-bezier(0.32,0.72,0,1), visibility 0s linear 0s;
  }
  .hh-comfort-set .spec-sheet__trigger-label--open{
    position:absolute; left:0; top:0;
    opacity:0; visibility:hidden; transform:translateY(-8px);
    transition:opacity 0.4s ease, transform 0.4s cubic-bezier(0.32,0.72,0,1), visibility 0s linear 0.4s;
  }
  .hh-comfort-set .spec-sheet-wrap.is-open .spec-sheet__trigger-label--closed{
    opacity:0; visibility:hidden; transform:translateY(8px);
    transition:opacity 0.4s ease, transform 0.4s cubic-bezier(0.32,0.72,0,1), visibility 0s linear 0.4s;
  }
  .hh-comfort-set .spec-sheet-wrap.is-open .spec-sheet__trigger-label--open{
    opacity:1; visibility:visible; transform:translateY(0);
    transition:opacity 0.4s ease, transform 0.4s cubic-bezier(0.32,0.72,0,1), visibility 0s linear 0s;
  }
  .hh-comfort-set .spec-sheet__trigger-icon{
    display:flex; align-items:center; justify-content:center; flex:none;
  }
  .hh-comfort-set .spec-sheet__trigger-icon svg{ width:16px; height:16px; }
  /* Chevron flips to point "up" once open - plain, well-understood
     expand/collapse language, deliberately distinct from the FAQ
     accordion's plus-to-x so the two don't read as the exact same
     control doing two different jobs. */
  .hh-comfort-set .spec-sheet-wrap.is-open .spec-sheet__trigger-icon{ transform:rotate(180deg); }
  @media (max-width: 760px){
    .hh-comfort-set .spec-sheet__trigger{ display:flex; }
    /* Panel height is set inline by toggleSpecSheet (see the script
       file) to the sheet's own measured scrollHeight, then transitioned
       to/from that exact pixel value - identical technique to the FAQ
       panel above, for the same reason (a guessed CSS max-height either
       clips a future content change or leaves a needless gap). */
    .hh-comfort-set .spec-sheet__panel{
      max-height:0; overflow:hidden;
      /* Slower than the first pass at this (was 0.4s) - reads as a
         deliberate, considered motion rather than a quick mechanical
         snap, which is what "much smoother and elegant" was asking for. */
      transition:max-height 0.55s cubic-bezier(0.32,0.72,0,1);
    }
    /* This used to fade each row in on its own small staggered delay
       (0.05s apart, one after another) while opening - closing had no
       such stagger (removing .is-open drops every row's delay back to
       0 in the same instant the collapse begins, see toggleSpecSheet in
       the script), so the two directions didn't actually move the same
       way: closing read as one clean, unified motion - the box and all
       its contents settling together - while opening read as several
       separate little reveals rippling one after another. That unified
       feel is exactly what was asked to carry over to opening too, so
       the per-row delays are gone: every row now fades/slides with the
       box's own height change, in the same instant, on the same
       duration and curve as .spec-sheet__panel above - one single
       motion, not a sequence of them, in both directions. Opacity/
       transform don't affect layout height, so this still doesn't throw
       off the scrollHeight measurement toggleSpecSheet reads. */
    .hh-comfort-set .spec-sheet__panel .spec-row{
      opacity:0; transform:translateY(8px);
      transition:opacity 0.55s cubic-bezier(0.32,0.72,0,1), transform 0.55s cubic-bezier(0.32,0.72,0,1);
    }
    .hh-comfort-set .spec-sheet-wrap.is-open .spec-sheet__panel .spec-row{ opacity:1; transform:translateY(0); }
    /* cubic-bezier(0.32,0.72,0,1) is a deceleration-only curve - fast off
       the mark, then easing into its landing. That's exactly the "fine"
       feel on CLOSE (a large, already-visible block easing down to
       nothing), but on OPEN the same curve's fast start is the very
       first thing that happens, right as the block leaves 0 - reading as
       an instant snap before it visibly starts easing. Swapped to a true
       ease-in-out (gentle away from the start too, not just into the
       end) ONLY while opening, via this .is-open-scoped override - it's
       added to the wrap before the height change runs (see toggleSpecSheet
       in the script), so it's already in effect for that transition, and
       removing .is-open on close (also before ITS height change runs)
       drops straight back to the base deceleration curve above, leaving
       the close motion exactly as it already was. */
    .hh-comfort-set .spec-sheet-wrap.is-open .spec-sheet__panel{
      transition-timing-function:cubic-bezier(0.65,0,0.35,1);
    }
    .hh-comfort-set .spec-sheet-wrap.is-open .spec-sheet__panel .spec-row{
      transition-timing-function:cubic-bezier(0.65,0,0.35,1);
    }
  }
  /* Desktop: forced permanently open regardless of toggleSpecSheet's own
     inline max-height, in case a visitor toggled it open on mobile and
     then widened the viewport (e.g. rotating a tablet, or a resize)
     without a reload - !important beats the inline style either way. */
  @media (min-width: 761px){
    .hh-comfort-set .spec-sheet__panel{ max-height:none !important; overflow:visible !important; }
  }
  @media (prefers-reduced-motion: reduce){
    .hh-comfort-set .spec-sheet__panel{ transition:none; }
    .hh-comfort-set .spec-sheet__panel .spec-row{ transition:none; }
    .hh-comfort-set .spec-sheet__trigger{ transition:none; }
    .hh-comfort-set .spec-sheet__trigger-icon{ transition:none; }
    .hh-comfort-set .spec-sheet__trigger-label--closed,
    .hh-comfort-set .spec-sheet__trigger-label--open{ transition:none; }
  }

  /* ---------- CROSS-SELL ---------- */
  .hh-comfort-set section.crosssell{ padding:64px 0 110px; background:var(--bg); }
  .hh-comfort-set .crosssell-head{ display:flex; align-items:flex-end; justify-content:space-between; margin-bottom:36px; gap:20px; flex-wrap:wrap; }
  .hh-comfort-set .addon-grid{ display:grid; grid-template-columns:1fr 1fr; gap:24px; }
  .hh-comfort-set .addon-card{
    background:var(--panel); border:1px solid var(--hairline); border-radius:4px;
    overflow:hidden; display:flex; flex-direction:column;
    min-width:0; /* same defensive hardening as .gallery above - see that
      comment. Not confirmed necessary given .addon-media's own fixed
      aspect-ratio + overflow:hidden, but costs nothing to keep. */
  }
  .hh-comfort-set .addon-media{ position:relative; aspect-ratio: 16/10; background:#0F1115; width:100%; min-width:0; }
  /* Crossfade layers - see the shared .media-layer rules up by .gallery-main. */
  /* Compact thumbnail strip for the accessory cards' own media (up to 4
     each, synced live from Shopify the same way the main gallery is -
     see the top of the file) - only rendered at all once a card actually
     has 2+ media items, so a single-photo accessory still looks exactly
     as clean as it always did. Sits inside the body's own side padding
     (26px) rather than full-bleed like .addon-media above it, so the
     thumbnails line up with the title/text below rather than the card's
     outer edge. */
  .hh-comfort-set .addon-thumbs{ display:flex; flex-wrap:wrap; gap:6px; padding:10px 26px 0; } /* wraps when an accessory has up to 7 photos + 1 video */
  .hh-comfort-set .addon-thumbs button{
    position:relative;
    padding:0; border:1px solid var(--hairline); background:#0F1115;
    width:44px; height:34px; border-radius:2px; cursor:pointer; overflow:hidden;
    /* Same addition as .gallery-thumbs button above, for the same reason:
       transform eases the shared .is-pressed press-scale at the same
       0.7s bespoke curve instead of snapping instantly. */
    transition:border-color 0.9s cubic-bezier(0.4,0,0.2,1),
      transform 0.7s cubic-bezier(0.32,0.72,0,1);
  }
  .hh-comfort-set .addon-thumbs button.active{ border-color:var(--brass); }
  .hh-comfort-set .addon-thumbs img{ width:100%; height:100%; object-fit:cover; transition:transform 0.25s ease; }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .addon-thumbs button:hover img{ transform:scale(1.08); }
  }
  .hh-comfort-set .addon-body{ padding:26px 26px 28px; display:flex; flex-direction:column; flex:1; }
  .hh-comfort-set .addon-body h3{ font-family:'Libre Caslon Display', serif; font-size:21px; font-weight:400; }
  .hh-comfort-set .addon-body p{ font-size:14px; color:var(--text-dim); margin-top:10px; flex:1; }
  .hh-comfort-set .addon-foot{ display:flex; align-items:center; justify-content:space-between; margin-top:20px; }
  .hh-comfort-set .addon-price{ font-size:19px; color:var(--brass-bright); font-family:'Libre Caslon Display', serif; }
  /* "Set of 2" clues on the UV Side-Window Screens card (each SKU contains
     two screens): a chip over the photo, a bold lead-in on the description,
     and a small caption under the price. The chip sits above the crossfading
     .media-layer elements (z-index) so it stays put while the slideshow runs. */
  .hh-comfort-set .addon-pack-chip{
    position:absolute; top:12px; left:12px; z-index:3;
    padding:5px 11px; border-radius:var(--radius-pill);
    background:rgba(15,17,21,0.78); border:1px solid var(--brass);
    color:var(--brass-bright); font-size:11px; font-weight:700;
    letter-spacing:0.08em; text-transform:uppercase; line-height:1.2;
    pointer-events:none;
  }
  .hh-comfort-set .addon-pack-emph{ color:var(--text); font-weight:700; }
  .hh-comfort-set .addon-price-wrap{ display:flex; flex-direction:column; gap:2px; }
  .hh-comfort-set .addon-price-note{ font-size:12px; color:var(--text-faint); }
  .hh-comfort-set .addon-add{
    border:1px solid var(--brass); color:var(--brass-bright);
    background:transparent; padding:9px 18px; border-radius:var(--radius-pill);
    font-size:13px; font-weight:700; cursor:pointer;
    transition:background 0.15s ease, color 0.15s ease, transform 0.12s ease;
  }
  /* Gated to real hover devices - same touch-sticks-hover reasoning as
     .add-to-cart above (this covers the sunshade/screens "Add to cart"
     buttons; #comfortDealAddBtn's own hover a few lines down already had this
     treatment). */
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .addon-add:hover{ background:var(--brass); color:#151318; }
  }
  .hh-comfort-set .addon-add.added{ background:#3E5A3F; border-color:#3E5A3F; color:#CDE0CD; }
  .hh-comfort-set .addon-add:disabled{ opacity:0.65; cursor:default; }
  .hh-comfort-set #comfortDealAddBtn{
    font-weight:400;
    border-color:rgba(93,182,96,0.55);
    color:var(--deal-green-bright);
    white-space:nowrap;
    flex-shrink:0;
  }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set #comfortDealAddBtn:hover{
      background:#3E5A3F;
      border-color:#3E5A3F;
      color:#CDE0CD;
    }
  }
  /* .added is a plain two-class selector, which is lower specificity than
     the ID-based hover rule above - without this, hovering the button
     while it's showing "Added ✓" (or right as the mouse lingers after the
     click that triggered it) would mask the green success colour and the
     later reset behind the grey hover fill instead. Matching it with an
     ID + class(+ hover) pairing guarantees the green state always wins,
     hover or not. Kept outside the hover-capable media query since the
     plain .added state (no :hover) must still apply on touch devices. */
  .hh-comfort-set #comfortDealAddBtn.added{
    background:#3E5A3F;
    border-color:#3E5A3F;
    color:#CDE0CD;
  }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set #comfortDealAddBtn.added:hover{
      background:#3E5A3F;
      border-color:#3E5A3F;
      color:#CDE0CD;
    }
  }
  /* Touch devices have no real :hover, so tapping any "Add to cart" style
     button previously gave almost no visible feedback - the shared
     .is-pressed press-scale (see near -webkit-tap-highlight-color at the
     top of this stylesheet) is only a 1-5% size change, easy to miss on a
     quick tap. Mirrors each button's own desktop :hover fill as a brief
     on-tap highlight instead: it's already wired to .is-pressed, which JS
     adds on pointerdown and clears on release, so the flash naturally
     lasts only as long as the finger is actually down. Gated to
     hover:none so a mouse/trackpad still gets the real :hover above,
     never this too. :not(.added) keeps a stray re-tap during the brief
     "Added ✓" window from masking that button's own green success fill. */
  @media (hover: none){
    .hh-comfort-set .add-to-cart.is-pressed{ background:var(--brass-bright); }
    .hh-comfort-set .addon-add.is-pressed:not(.added){ background:var(--brass); color:#151318; }
    .hh-comfort-set #comfortDealAddBtn.is-pressed:not(.added){
      background:#3E5A3F; border-color:#3E5A3F; color:#CDE0CD;
    }
    /* Same on-tap flash treatment, extended to the round cart icon that
       sits in the main product/buy-box area (#buyBoxViewCart) - mirrors
       its own desktop :hover fill above (brass fill, dark icon) exactly,
       so a tap gets the same clear feedback the Add to Cart buttons
       already had instead of just the shared 1-5% press-scale. */
    .hh-comfort-set .view-cart-btn.is-pressed{ background:var(--brass); color:#15171C; }
  }
  @media (max-width: 760px){ .hh-comfort-set .addon-grid{ grid-template-columns:1fr; } }

  .hh-comfort-set .bundle-note{
    margin-top:24px; padding:22px 26px;
    border:1px solid var(--hairline); border-radius:4px;
    background:var(--panel);
    font-size:14px; color:var(--text-dim);
    display:flex; align-items:center; justify-content:space-between; gap:20px; flex-wrap:wrap;
  }
  .hh-comfort-set .bundle-note__info{ max-width:520px; }
  .hh-comfort-set .bundle-note__info strong{
    display:block; font-family:'Libre Caslon Display', serif; font-weight:400;
    font-size:17px; color:var(--text); margin-bottom:6px;
  }
  .hh-comfort-set .bundle-note__info p{ margin:0; font-size:13.5px; color:var(--text-dim); }
  /* Same specificity family as .bundle-note__info p just above (element +
     2 classes) so this wins on source order rather than needing !important -
     a distinct colour/weight makes the savings line read as a highlighted
     callout under the plain description text above it. Empty and takes up
     no space until updateComfortSetDealCopy() fills it in on load. */
  .hh-comfort-set .bundle-note__info p.bundle-note__savings{
    margin:10px 0 0; font-size:13px; font-weight:700;
    color:var(--deal-green-bright);
  }

  /* ---------- TRUST / FOOTER ---------- */
  .hh-comfort-set section.trust{ padding:64px 0 100px; background:var(--panel); }
  .hh-comfort-set .trust-grid{ display:grid; grid-template-columns:repeat(3,1fr); gap:24px; }
  .hh-comfort-set .trust-cell{ padding:26px 0; border-top:1px solid var(--hairline); }
  .hh-comfort-set .trust-cell h4{ font-size:14.5px; font-weight:700; margin-bottom:6px; }
  .hh-comfort-set .trust-cell p{ font-size:13.5px; color:var(--text-dim); margin:0; }
  @media (max-width: 760px){ .hh-comfort-set .trust-grid{ grid-template-columns:1fr; } }

  /* ---------- REVIEW CARDS ----------
     PLACEHOLDER SECTION - see the "REVIEW CARDS" HTML comment on the
     markup below (and the big warning comment up in REVIEWS SUMMARY)
     before touching the twelve mock cards this styles. Sits as its own
     section directly above the footer/policy links on purpose (Sizo's
     call), reachable both by scrolling and via the "reviews" link in
     the summary strip near the top of the page. scroll-margin-top
     mirrors section.buy's - same reasoning: keeps the sticky header
     from covering this section's own heading when jumped to. */
  .hh-comfort-set section.review-cards{ padding:64px 0 100px; background:var(--bg); scroll-margin-top:88px; }

  /* Layout has two modes sharing the exact same card markup (see
     initReviewsCarousel in the script file) - CAROUSEL is the default
     everywhere, including desktop (Sizo's call - "the carousel is still
     default as it should be on mobile too"), and GRID is an opt-in only
     offered at tablet/desktop widths via .reviews-view-toggle below
     (hidden entirely under 761px - a 3-column grid squeezed onto a phone
     isn't a real option). Switching just toggles .is-grid-mode on
     .reviews-carousel; nothing in the DOM is rebuilt. */
  .hh-comfort-set .reviews-section-head{
    /* .section-head's own max-width:640px (above) is meant for a plain
       heading + paragraph - overridden back to none here so this row's
       justify-content:space-between spreads across the full section
       width instead of being capped mid-row, matching how
       .crosssell-head handles the same "heading left, control right"
       layout elsewhere in this file. */
    max-width:none;
    display:flex; align-items:flex-end; justify-content:space-between;
    gap:20px; flex-wrap:wrap;
  }
  /* Compact echo of the reviews-summary score, sat in this row - see its
     markup comment for why it's here at all. Under 761px this is plain
     flex's second (and, with the toggle hidden there, last) child, so
     justify-content:space-between above already puts it opposite the
     heading with no extra rule needed. */
  .hh-comfort-set .reviews-cards-rating{
    display:flex; align-items:center; gap:12px;
  }
  /* Stars-and-reviewer-count stack, sat to the score's left - mirrors the
     reviews-summary strip's own score+stars pairing above (big number,
     stars/caption alongside it), just with the two halves swapped, and
     "12 reviewers" here in place of the summary's fuller "Based on 12
     verified reviews" sentence, since this is meant to read as a quick
     echo, not a repeat of that whole line. */
  .hh-comfort-set .reviews-cards-rating__stars-col{
    display:flex; flex-direction:column; align-items:flex-start; gap:4px;
  }
  .hh-comfort-set .reviews-cards-rating__reviewers{
    /* Smaller and tighter than the site's normal caption line-height
       (1.55) - a proper small caption under the stars rather than
       something reading at nearly the same weight as the count itself. */
    font-size:10px; line-height:1.3; font-weight:600; letter-spacing:0.02em;
    color:var(--text-dim);
    /* The first star's own SVG path comes to a point right at its left
       edge, so its glyph's visual weight sits inset from the box's true
       left edge - lined up against "12 reviews" below (whose text starts
       flush with ITS box edge), that reads as the two being off from one
       another even though they share the same left coordinate. A couple
       of pixels of nudge brings the text in to meet the star's visual
       (not literal) left edge. */
    margin-left:2px;
  }
  .hh-comfort-set .reviews-cards-rating__score{
    /* Sized (not to match the h2 any more, but) to the stars+"12
       reviews" stack's own combined height just to its left - stars
       (16px) + the stack's 4px gap + the reviewers line's rendered
       height (10px * 1.3 line-height = 13px) = 33px, and with
       line-height:1 here a font-size this size renders a line box
       that height too, so the two sit level with each other rather
       than the score looming over (or shrinking under) the stack. */
    font-family:'Libre Caslon Display', serif; font-size:33px;
    color:var(--brass-bright); line-height:1;
  }
  /* Stars sized up a touch from their default caption-sized use
     elsewhere, so the "12 reviewers" line under them reads as a proper
     two-line stack rather than a squashed afterthought. */
  .hh-comfort-set .reviews-stars.reviews-stars--sm .star-wrap{ width:16px; height:16px; }
  .hh-comfort-set .reviews-stars.reviews-stars--sm svg{ width:16px; height:16px; }
  @media (max-width: 760px){
    /* Under 761px the badge used to share its row with the heading
       (space-between pushing it to the opposite edge) - fine at first
       glance, but two headline-size figures ("In their own words" and
       the score) fighting for the same narrow row read as cramped, not
       neat. flex-basis:100% forces it onto its own full-width line
       below the heading instead (the row's own 20px gap already becomes
       the vertical gap between the two lines, no extra margin needed),
       so both get real breathing room and the badge reads as a proper
       second line under the title rather than something squeezed in
       beside it. */
    .hh-comfort-set .reviews-cards-rating{ flex-basis:100%; }
  }
  .hh-comfort-set .reviews-view-toggle{
    display:none; /* shown from 761px up, below */
    gap:4px; padding:4px;
    border:1px solid var(--hairline); border-radius:var(--radius-pill);
    margin-bottom:2px; /* optical alignment against the h2 baseline above it */
  }
  @media (min-width: 761px){
    .hh-comfort-set .reviews-view-toggle{ display:flex; }
    /* Grid rather than flex from here up, now that the row has three
       children (heading, rating badge, view toggle) - justify-content:
       space-between would land the middle one wherever the flanking
       items' own widths happen to push it, not at the row's true
       centre. A 1fr/auto/1fr grid centres the rating badge exactly,
       regardless of how wide the heading text or the toggle end up
       being, while the heading and toggle keep the same edge-anchored
       positions they always had. */
    .hh-comfort-set .reviews-section-head{
      display:grid;
      grid-template-columns: 1fr auto 1fr;
      align-items:flex-end;
    }
    .hh-comfort-set .reviews-cards-rating{ justify-self:center; }
    .hh-comfort-set .reviews-view-toggle{ justify-self:end; }
  }
  .hh-comfort-set .reviews-view-btn{
    display:flex; align-items:center; gap:6px;
    padding:8px 14px; border:none; border-radius:var(--radius-pill);
    background:transparent; color:var(--text-dim);
    font-size:12.5px; font-weight:600; cursor:pointer;
    transition:background 0.15s ease, color 0.15s ease;
  }
  .hh-comfort-set .reviews-view-btn svg{ width:14px; height:14px; }
  .hh-comfort-set .reviews-view-btn.is-active{ background:var(--brass); color:#15171C; }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .reviews-view-btn:not(.is-active):hover{ background:var(--panel-raised); color:var(--text); }
  }

  .hh-comfort-set .reviews-carousel{
    position:relative; margin-top:44px;
    /* Mobile card width, referenced by both .reviews-grid's centering
       padding and .review-card's own width below - a custom property
       so the two stay in lockstep instead of each hard-coding the same
       number. Desktop/tablet override both back to the old values (see
       the 761px media query further down), so this only ever matters
       under that width. */
    --reviews-card-w: clamp(210px, 62vw, 250px);
  }

  /* CAROUSEL (default): a single flex row that scrolls horizontally,
     one card snapping into place at a time. Native scrollbar hidden
     since the arrows/dots below are the intended controls, but the
     track stays a real scroll container underneath - so trackpad,
     touch-swipe and keyboard scrolling all still work even with those
     hidden. */
  .hh-comfort-set .reviews-grid{
    display:flex; gap:16px;
    overflow-x:auto; scroll-snap-type:x mandatory;
    -webkit-overflow-scrolling:touch;
    scrollbar-width:none; -ms-overflow-style:none;
    /* Centres the focused card under 761px: padding this wide on both
       ends of the flex container gives the first/last card the same
       run-up to the middle that any other card gets from its
       neighbours, so scroll-snapping to card 1 or card 12 centres it
       exactly like every card in between, with a peek of whichever
       card(s) sit either side. Reset to 0 for the 3-per-page desktop/
       tablet layout below, which doesn't centre. */
    padding-left:calc((100% - var(--reviews-card-w)) / 2);
    padding-right:calc((100% - var(--reviews-card-w)) / 2);
    /* Vertical slack so the focused card's own lift/scale-up and its
       shadow never get cut off. Setting overflow-x to anything but
       visible implicitly turns overflow-y into a real scroll axis too
       (the browser can't leave one axis "visible" while the other
       scrolls), so without this the row's own top/bottom edge would
       clip the in-focus card's translateY(-4px) lift and box-shadow the
       instant it became the focused one. */
    padding-top:28px; padding-bottom:12px;
  }
  .hh-comfort-set .reviews-grid::-webkit-scrollbar{ display:none; }
  /* Click-and-drag affordance for a real mouse - see the pointerdown/
     move/up handling in initReviewsCarousel in the script file. Touch
     already drags this row natively (no cursor needed there), and
     pointer:fine alone would also catch a stylus, hence the fuller
     hover:hover pairing already used elsewhere on this page for the
     same "an actual mouse, not a touch/stylus" distinction. Cursor only
     - user-select is scoped to .is-dragging below so ordinary text
     selection inside a card still works until a drag is actually
     under way. */
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .reviews-grid{ cursor:grab; }
  }
  .hh-comfort-set .reviews-grid.is-dragging{ cursor:grabbing; user-select:none; }
  /* Suspended for the duration of any JS-driven eased scroll (auto-
     advance, or a manual arrow/dot/keyboard jump - see easedScrollTrackTo
     in the script file) - same reasoning as desktop's own permanent
     scroll-snap-type:none below: a mandatory snap can "correct" a scroll
     it thinks has settled mid-animation, short-circuiting the custom
     ease into what reads as an instant jump instead of a glide. Restored
     immediately after, so a real touch-drag still snaps to the nearest
     card as normal. */
  .hh-comfort-set .reviews-grid.is-auto-scrolling{ scroll-snap-type:none; }
  .hh-comfort-set .review-card{
    /* Set continuously by JS (mobile: on every scroll/snap settle;
       desktop: every frame while the row drifts) to how close this card
       currently sits to the row's own centre - 1 for the card in focus,
       falling off smoothly for its neighbours so they read as noticeably
       smaller. See updateCardFocus in the script file. is-inview-
       selected (mobile) and :hover (desktop) below both fold this same
       var() into their own transform rather than fighting over which
       transform "wins". */
    --focus-scale: 1;
    transform:scale(var(--focus-scale));
    /* Border-color and box-shadow are listed here too, not just
       transform - is-inview-selected/:hover below change all three at
       once when the focused card changes, and border-color/box-shadow
       previously had no transition of their own at all, so the gold
       highlight was popping on/off instantly even while the scroll
       itself glided smoothly - reading as an abrupt "switch" rather
       than a single coherent change. */
    transition:transform 0.45s ease-out, border-color 0.45s ease-out, box-shadow 0.45s ease-out;
    /* "center" (not "start") is what makes the current card sit in the
       middle with neighbours partially visible either side under
       761px - see the .reviews-grid padding just above, which is what
       makes that centering land correctly even for card 1 and card 12.
       Reset to "start" on desktop/tablet below, where paging by a full
       "page" of 3 cards at a time reads better left-aligned. */
    scroll-snap-align:center;
    flex:0 0 auto;
    width:var(--reviews-card-w);
    background:var(--panel); border:1px solid var(--hairline); border-radius:4px;
    padding:26px; display:flex; flex-direction:column; gap:14px;
    /* Lets the @container rules below key off THIS card's own rendered
       width rather than a viewport breakpoint - the mobile carousel's
       ~210-250px cards and a narrower tablet carousel "page" (e.g. a
       900px screen still only gives each card ~260px) both need the
       same smaller type, and a container query catches both without
       having to duplicate the same rules under two different @media
       widths. */
    container-type:inline-size;
    container-name:reviewcard;
  }
  @media (min-width: 761px){
    .hh-comfort-set .reviews-grid{
      gap:24px; padding-left:0; padding-right:0;
      /* Desktop no longer pages discretely (see the continuous drift in
         initReviewsCarousel) - it's a constant slow crawl now, so
         scroll-snap has nothing to snap TO mid-drift, and would otherwise
         fight the JS-driven scrollLeft the instant the drift pauses
         (hover, say) by trying to "correct" to the nearest snap point of
         its own, reading as an unwanted little jump right as it stops. */
      scroll-snap-type:none;
    }
    /* three cards per "page" width, still used for the manual arrow/dot/
       keyboard jump and for sizing the cards themselves - only the
       automatic motion between them stopped being page-at-a-time. */
    .hh-comfort-set .review-card{ width:calc((100% - 24px * 2) / 3); scroll-snap-align:none; }
  }
  /* Unconditional in both modes now - carousel never had a "show more"
     step (scrolling past the first page already reveals the rest), and
     grid mode's own fixed-height scroll box (see .is-grid-mode
     .reviews-grid further down) replaced its old checkbox-driven
     reveal with the same "just scroll for more" pattern, so neither
     mode still needs cards held back behind a click. */
  .hh-comfort-set .review-card--extra{ display:flex; }

  /* Desktop/tablet-only "in focus" lift - mirrors .addon-card:hover
     below (same transform/border/shadow), gated the same way on a real
     mouse hover so a touch tap never sticks it. Mobile doesn't get this;
     it gets its own always-on gold border on whichever card is centred
     (is-inview-selected below), since there's no hover there to react to. */
  @media (min-width: 761px) and (hover: hover) and (pointer: fine){
    .hh-comfort-set .review-card:hover{
      /* Folds in the same --focus-scale a hovered neighbour already has
         (from the continuous desktop drift) rather than snapping it up
         to full size just because the pointer happens to be over it. */
      transform:translateY(-4px) scale(var(--focus-scale));
      border-color:var(--brass);
      box-shadow:0 16px 32px rgba(0,0,0,0.28);
    }
  }
  /* Mobile-only "in view" gold focus - the exact same look as .addon-card
     .is-inview-selected (see that rule's own comment for why gold is kept
     off .feature-cell but on here/addon-card), just driven by the reviews
     carousel's own current-card index (initReviewsCarousel in the script
     file) rather than distance from the viewport's vertical centre, since
     this carousel scrolls horizontally rather than sitting in normal page
     flow. 760px matches the reviews carousel's own grid-capable cutoff
     exactly (see gridCapableMQ in the script), so there's no gap between
     "mobile" here and "mobile" there. */
  @media (max-width: 760px){
    .hh-comfort-set .review-card.is-inview-selected{
      transform:translateY(-4px) scale(var(--focus-scale));
      border-color:var(--brass);
      box-shadow:0 16px 32px rgba(0,0,0,0.28);
    }
  }

  .hh-comfort-set .review-card .reviews-stars svg{ width:15px; height:15px; }
  .hh-comfort-set .review-card__text{
    font-size:14.5px; line-height:1.6; color:var(--text-dim); flex:1;
  }
  /* Desktop/tablet only, per Sizo's call - an unusually long review no
     longer stretches the whole card (and its row-mates, since a flex row
     stretches every item to the tallest by default) to match it: past six
     lines or so it scrolls internally instead, capping every card in a
     row at the same sane height regardless of what any one review says.
     Mobile is left at its natural height (one card per screen already,
     so nothing else in the layout depends on cards matching heights). */
  @media (min-width: 761px){
    .hh-comfort-set .review-card__text{
      max-height:140px; overflow-y:auto; padding-right:4px;
      scrollbar-width:thin; scrollbar-color:var(--hairline) transparent;
    }
    .hh-comfort-set .review-card__text::-webkit-scrollbar{ width:5px; }
    .hh-comfort-set .review-card__text::-webkit-scrollbar-track{ background:transparent; }
    .hh-comfort-set .review-card__text::-webkit-scrollbar-thumb{ background:var(--hairline); border-radius:3px; }
    .hh-comfort-set .review-card__text:hover::-webkit-scrollbar-thumb,
    .hh-comfort-set .review-card__text:focus-within::-webkit-scrollbar-thumb{ background:var(--brass); }
  }
  /* Optional proof photos a reviewer attached - most cards have none
     (see the HTML comment above the mock data for why only some do).
     Plain camera-icon swatches here, deliberately NOT photorealistic -
     these stand in for wherever a real Judge.me-hosted photo URL will
     render once real reviews exist, and are placed between the quote
     and the meta row, same as most photo-review widgets (the "proof"
     sits right under the claim it's backing up). Each swatch is a real
     <button> (see the markup) - clicking one opens it full-size in the
     lightbox further down, rather than leaving the tiny 52px thumbnail
     as the only way to see it. */
  .hh-comfort-set .review-card__photos{ display:flex; gap:6px; }
  .hh-comfort-set .review-card__photo{
    position:relative; width:52px; height:52px; border-radius:4px; overflow:hidden;
    background:linear-gradient(135deg, var(--panel-raised), var(--hairline));
    border:1px solid var(--hairline);
    display:flex; align-items:center; justify-content:center;
    color:var(--text-faint); flex-shrink:0;
    padding:0; cursor:pointer;
    transition:border-color 0.15s ease;
  }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .review-card__photo:hover{ border-color:var(--brass); }
  }
  .hh-comfort-set .review-card__photo svg{ width:18px; height:18px; }
  .hh-comfort-set .review-card__photo__more{
    position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
    background:rgba(20,22,27,0.72); color:var(--text); font-size:12px; font-weight:700;
  }
  .hh-comfort-set .review-card__meta{
    display:flex; align-items:center; justify-content:space-between; gap:10px;
    padding-top:14px; border-top:1px solid var(--hairline);
  }
  /* Names vary a lot in length ("Sipho N." vs "Chantal du Plessis"),
     and this row used to just let a long one wrap - which, next to a
     flex sibling that ALSO wraps, could break "Verified Buyer" itself
     across two lines rather than the name. Now the name is the one
     thing allowed to give way: it truncates with an ellipsis
     (min-width:0 is required for that to work at all inside a flex
     item, ellipsis is silently ignored without it) while the badge
     next to it stays put at its full width and never wraps, whatever
     the name's length or the card's width. */
  .hh-comfort-set .review-card__name{
    font-size:13.5px; font-weight:700; color:var(--text);
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap; min-width:0;
  }
  .hh-comfort-set .review-card__badge{
    display:inline-flex; align-items:center; gap:4px; flex-shrink:0;
    font-size:11px; font-weight:700; letter-spacing:0.02em; text-transform:uppercase;
    color:var(--brass-bright); white-space:nowrap;
  }
  .hh-comfort-set .review-card__badge svg{ width:11px; height:11px; fill:var(--brass-bright); flex-shrink:0; }

  /* Smaller card, smaller everything inside it - keyed off the card's
     OWN rendered width (see container-type/-name on .review-card
     above) rather than a viewport breakpoint, so this applies equally
     to the mobile carousel's ~210-250px cards and a tablet carousel
     "page" that ends up just as narrow (three cards on a 900px screen
     are only ~260px each) - anywhere the card itself is this tight,
     not just "on phones". Grid mode's cards (356px+) never hit this. */
  @container reviewcard (max-width: 300px){
    .hh-comfort-set .review-card{ padding:18px; gap:10px; }
    .hh-comfort-set .review-card .reviews-stars svg{ width:13px; height:13px; }
    .hh-comfort-set .review-card__text{ font-size:13px; line-height:1.55; }
    .hh-comfort-set .review-card__photo{ width:42px; height:42px; }
    .hh-comfort-set .review-card__photo svg{ width:15px; height:15px; }
    .hh-comfort-set .review-card__meta{ padding-top:12px; gap:8px; }
    .hh-comfort-set .review-card__name{ font-size:12.5px; }
    .hh-comfort-set .review-card__badge{ font-size:9.5px; gap:3px; }
    .hh-comfort-set .review-card__badge svg{ width:9.5px; height:9.5px; }
  }

  /* Carousel controls - a plain row below the track (arrows either side
     of the dots) rather than floating over the cards, so nothing ever
     overlaps card content or a card's own shadow/border at any width. */
  .hh-comfort-set .reviews-carousel__controls{
    display:flex; align-items:center; justify-content:center; gap:18px;
    margin-top:28px;
  }
  .hh-comfort-set .reviews-arrow{
    display:flex; align-items:center; justify-content:center;
    width:44px; height:44px; border-radius:50%; flex-shrink:0;
    background:transparent; color:var(--brass-bright); border:1px solid var(--brass);
    cursor:pointer;
    transition:background 0.15s ease, color 0.15s ease, opacity 0.15s ease;
  }
  .hh-comfort-set .reviews-arrow svg{ width:18px; height:18px; }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .reviews-arrow:not(:disabled):hover{ background:var(--brass); color:#15171C; }
  }
  .hh-comfort-set .reviews-arrow:disabled{ opacity:0.35; cursor:default; }
  /* Mobile: bare chevrons, no circle - width/height/border-radius are
     deliberately left as-is (still a real 44px tap target, just an
     invisible one now) so this only removes what's visible, not the
     comfortable hit area. */
  @media (max-width: 760px){
    .hh-comfort-set .reviews-arrow{ background:transparent; border:none; }
  }
  @media (max-width: 760px) and (hover: hover) and (pointer: fine){
    .hh-comfort-set .reviews-arrow:not(:disabled):hover{ background:transparent; }
  }
  .hh-comfort-set .reviews-dots{ display:flex; align-items:center; gap:7px; }
  .hh-comfort-set .reviews-dot{
    width:7px; height:7px; border-radius:50%; border:none; padding:0;
    background:var(--hairline); cursor:pointer;
    transition:background 0.15s ease, transform 0.15s ease;
  }
  .hh-comfort-set .reviews-dot.is-active{ background:var(--brass-bright); transform:scale(1.35); }

  /* Cycle-timer loader - a hairline bar that quietly drains over the
     carousel's own auto-advance interval (mobile: one card, 7s, same
     pace as the main gallery slideshow; desktop: one full slow pass
     along the row, its own longer duration - see updateCardFocus /
     hhStartCycleAnim in the script). Restarted fresh by JS every time a
     new cycle actually begins, frozen in place (via animation-play-
     state) rather than reset whenever anything pauses it, so it never
     misrepresents time that didn't actually pass. Deliberately track-
     width, not card-width, and sits right under the arrows/dots -
     reads as "time until the row moves" rather than belonging to any
     one card. Hidden in grid mode, same as the controls row above it. */
  .hh-comfort-set .reviews-cycle-bar{
    /* Much shorter than a first pass at this (was 340px) - reads as a
       small, understated tick rather than a second progress bar
       competing with the controls row above it. */
    width:100%; max-width:96px; margin:14px auto 0;
    height:2px; border-radius:2px; overflow:hidden;
    background:var(--hairline);
  }
  /* Shorter again on mobile specifically - same 760px boundary as
     gridCapableMQ in the script (mobile never enters grid/drift mode).
     Desktop's 96px is left alone; this is purely about mobile, where the
     bar sits directly under a single centred card rather than a full
     multi-card row and doesn't need to read as prominently. */
  @media (max-width: 760px){
    .hh-comfort-set .reviews-cycle-bar{ max-width:56px; }
  }
  .hh-comfort-set .reviews-cycle-bar__fill{
    width:100%; height:100%; transform-origin:left center;
    transform:scaleX(0);
    background:var(--brass-bright);
    animation-name:none;
  }
  .hh-comfort-set .reviews-cycle-bar__fill.is-animating{
    animation:hh-cycle-drain var(--cycle-duration, 7000ms) linear forwards;
  }
  .hh-comfort-set .reviews-carousel.is-grid-mode .reviews-cycle-bar{ display:none; }
  /* Every restart of this animation (hhStartCycleAnim removing then
     re-adding .is-animating) used to jump the bar straight from wherever
     it had drained to back up to a full scaleX(1) in a single frame,
     since the keyframes' own "from" state applies the instant the
     animation starts, with no transition able to soften a jump an
     animation itself is causing - the ask was for that specific moment
     (a fresh cycle beginning, whether that's mobile staying on the same
     card or desktop resetting the whole row back to card 1) to refill
     smoothly instead. Solved inside this one animation rather than a
     separate transition-based phase, so hhStartCycleAnim's existing
     restart/pause/resume logic (including animation-play-state pausing
     mid-drain) needs no changes at all: the first 7% of the duration now
     eases from empty up to a near-full 0.94 (deliberately just short of
     the very brim - both an honest reflection of a countdown that's
     already ticking by the time it's visibly refilled, and the
     "doesn't have to be to the brim" the smoothing was asked to allow
     for), on its own gentle deceleration curve; the remaining 93% then
     drains back down to empty at a strict, undistorted linear pace, same
     as before, so the bar still tracks real elapsed time accurately. */
  @keyframes hh-cycle-drain{
    0%{ transform:scaleX(0); animation-timing-function:cubic-bezier(0.16,1,0.3,1); }
    7%{ transform:scaleX(0.94); animation-timing-function:linear; }
    100%{ transform:scaleX(0); }
  }
  @media (prefers-reduced-motion: reduce){
    .hh-comfort-set .reviews-cycle-bar__fill{ transition:none; }
    .hh-comfort-set .reviews-cycle-bar__fill.is-animating{ animation:none; transform:scaleX(0); }
  }

  /* GRID (opt-in, tablet/desktop only): a fixed-height, equal-sized
     3-column grid that scrolls (drag-with-the-mouse, same as the
     carousel - see .reviews-grid's own cursor:grab and the pointerdown/
     move/up handling in initReviewsCarousel) rather than growing the
     page - all 12+ cards are already in the DOM at once (the old
     checkbox-driven "show all 12" reveal below is now unconditional in
     both modes, see .review-card--extra/.reviews-show-more further
     down), just clipped to a few rows' worth of height until scrolled. */
  .hh-comfort-set .reviews-carousel.is-grid-mode .reviews-grid{
    display:grid; grid-template-columns:repeat(3,1fr);
    /* A FIXED px row height, not 1fr - measured against this file's own
       real markup/CSS (12 review cards, some with photos, desktop
       width) via a Playwright render rather than guessed, so every
       card is genuinely the same size with no clipped or truncated
       content. 1fr was tried first and looked right on its own, but it
       only equalizes rows when the grid's own height is otherwise
       unconstrained - add the max-height/overflow-y below on the same
       element and the browser can no longer treat the grid's height as
       indefinite for that distribution, so 1fr silently stops
       equalizing across rows again (confirmed with the same Playwright
       check) and rows go back to only matching their own row-mates.
       A fixed value has no such dependency on the container's own
       height, so it keeps working correctly alongside the scroll cap. */
    grid-auto-rows:322px;
    /* Shows two full rows with a deliberate ~30px peek of a third row's
       top edge - a visible cue that there's more to drag/scroll to,
       echoing the same "neighbour peeking into frame" language the
       carousel's own centred card already uses. */
    max-height:700px;
    overflow-y:auto; overflow-x:hidden;
    scroll-snap-type:none;
  }
  .hh-comfort-set .reviews-carousel.is-grid-mode .review-card{ width:auto; height:100%; scroll-snap-align:none; }
  .hh-comfort-set .reviews-carousel.is-grid-mode .reviews-carousel__controls{ display:none; }

  /* The checkbox + label "show all 12 reviews" step this used to be
     (grid mode only, carousel never had one) is retired now that grid
     mode is its own fixed-height scroll box instead of a growing
     static grid - every card is unconditionally visible in both modes
     (see .review-card--extra above), and scrolling/dragging is what
     reveals the rest. The checkbox input itself (#hhReviewsExpand)
     still exists in the markup, unused but harmless - simplest to
     leave it in place rather than also needing a main-file change to
     remove it. .reviews-show-more is hidden directly on its own base
     rule below rather than via a separate override elsewhere, so
     there's one place to look, not two rules racing on source order. */
  .hh-comfort-set .reviews-expand-toggle{
    position:absolute; width:1px; height:1px; margin:-1px; padding:0;
    overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0;
  }
  .hh-comfort-set .reviews-show-more{ display:none; }

  @media (max-width: 620px){
    .hh-comfort-set .reviews-view-toggle{ display:none !important; } /* belt-and-braces - see the JS-side guard too */
  }

  /* Empty state - shown instead of .reviews-grid whenever
     hh_review_summary_count is 0 (see the liquid `if` around both
     branches). Outline stars rather than the filled brass ones used
     everywhere else in this section - deliberately reads as "not rated
     yet" rather than a duller version of a real score. */
  .hh-comfort-set .reviews-empty{
    max-width:420px; margin:0 auto; padding:20px 20px 8px;
    text-align:center;
  }
  .hh-comfort-set .reviews-empty__stars{
    display:flex; justify-content:center; gap:7px; margin-bottom:22px;
  }
  .hh-comfort-set .reviews-empty__stars svg{
    width:22px; height:22px; fill:none; stroke:var(--hairline); stroke-width:1.4;
  }
  .hh-comfort-set .reviews-empty h3{
    font-family:'Libre Caslon Display', serif; font-size:23px; color:var(--text);
    margin-bottom:12px;
  }
  .hh-comfort-set .reviews-empty p{ font-size:14.5px; line-height:1.65; color:var(--text-dim); }
  .hh-comfort-set .reviews-empty a{ color:var(--brass-bright); text-decoration:underline; text-underline-offset:2px; }

  /* ---------- REVIEWS LIGHTBOX ----------
     Opened by clicking any .review-card__photo swatch (see the
     initReviewsLightbox function in the script file). Every review
     card here is mock/placeholder content, so this simply shows the
     same camera-icon placeholder enlarged - never a fabricated
     photorealistic image - it's here to prove out the "tap a photo ->
     see it properly large" interaction ahead of the real Judge.me
     photo URLs landing in these cards. Stage is sized off the panel
     width (min(480px, 100%)), not a fixed pixel photo size, so it's
     genuinely large on any screen rather than "slightly bigger than
     the 42-52px thumbnail" - the whole point of the "not miniscule"
     requirement this exists to satisfy. */
  .hh-comfort-set .reviews-lightbox{
    position:fixed; inset:0; z-index:60;
    display:flex; align-items:center; justify-content:center;
    padding:24px;
    /* Stops a drag/swipe starting anywhere on this overlay from being
       treated as a page-scroll gesture at all (paired with the touchmove/
       wheel listeners in initReviewsLightbox in the script file, which
       preventDefault the same gestures belt-and-suspenders) - see that
       function's comments for why this replaced the old freeze-the-body-
       and-restore-scroll technique entirely, rather than patching that
       technique again. Taps/clicks on the buttons inside are a different
       interaction and are untouched by either. */
    touch-action:none; overscroll-behavior:contain;
  }
  .hh-comfort-set .reviews-lightbox[hidden]{ display:none; }
  .hh-comfort-set .reviews-lightbox__backdrop{
    position:absolute; inset:0; background:rgba(10,11,14,0.86);
  }
  .hh-comfort-set .reviews-lightbox__panel{
    position:relative; z-index:1;
    width:min(480px, 100%);
    background:var(--panel); border:1px solid var(--hairline); border-radius:4px;
    padding:20px; display:flex; flex-direction:column; gap:14px;
  }
  .hh-comfort-set .reviews-lightbox__close{
    position:absolute; top:-16px; right:-16px; z-index:2;
    width:40px; height:40px; border-radius:50%;
    background:var(--panel-raised); border:1px solid var(--hairline);
    color:var(--text); display:flex; align-items:center; justify-content:center;
    padding:0; cursor:pointer; transition:border-color 0.15s ease, color 0.15s ease;
  }
  .hh-comfort-set .reviews-lightbox__close svg{ width:18px; height:18px; }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .reviews-lightbox__close:hover{ border-color:var(--brass); color:var(--brass-bright); }
  }
  .hh-comfort-set .reviews-lightbox__stage{
    position:relative; width:100%; aspect-ratio:1;
    border-radius:4px; overflow:hidden;
    background:linear-gradient(135deg, var(--panel-raised), var(--hairline));
    display:flex; align-items:center; justify-content:center;
    color:var(--text-faint);
  }
  .hh-comfort-set .reviews-lightbox__image svg{ width:96px; height:96px; }
  .hh-comfort-set .reviews-lightbox__nav{
    position:absolute; top:50%; transform:translateY(-50%); z-index:2;
    width:38px; height:38px; border-radius:50%; flex-shrink:0;
    background:rgba(20,22,27,0.62); border:1px solid var(--hairline);
    color:var(--text); display:flex; align-items:center; justify-content:center;
    padding:0; cursor:pointer; transition:border-color 0.15s ease, color 0.15s ease;
  }
  .hh-comfort-set .reviews-lightbox__nav svg{ width:18px; height:18px; }
  .hh-comfort-set .reviews-lightbox__nav--prev{ left:12px; }
  .hh-comfort-set .reviews-lightbox__nav--next{ right:12px; }
  .hh-comfort-set .reviews-lightbox__nav[hidden]{ display:none; }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .reviews-lightbox__nav:hover{ border-color:var(--brass); color:var(--brass-bright); }
  }
  /* Caption text length varies a fair bit between photos (short one-word
     captions vs. a full sentence), and it used to sit at its natural
     height - so stepping to a caption that wrapped onto a second line
     changed the panel's total height, and since the panel is centered
     in the viewport (.reviews-lightbox has align-items:center), THAT
     recentred the whole panel including the stage above it, which is
     exactly what read as the prev/next arrows "jumping" up or down on
     every click. Reserving two lines' worth of height here up front,
     with the text vertically centred inside that reserved space, keeps
     the panel's height (and therefore the stage/arrows) identical
     regardless of whether the current caption needs one line or two. */
  .hh-comfort-set .reviews-lightbox__caption{
    margin:0; text-align:center; font-size:13.5px; line-height:1.4; color:var(--text-dim);
    min-height:calc(13.5px * 1.4 * 2);
    display:flex; align-items:center; justify-content:center;
  }
  /* Footer row: always the caption's home (so there's only ever one
     caption element in the DOM), with the prev/next buttons living here
     too - at every screen size, not just mobile. The pair that used to
     be overlaid on top of the photo (position:absolute against the
     stage) has been removed from the markup entirely, since it was the
     one part of this panel that behaved differently between mobile and
     desktop, and desktop kept showing the arrow-jump the footer
     relocation had already fixed on mobile. There's only ever one nav
     pair now, sat statically in this row, which can't drift regardless
     of what the stage above it does. */
  .hh-comfort-set .reviews-lightbox__footer{ display:flex; align-items:center; gap:10px; }
  .hh-comfort-set .reviews-lightbox__footer .reviews-lightbox__caption{ flex:1; }
  .hh-comfort-set .reviews-lightbox__nav--footer{
    display:flex; position:static; transform:none; width:30px; height:30px;
  }
  .hh-comfort-set .reviews-lightbox__nav--footer svg{ width:15px; height:15px; }
  /* .reviews-lightbox__nav[hidden]{ display:none; } above is two class-
     level selectors deep vs. this rule's one, so it still wins here
     whenever a button also carries the hidden attribute (single-photo
     groups) - no extra [hidden] override needed on top of this. */
  @media (min-width: 781px){
    .hh-comfort-set .reviews-lightbox__nav--footer{ width:34px; height:34px; }
    .hh-comfort-set .reviews-lightbox__nav--footer svg{ width:17px; height:17px; }
  }
  @media (max-width: 400px){
    .hh-comfort-set .reviews-lightbox{ padding:16px; }
    .hh-comfort-set .reviews-lightbox__panel{ padding:16px; }
    .hh-comfort-set .reviews-lightbox__close{ top:-14px; right:-14px; width:36px; height:36px; }
  }
  /* ---------- FAQ ---------- */
  .hh-comfort-set section.faq{ padding:64px 0 100px; background:var(--panel); }
  .hh-comfort-set .faq-list{ max-width:720px; margin:0 auto; }
  .hh-comfort-set .faq-item{ border-top:1px solid var(--hairline); }
  .hh-comfort-set .faq-item:last-child{ border-bottom:1px solid var(--hairline); }
  .hh-comfort-set .faq-item__trigger{
    width:100%; display:flex; align-items:center; justify-content:space-between;
    gap:20px; padding:22px 2px; background:none; border:none; cursor:pointer;
    text-align:left; color:var(--text); font-family:inherit;
  }
  /* Opts this specific button out of the page-wide .is-pressed press-scale
     (see transform:scale(0.95) near -webkit-tap-highlight-color at the top
     of the stylesheet) - that generic feedback was tuned against small,
     roughly-square controls (icon buttons, pills), where a 5% shrink barely
     registers. This trigger is a full-width row with content pinned to
     both ends (question text left, icon right), so the same scale()
     visibly pulls both ends inward from a shared centre - read as a janky
     "shrink" reaction, and one that can fire the instant a finger touches
     down to start a scroll (pointerdown fires before the browser knows
     the gesture is a scroll, not a tap), not only on an actual tap. The
     accordion opening/closing is already immediate, obvious feedback for
     a real tap, so no replacement press effect is needed here. */
  .hh-comfort-set .faq-item__trigger.is-pressed{ transform:none; }
  /* transition added here specifically for the on-tap colour (see
     .faq-item__trigger.is-pressed .faq-item__question in the hover:none
     block below) - same 0.7s bespoke ease as .foot-links a and
     .buybox-rating__count, so a scroll started on the question text
     doesn't read as an instant colour blink. */
  .hh-comfort-set .faq-item__question{ font-size:16px; font-weight:600; transition:color 0.7s cubic-bezier(0.32,0.72,0,1); }
  /* One small circled icon doubles as both the affordance and the open/
     closed indicator - a plus rotated exactly 45deg reads as an x, so no
     separate "expanded" icon/swap is needed, just a transform. Filled
     solid brass while open, echoing the same hover-fill treatment the
     gallery slideshow button and the cart view button already use
     elsewhere on this page - one consistent "this brass circle is the
     active one" language across the whole page, not a one-off. */
  .hh-comfort-set .faq-item__icon{
    display:flex; align-items:center; justify-content:center; flex:none;
    width:28px; height:28px;
    border:1px solid var(--brass); border-radius:50%;
    color:var(--brass-bright);
    transition:background 0.2s ease, color 0.2s ease, border-color 0.2s ease;
  }
  .hh-comfort-set .faq-item__icon svg{ width:14px; height:14px; transition:transform 0.3s cubic-bezier(0.32,0.72,0,1); }
  .hh-comfort-set .faq-item.is-open .faq-item__icon{ background:var(--brass); border-color:var(--brass); color:#15171C; }
  .hh-comfort-set .faq-item.is-open .faq-item__icon svg{ transform:rotate(45deg); }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .faq-item__trigger:hover .faq-item__question{ color:var(--brass-bright); }
    /* Twists the + toward the open state's x (same rotate(45deg) as
       .faq-item.is-open .faq-item__icon svg above, same transition) just
       on hover, colour/fill left alone - a preview of "this opens" before
       the click, not the open state itself. Mouse/trackpad only: on
       touch there's no hover to preview with, the accordion just opens
       on tap. Harmless on an already-open item's icon too, since it's
       hovering the exact same rotated value .is-open already set. */
    .hh-comfort-set .faq-item__trigger:hover .faq-item__icon svg{ transform:rotate(45deg); }
  }
  /* Mirrors the desktop :hover colour above as touch feedback instead of
     the (already removed, see .faq-item__trigger.is-pressed further up)
     press-scale - touch devices have no real :hover, so without this a
     tap on a question title had no colour feedback of its own before the
     accordion itself opens. */
  @media (hover: none){
    .hh-comfort-set .faq-item__trigger.is-pressed .faq-item__question{ color:var(--brass-bright); }
  }
  /* Panel height is set inline by toggleFaq (see the script file) to the
     answer's own measured scrollHeight, then transitioned to/from that
     exact pixel value - max-height alone (this rule) only supplies the
     transition and the closed (0) resting state; see the script for why
     a JS-measured height beats a guessed CSS max-height here. */
  .hh-comfort-set .faq-item__panel{
    max-height:0; overflow:hidden;
    transition:max-height 0.35s cubic-bezier(0.32,0.72,0,1);
  }
  .hh-comfort-set .faq-item__answer{
    padding:0 2px 24px; max-width:64ch;
    opacity:0; transition:opacity 0.2s ease;
  }
  .hh-comfort-set .faq-item.is-open .faq-item__answer{ opacity:1; transition:opacity 0.25s ease 0.1s; }
  .hh-comfort-set .faq-item__answer p{ margin:0; color:var(--text-dim); font-size:14.5px; line-height:1.65; }
  .hh-comfort-set .faq-item__answer a{ color:var(--brass-bright); text-decoration:underline; text-underline-offset:2px; }
  @media (max-width: 760px){
    .hh-comfort-set section.faq{ padding:48px 0 72px; }
    .hh-comfort-set .faq-item__trigger{ padding:17px 0; gap:14px; }
    .hh-comfort-set .faq-item__question{ font-size:14.5px; }
    .hh-comfort-set .faq-item__icon{ width:24px; height:24px; }
    .hh-comfort-set .faq-item__icon svg{ width:12px; height:12px; }
    .hh-comfort-set .faq-item__answer{ font-size:13.5px; padding-bottom:18px; }
    .hh-comfort-set .faq-item__answer p{ font-size:13.5px; }
  }
  @media (prefers-reduced-motion: reduce){
    .hh-comfort-set .faq-item__panel{ transition:none; }
    .hh-comfort-set .faq-item__icon svg{ transition:none; }
    .hh-comfort-set .faq-item__answer{ transition:none; }
  }

  .hh-comfort-set footer.site{ border-top:1px solid var(--hairline); padding:40px 0 120px; background:var(--bg); }
  .hh-comfort-set .foot-links{
    display:flex; flex-wrap:wrap; justify-content:center;
    gap:10px 28px;
    padding-bottom:26px; margin-bottom:26px;
    border-bottom:1px solid var(--hairline);
    font-size:13px;
  }
  /* 0.7s bespoke ease (matches .view-cart-btn/.faq-item__question/
     .buybox-rating__count) rather than a quick snap, so a scroll started
     from directly on top of a link barely has time to tint before easing
     back out, instead of an abrupt on/off flash either way. */
  .hh-comfort-set .foot-links a{ color:var(--text-dim); transition:color 0.7s cubic-bezier(0.32,0.72,0,1); }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .foot-links a:hover{ color:var(--brass-bright); }
  }
  /* Opts these links out of the page-wide .is-pressed press-scale (see
     transform:scale(0.95) near -webkit-tap-highlight-color at the top of
     this file) - same reasoning as .buybox-rating/.free-delivery-note/
     .faq-item__trigger elsewhere in this file: this row sits at the very
     bottom of the page, exactly where a finger lands to start scrolling
     back up, and pointerdown (which applies .is-pressed) fires before the
     browser knows a touch will become a scroll rather than a tap. */
  .hh-comfort-set .foot-links a.is-pressed{ transform:none; }
  /* Touch devices have no real :hover, so a tap on one of these links had
     no feedback of its own beyond the (now-removed) press-scale above.
     Mirrors the desktop :hover colour instead, on the same .is-pressed
     class JS already toggles - reusing --brass-bright rather than
     inventing a new colour, since that's already this site's one
     accent colour for "link/control being interacted with" everywhere
     else (footer links' own :hover just above, buy-box rating count on
     hover, wordmark ampersand, etc.). */
  @media (hover: none){
    .hh-comfort-set .foot-links a.is-pressed{ color:var(--brass-bright); }
  }
  .hh-comfort-set .foot-row{ display:flex; justify-content:space-between; align-items:center; flex-wrap:wrap; gap:16px; }
  .hh-comfort-set .foot-row p{ font-size:13px; color:var(--text-faint); margin:0; }
  @media (max-width: 560px){
    .hh-comfort-set .foot-links{ justify-content:center; gap:10px 20px; font-size:12.5px; }
  }

  /* ---------- FOOTER: social + payment trust row ---------- */
  /* Sits between the policy-link row above and the copyright row below,
     each half (social / payments) stacking to its own centred column on
     narrow screens. Shares the page's small-caps "label above content"
     language already used for .variant-label/.kicker elsewhere. */
  .hh-comfort-set .foot-connect{
    display:flex; justify-content:space-between; align-items:flex-start;
    flex-wrap:wrap; gap:28px;
    padding-bottom:26px; margin-bottom:26px;
    border-bottom:1px solid var(--hairline);
  }
  .hh-comfort-set .foot-connect__label{
    display:block; font-size:11.5px; font-weight:700;
    letter-spacing:0.06em; text-transform:uppercase;
    color:var(--text-faint); margin-bottom:12px;
  }
  /* Social icons reuse the same circular-outline-button language as
     .view-cart-btn above (brass ring, fills brass on hover) so this row
     reads as part of the same design system rather than a bolted-on
     widget - just a size step down (38px vs 46px) since it's a secondary,
     footer-level affordance rather than a primary buy-box action. */
  .hh-comfort-set .foot-social__icons{ display:flex; gap:10px; }
  .hh-comfort-set .foot-social__icon{
    display:flex; align-items:center; justify-content:center;
    width:38px; height:38px;
    border:1px solid var(--brass);
    border-radius:50%;
    color:var(--brass-bright);
    /* Same slowdown as the other footer/buy-box touch-feedback elements
       above (0.7s, the same bespoke settle curve) - the hover fill/
       colour and the (currently unused, see .is-pending below) opacity
       state are unchanged in WHAT they do, just eased in much more
       gently than the previous 0.15s snap. */
    transition:background 0.7s cubic-bezier(0.32,0.72,0,1),
      color 0.7s cubic-bezier(0.32,0.72,0,1),
      opacity 0.7s cubic-bezier(0.32,0.72,0,1);
  }
  .hh-comfort-set .foot-social__icon svg{ width:17px; height:17px; }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .foot-social__icon:not(.is-pending):hover{
      background:var(--brass); color:#15171C;
    }
  }
  /* All four social/contact icons are real, working links as of Round AQ
     (Facebook, Instagram, TikTok accounts all exist now). .is-pending is
     kept around, unused, as the honest placeholder treatment for any
     FUTURE platform added before its real handle/URL is known - render
     it as an inert <span> (no href at all, so there's nothing to
     click-through to nowhere) with this class rather than a dead link,
     then swap in a real <a href> once the handle exists; no other
     markup needs to change. */
  .hh-comfort-set .foot-social__icon.is-pending{
    opacity:0.42; cursor:default; border-color:var(--hairline); color:var(--text-faint);
  }
  /* Payment badges sit on a light chip regardless of the page's dark
     theme - card-network marks are designed for light backgrounds and
     read as muddy/off-brand tinted onto a dark panel directly, which is
     why virtually every dark-themed storefront still shows them on a
     small white tile rather than recolouring them. */
  .hh-comfort-set .foot-payments{ display:flex; flex-direction:column; align-items:flex-end; }
  .hh-comfort-set .foot-payments__badges{ display:flex; gap:8px; }
  .hh-comfort-set .pay-badge{
    display:flex; align-items:center; justify-content:center;
    width:46px; height:30px;
    background:#F1EDE6;
    border-radius:4px;
    box-shadow:0 1px 3px rgba(0,0,0,0.3);
  }
  .hh-comfort-set .pay-badge--visa{
    font-family:'Manrope', sans-serif; font-weight:800; font-style:italic;
    font-size:13px; letter-spacing:-0.02em; color:#1A1F71;
  }
  .hh-comfort-set .pay-badge--mastercard{ gap:0; }
  .hh-comfort-set .pay-badge--mastercard span{
    width:16px; height:16px; border-radius:50%;
  }
  .hh-comfort-set .pay-badge--mastercard span:first-child{ background:#EB001B; margin-right:-6px; }
  .hh-comfort-set .pay-badge--mastercard span:last-child{ background:#F79E1B; mix-blend-mode:multiply; }
  /* Kept on its own brand green (unrelated to --deal-green above) - this
     sits on the light #F1EDE6 chip alongside the untouched VISA navy and
     Mastercard red/orange, so it's a payment-network mark, not a
     discount signal, and #CDE0CD (built for pale-on-dark) went almost
     invisible against that light chip. */
  .hh-comfort-set .pay-badge--eft{
    flex-direction:column; gap:1px; padding:3px 0;
  }
  .hh-comfort-set .pay-badge--eft svg{ width:14px; height:14px; color:#1F7A4D; }
  .hh-comfort-set .pay-badge--eft span{
    font-size:8px; font-weight:800; letter-spacing:0.02em; color:#1F7A4D;
  }
  .hh-comfort-set .foot-payments__secured{
    display:flex; align-items:center; gap:5px;
    margin:10px 0 0; font-size:11.5px; color:var(--text-faint);
  }
  .hh-comfort-set .foot-payments__secured svg{ width:12px; height:12px; flex-shrink:0; }
  /* The gateway's own mark sits right in the trust line - no white
     chip behind it like the payment-method badges above, so it reads
     as part of the sentence (blending straight onto the panel) rather
     than as another payment option alongside VISA/Mastercard/EFT. */
  .hh-comfort-set .foot-payments__secured-logo{
    height:14px; width:auto; display:block; flex-shrink:0;
  }
  @media (max-width: 560px){
    /* Both rows step down a size on mobile - at the full desktop sizing
       the 38px icon circles read noticeably heavier/bulkier than the
       30px-tall payment chips beside them once everything's squeezed
       into a single narrow column, throwing the two groups out of visual
       balance with each other and with the small fine-print text around
       them. Sized down together here so the whole row reads as one
       calm, evenly-weighted unit on a phone screen. */
    .hh-comfort-set .foot-social__icons{ gap:8px; }
    .hh-comfort-set .foot-social__icon{ width:32px; height:32px; }
    .hh-comfort-set .foot-social__icon svg{ width:14px; height:14px; }
    .hh-comfort-set .foot-payments__badges{ gap:6px; }
    .hh-comfort-set .pay-badge{ width:40px; height:26px; }
    .hh-comfort-set .pay-badge--visa{ font-size:11px; }
    .hh-comfort-set .pay-badge--mastercard span{ width:14px; height:14px; }
    .hh-comfort-set .pay-badge--mastercard span:first-child{ margin-right:-5px; }
    .hh-comfort-set .pay-badge--eft svg{ width:12px; height:12px; }
    .hh-comfort-set .pay-badge--eft span{ font-size:7px; }
  }
  /* Follow Us and We Accept sit on ONE shared row, pinned to the left and
     right page edges respectively (matching desktop) - at the mobile
     icon/badge sizing above, both groups' combined width plus their gap
     fits comfortably from ~360px viewports upward. Only below that (a
     small minority of real phones, e.g. a 320px-wide older device) is
     there genuinely not enough room for both on one line - there, and
     only there, they stack into two rows, each still hugging its own
     edge rather than centring, so the two groups never appear staggered
     at different heights relative to each other on any width that can
     fit them side by side. */
  @media (max-width: 359px){
    .hh-comfort-set .foot-connect{ flex-direction:column; }
    .hh-comfort-set .foot-payments{ align-self:flex-end; }
  }

  /* Legal fine print - sits right under the copyright row and above the
     platform-credit lines below, so the page's actual legal boilerplate
     groups with the copyright notice rather than getting mixed in with
     the "powered by" attribution beneath it. Trimmed to a single-line
     disclaimer plus pointers - fitment, safety/airbag, and material-care
     detail all now live in full in Terms of Service / Refund Policy, so
     the footer only needs to flag the trademark disclaimer (it has no
     other home) and send people to those policies rather than restate
     them here. Small type is intentional, but kept a touch above the
     platform-credit line below so it stays legible. */
  .hh-comfort-set .foot-fineprint{
    margin-top:16px;
    font-size:10px; line-height:1.6; color:var(--text-faint);
    max-width:860px;
  }
  .hh-comfort-set .foot-fineprint a{
    color:var(--text-faint); text-decoration:underline; text-underline-offset:2px;
    transition:color 0.2s ease;
  }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .foot-fineprint a:hover{ color:var(--brass-bright); }
  }

  /* Very last thing on the page - two small, quiet attribution lines
     beneath the copyright row: the platform the store runs on, and who
     built this particular page. Deliberately understated (faint colour,
     small type) so it reads as honest fine print rather than another
     promotional badge competing with the page's own content above it. */
  .hh-comfort-set .foot-credits{
    display:flex; justify-content:space-between; flex-wrap:wrap;
    gap:8px 20px;
    margin-top:22px; padding-top:18px;
    border-top:1px solid var(--hairline);
  }
  .hh-comfort-set .foot-credits p{
    display:flex; align-items:center; gap:6px;
    margin:0; font-size:11px; color:var(--text-faint);
  }
  .hh-comfort-set .foot-credits img{ flex-shrink:0; display:block; }
  .hh-comfort-set .foot-credits__logo-shopify{ height:14px; width:auto; }
  .hh-comfort-set .foot-credits a{
    color:var(--text-faint); text-decoration:underline; text-underline-offset:2px;
    transition:color 0.2s ease;
  }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .foot-credits a:hover{ color:var(--brass-bright); }
  }
  @media (max-width: 560px){
    .hh-comfort-set .foot-credits{ justify-content:center; }
  }

  .hh-comfort-set .cart-toast{
    /* Centred, and lifted clear of the sticky cart bar (bottom:20px, ~60px
       tall) so it never hides behind it. z-index sits above the sticky bar
       (200) and above the cart drawer (300/301), so it also shows when the
       drawer is open. */
    position:fixed; left:50%; bottom:96px;
    width:max-content; max-width:min(92vw, 380px);
    background:rgba(35,38,46,0.96); border:1px solid var(--brass);
    color:var(--text); padding:12px 20px; border-radius:var(--radius-pill);
    font-size:13.5px; line-height:1.4; text-align:center;
    box-shadow:0 12px 30px rgba(0,0,0,0.45);
    transform:translateX(-50%) translateY(16px); opacity:0; pointer-events:none;
    transition:transform 0.3s cubic-bezier(0.22,1,0.36,1), opacity 0.25s ease;
    z-index:400;
  }
  .hh-comfort-set .cart-toast.show{ transform:translateX(-50%) translateY(0); opacity:1; }

  /* ---------- Scroll polish ---------- */
  html{ -webkit-overflow-scrolling:touch; }
  .hh-comfort-set .reveal{
    opacity:0; transform:translateY(18px);
    transition:opacity 0.6s ease, transform 0.4s ease, box-shadow 0.25s ease, border-color 0.25s ease, background-color 0.25s ease;
  }
  .hh-comfort-set .reveal.in-view{ opacity:1; transform:translateY(0); }
  @media (prefers-reduced-motion: reduce){
    html{ scroll-behavior:auto; }
    .hh-comfort-set .reveal{ opacity:1; transform:none; transition:none; }
    .hh-comfort-set .gallery-thumbs img{ transition:none; }
    .hh-comfort-set .gallery-main .media-layer, .hh-comfort-set .addon-media .media-layer,
    .hh-comfort-set .gallery-thumbs button, .hh-comfort-set .addon-thumbs button{ transition:none; }
    .hh-comfort-set .hh-nav, .hh-comfort-set .brand-mark,
    .hh-comfort-set .nav-links, .hh-comfort-set .nav-cta{ transition:none; }
    .hh-comfort-set .feature-cell::after{ transition:none; }
    .hh-comfort-set .cart-fab{ transition:none; }
    .hh-comfort-set .cart-fab-clearing__progress{ transition:none !important; }
    .hh-comfort-set .cart-drawer__min-notice.is-blinking{ animation:none; }
    .hh-comfort-set .cart-drawer__continue-btn{ transition:none; }
  }

  /* Scoped to real hover devices for the same reason as feature-cell below:
     on touch devices a tap can trigger (and stick) a :hover state, and taps
     shouldn't cause this effect on mobile - only scroll-position focus
     (is-inview-selected, driven by JS) should. */
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .addon-card:hover{
      transform:translateY(-4px);
      border-color:var(--brass);
      box-shadow:0 16px 32px rgba(0,0,0,0.28);
    }
  }
  /* feature-cell sits in a flush grid (1px gap + shared hairline
     background faking the dividers) - lifting one cell with translateY
     breaks that shared edge against its neighbours, so it gets an inset
     glow instead: same "selected" read, no movement, no misalignment.
     Scoped to devices with a real mouse hover - on touch devices, :hover
     can get triggered (and stuck) by a tap, and taps shouldn't cause this
     effect at all on mobile: only scroll-position focus should. */
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .feature-cell:hover{
      box-shadow:0 8px 18px rgba(0,0,0,0.16);
      z-index:1;
    }
    .hh-comfort-set .feature-cell:hover::after{
      transform:translateX(-50%) scaleX(1);
      opacity:1;
    }
  }
  /* Mobile scroll-focus for these same four cards - driven purely by JS
     (is-inview-selected) based on scroll position, never by touch/tap.
     Now with gold restored for feature-cell too (it used to be kept
     gold-free deliberately, to leave that accent reserved for add-on
     cards/real desktop hover) - now that a fixed height means nothing
     here can lean on a size change to read as "in focus" any more, it
     needs a genuinely richer treatment to still feel alive: the focused
     card lifts slightly (a subtle scale rather than addon-card's
     translateY, since feature-cell sits in a flush 1px-gap grid with
     shared hairline dividers and a vertical lift would visibly detach it
     from a neighbour's edge on just one side - a small scale keeps the
     card centred over its own footprint, and any hairline-width overlap
     it causes reads as the card lifting above the surface, not
     misaligned, once it's got a real shadow and z-index backing that
     up), gains the brand's gold border and a warmer heading colour, and
     sits on the raised panel background. Every OTHER card dims via
     filter rather than opacity, specifically so it never fights the
     .reveal/.in-view machinery's own opacity (that still owns the
     original "fade up into view on first scroll" effect untouched) -
     two independent properties, so both can freely coexist without one
     silently overriding the other depending on selector order. */
  @media (max-width: 780px){
    .hh-comfort-set .addon-card.is-inview-selected{
      transform:translateY(-4px);
      border-color:var(--brass);
      box-shadow:0 16px 32px rgba(0,0,0,0.28);
    }
    .hh-comfort-set .feature-cell{
      filter:saturate(0.7) brightness(0.95);
    }
    .hh-comfort-set .feature-cell.is-inview-selected{
      filter:none;
      background:var(--panel-raised);
      border-color:var(--brass);
      transform:scale(1.03);
      box-shadow:0 16px 34px rgba(0,0,0,0.32);
      z-index:1;
    }
    .hh-comfort-set .feature-cell.is-inview-selected h3{
      color:var(--brass-bright);
    }
    /* Caret removed on mobile entirely, on request - the short bottom
       bar was designed for a mouse-driven hover handoff between cards
       and reads as a stray line on a touch scroll-focus effect. Its
       .feature-cell::after base rule stays fully in place for desktop;
       this is the one override that turns it off, purely for this
       breakpoint. */
    .hh-comfort-set .feature-cell::after{ display:none; }
    /* Per-card icon fills the empty space a collapsed (non-focused) card
       is left with once its description is hidden - large and left
       unboxed on purpose (no badge/chip background or border) so it
       reads as a big, loose watermark-like shape sitting in that blank
       area rather than a small contained UI control; each one keeps the
       spec-sheet trigger's stroke style (currentColor, round caps/joins)
       so the linework itself still matches the rest of the page even
       though nothing encloses it here. Vertically centred on the card
       rather than pinned to the heading's own line, since at this size
       sitting level with the (short, top-aligned) heading would crowd
       it - centring uses the full height a fixed-height card reserves
       for its hidden description instead.
       Shown ONLY while its card is NOT the focused one - the focused
       card shows its real description in that space instead, so the two
       never compete for the same room. Uses the accessible
       opacity+visibility crossfade pattern already used elsewhere on
       this page (delayed visibility on the way out, so it leaves the
       accessibility tree only once actually invisible; none on the way
       in, so the icon on a newly-unfocused card is immediately present)
       rather than display:none, purely so the fade itself stays
       animatable. */
    .hh-comfort-set .feature-cell__icon{
      display:flex; align-items:center; justify-content:center;
      position:absolute; top:50%; right:14px;
      transform:translateY(-50%);
      width:68px; height:68px;
      color:var(--text-dim);
      opacity:1; visibility:visible;
      transition:color 0.6s ease, opacity 0.55s ease, visibility 0s linear 0s;
    }
    .hh-comfort-set .feature-cell__icon svg{
      width:100%; height:100%; display:block;
    }
    .hh-comfort-set .feature-cell.is-inview-selected .feature-cell__icon{
      opacity:0; visibility:hidden;
      transition:color 0.6s ease, opacity 0.5s ease, visibility 0s linear 0.5s;
    }
  }
  /* Deliberately its own transition (rather than relying on .reveal's
     0.25s), on a selector specific enough to always win regardless of
     source order: a slower duration and a gentle ease-in-out curve make
     the mobile focus swap read as a soft settle rather than a snap.
     filter added alongside the properties this already covered, for the
     new dim/undim treatment above. opacity stays at its original 0.6s -
     that one's the one-time fade-up when a card first scrolls into view
     (the sitewide .reveal/.in-view effect), not part of the focus
     handoff between cards, so it wasn't part of what read as too quick.
     Everything else here IS part of that handoff (how a card visually
     steps forward/back as focus moves between the four), so those are
     slowed down together, on request, so cards read as easing between
     states rather than swapping. */
  .hh-comfort-set .feature-cell.reveal{
    transition:
      opacity 0.6s ease,
      transform 0.75s cubic-bezier(0.4,0,0.2,1),
      box-shadow 0.85s cubic-bezier(0.4,0,0.2,1),
      background-color 0.85s cubic-bezier(0.4,0,0.2,1),
      border-color 0.85s cubic-bezier(0.4,0,0.2,1),
      filter 0.75s ease;
  }

  /* ---------- STICKY BOTTOM CART BAR ---------- */
  .hh-comfort-set .sticky-cart-bar{
    position:fixed;
    bottom:20px;
    left:50%;
    transform:translateX(-50%) translateY(130%);
    /* Widened back out from an earlier min(61.3%, 307px): now that the
       prices inside are smaller and no longer use an inflated superscript,
       the pill has room to hold both totals plus the View Cart button
       comfortably instead of crowding them. Still centred via left:50% +
       translateX(-50%) regardless of width, and still narrower than the
       original min(92%, 460px) - the shape (a full pill) is unchanged,
       only the size. */
    width:min(70%, 350px);
    /* Semi-transparent instead of solid so backdrop-filter has something to
       blur through - whatever's scrolling underneath the whole pill (not
       just showing through gaps) reads as softly frosted glass, same
       treatment as the sticky header above. */
    background:rgba(35,38,46,0.82);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border:1px solid var(--brass);
    /* Full pill, matching the shape of the "Add to Cart" button below
       rather than a rounded rectangle. */
    border-radius:var(--radius-pill);
    /* Same problem as the header shadow above: a single rgba(0,0,0,0.42)
       layer against this near-black palette measured at only ~8-10 per
       channel difference from the page behind it - present but practically
       invisible. Split into a tighter contact shadow plus a wider, more
       opaque ambient one (verified via rendered pixel-diff to land around
       ~25-29 per channel now) so the pill visibly lifts off the page
       instead of just implying it does. */
    box-shadow:
      0 10px 18px rgba(0,0,0,0.6),
      0 22px 44px rgba(0,0,0,0.5);
    z-index:200;
    opacity:0;
    transition:transform 0.35s cubic-bezier(0.22,1,0.36,1), opacity 0.35s ease;
  }
  .hh-comfort-set .sticky-cart-bar.is-visible{
    transform:translateX(-50%) translateY(0);
    opacity:1;
  }
  /* Small "clear cart" bin, attached to the pill's true left edge,
     vertically centred on it. left is negative so most of the circle
     still overlaps/sits on the pill (reads as "attached" rather than
     floating separate from it) while a small rim pokes out past the true
     edge (reads as a badge rather than being swallowed flush inside it) -
     same rule at every width, only the pill's own width differs (see the
     480px query below). Muted/neutral by default so it doesn't read as an
     alarming red button sitting on the page at rest - only turns
     warning-red on hover/focus, or once armed (see .is-confirming below).
     Requires two taps to actually clear - a deliberate "are you sure" step
     (the first tap only arms it, see armStickyCartClear in the script),
     kept even though the bar's own cleared/undo panel afterwards is a
     second safety net of its own - the two together make clearing the
     cart by accident about as hard as it reasonably can be without a
     blocking native confirm() dialog. Hidden entirely via JS
     (updateCartCountBadge) whenever the cart is already empty - clearing
     nothing isn't a useful action to offer. */
  .hh-comfort-set .sticky-cart-bar__clear{
    position:absolute; top:50%; left:-11px;
    transform:translateY(-50%);
    width:26px; height:26px; border-radius:50%;
    background:var(--panel-raised); border:1px solid var(--hairline);
    color:var(--text-faint); padding:0;
    display:flex; align-items:center; justify-content:center;
    cursor:pointer;
    transition:background 0.15s ease, color 0.15s ease, border-color 0.15s ease, transform 0.12s ease;
  }
  .hh-comfort-set .sticky-cart-bar__clear.is-pressed{ transform:translateY(-50%) scale(0.88); }
  .hh-comfort-set .sticky-cart-bar__clear svg{ width:13px; height:13px; display:block; }
  .hh-comfort-set .sticky-cart-bar__clear:focus-visible{
    background:#3A2426; color:#E08585; border-color:#8A4A4A;
  }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .sticky-cart-bar__clear:hover{
      background:#3A2426; color:#E08585; border-color:#8A4A4A;
    }
  }
  .hh-comfort-set .sticky-cart-bar__clear:disabled{ opacity:0.6; cursor:default; }
  /* Armed state after the first tap - a soft pulsing ring is the visual
     cue that a second tap will now actually clear the cart. */
  .hh-comfort-set .sticky-cart-bar__clear.is-confirming{
    background:#3A2426; color:#E08585; border-color:#E08585;
    animation: hh-clear-pulse 0.9s ease-in-out infinite;
  }
  @keyframes hh-clear-pulse{
    0%, 100% { box-shadow:0 0 0 0 rgba(224,133,133,0.45); }
    50% { box-shadow:0 0 0 5px rgba(224,133,133,0); }
  }
  /* Names what the bin does at rest (hover/focus only, CSS-driven), then
     doubles as a live status label once tapped - "Tap again to clear"
     while armed, then a brief "Clearing…" the instant the second tap
     lands - forced visible via .is-armed at those two points regardless
     of hover/focus (see armStickyCartClear/confirmStickyCartClear in the
     script), since a touch has no hover state to reveal it with. No
     pointer/caret (deliberately not visually fused to the icon), centred
     over the bin's own left-edge position so it still reads as clearly
     "belonging" to it without touching it. */
  .hh-comfort-set .sticky-cart-bar__clear-tip{
    position:absolute; bottom:calc(100% + 12px); left:2px;
    transform:translateX(-50%) translateY(6px) scale(0.96);
    background:#2B2E35; color:var(--text-dim);
    border:1px solid var(--hairline);
    font-family:'Manrope', sans-serif; font-size:11.5px; font-weight:500;
    line-height:1.3; letter-spacing:0.01em;
    padding:8px 12px; border-radius:8px;
    white-space:nowrap;
    box-shadow:0 10px 24px rgba(0,0,0,0.45);
    opacity:0; pointer-events:none;
    transition:opacity 0.2s ease, transform 0.2s ease;
    z-index:1;
  }
  .hh-comfort-set .sticky-cart-bar__clear:focus-visible + .sticky-cart-bar__clear-tip,
  .hh-comfort-set .sticky-cart-bar__clear-tip.is-armed{
    opacity:1; transform:translateX(-50%) translateY(0) scale(1);
  }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .sticky-cart-bar__clear:hover + .sticky-cart-bar__clear-tip{
      opacity:1; transform:translateX(-50%) translateY(0) scale(1);
    }
  }
  .hh-comfort-set .sticky-cart-bar__inner{
    /* Was justify-content:space-between, which spread all four children
       (info, +, other-wrap, actions) evenly across the full width - that
       pulled "Other items" right up against the View Cart button since
       they're neighbours. Grouping the price info on the left (default
       flex-start + gap) and pushing only the actions/button group to the
       far right via margin-left:auto opens up real breathing room between
       the "Other items" figure and the button. */
    display:flex; align-items:center;
    /* Left padding bumped up beyond the other 3 sides (20px) - the bin now
       sits on this edge, overlapping in from it (see
       .sticky-cart-bar__clear above), so the "Comfort Set xN" text needs
       the extra clearance to not visually collide with it. */
    padding:13px 20px 13px 36px; gap:12px;
    flex-wrap:wrap;
  }
  /* Wraps the price/info group (everything except the View Cart button) in
     a real button so tapping/clicking that text jumps the page to the
     Comfort Set section - a plain reset (no border/background of its own)
     so it stays visually identical to the old plain <div> it replaces,
     with the same internal gap the parent used to provide directly. */
  .hh-comfort-set .sticky-cart-bar__scroll-target{
    display:flex; align-items:center; gap:12px;
    background:none; border:none; padding:0; margin:0;
    font:inherit; color:inherit; text-align:left;
    cursor:pointer; min-width:0;
  }
  .hh-comfort-set .sticky-cart-bar__info{ display:flex; flex-direction:column; line-height:1.3; }
  /* Grey label text (the "Comfort Set ×N" count and the "Other items"
     label below) is deliberately much smaller than the prices next to it -
     it's context, not the figure the eye should land on. */
  .hh-comfort-set .sticky-cart-bar__count{ font-size:9.5px; color:var(--text-faint); white-space:nowrap; }
  /* Prices inside the sticky panel only are set smaller than their
     page-wide counterparts (14px / 12.5px rather than 18px / 16px) - this,
     together with the decimal-point/cents rework below, is what keeps the
     pill compact instead of looking inflated. The gold Comfort Set total
     and the grey "other items" total are kept at the SAME font-size so the
     two figures read as equally-weighted amounts - only their colour
     (brass vs. dim grey) tells them apart. */
  .hh-comfort-set .sticky-cart-bar__total{
    font-family:'Libre Caslon Display', serif;
    font-size:14px; color:var(--brass-bright);
  }
  /* Separator between the Comfort Set total and the "other items" total. */
  .hh-comfort-set .sticky-cart-bar__plus{
    font-size:15px; font-weight:700; color:var(--text-faint);
    line-height:1; padding:0 1px;
  }
  .hh-comfort-set .sticky-cart-bar__other-wrap{ display:flex; flex-direction:column; align-items:center; line-height:1.3; }
  .hh-comfort-set .sticky-cart-bar__other-label{ font-size:9.5px; color:var(--text-faint); white-space:nowrap; }
  .hh-comfort-set .sticky-cart-bar__other{
    font-family:'Libre Caslon Display', serif;
    font-size:14px; color:var(--text-dim);
  }
  .hh-comfort-set .sticky-cart-bar__actions{ display:flex; align-items:center; gap:10px; flex-shrink:0; margin-left:auto; }
  .hh-comfort-set .sticky-cart-bar__add-btn{
    background:var(--brass); color:#151318;
    border:none; border-radius:var(--radius-pill);
    padding:8px 12px; font-size:12px; font-weight:700;
    cursor:pointer; white-space:nowrap;
    transition:background 0.15s ease, transform 0.12s ease;
  }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .sticky-cart-bar__add-btn:hover{ background:var(--brass-bright); }
  }
  .hh-comfort-set .sticky-cart-bar__add-btn:disabled{ opacity:0.65; cursor:default; }
  /* Pending-clear/undo state - the second tap on the bin doesn't clear the
     cart right away; it swaps the bar's usual price/View-Cart content for
     this panel instead (toggled via .is-pending-clear on the bar) and only
     actually calls /cart/clear.js once the countdown below finishes -
     tapping Undo before then cancels it outright, so nothing was ever
     removed and there's nothing to restore. See commitPendingClear/
     cancelPendingClear in the script. The bin and its tooltip are hidden
     for the duration too (see further down) - the cart genuinely still has
     its items until the countdown ends, so there's nothing for the bin to
     do meanwhile. */
  .hh-comfort-set .sticky-cart-bar__cleared{
    display:none; align-items:center; justify-content:space-between;
    padding:13px 20px 13px 36px; gap:12px;
  }
  .hh-comfort-set .sticky-cart-bar.is-pending-clear .sticky-cart-bar__inner{ display:none; }
  .hh-comfort-set .sticky-cart-bar.is-pending-clear .sticky-cart-bar__clear,
  .hh-comfort-set .sticky-cart-bar.is-pending-clear .sticky-cart-bar__clear-tip{
    display:none;
  }
  .hh-comfort-set .sticky-cart-bar.is-pending-clear .sticky-cart-bar__cleared{ display:flex; }
  .hh-comfort-set .sticky-cart-bar__cleared-text{
    font-size:12.5px; font-weight:600; color:var(--text-dim);
    letter-spacing:0.01em;
  }
  /* Wraps just the Undo button so the countdown strip below can be
     positioned relative to it alone, on the opposite side of the bar from
     the bin - a finger that just tapped the bin (far left) is nowhere near
     it, so lifting away never blocks the one visual actually showing how
     much time is left. */
  .hh-comfort-set .sticky-cart-bar__undo-wrap{ position:relative; flex-shrink:0; }
  .hh-comfort-set .sticky-cart-bar__undo-btn{
    background:none; border:1px solid var(--brass);
    border-radius:var(--radius-pill);
    color:var(--brass-bright); padding:7px 14px;
    font-size:12px; font-weight:700;
    cursor:pointer; white-space:nowrap;
    transition:background 0.15s ease, color 0.15s ease, transform 0.12s ease;
  }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .sticky-cart-bar__undo-btn:hover{ background:var(--brass); color:#15171C; }
  }
  /* The countdown "loader" - a thin bar that depletes from full width down
     to nothing over the exact undo window, so the shopper can see at a
     glance how long they have left without needing an exact number. JS
     (showPendingClear) sets its transition-duration to match
     STICKY_CART_UNDO_MS and flips the transform from scaleX(1) to
     scaleX(0); transform (not width) so the browser can animate it purely
     on the compositor rather than re-laying-out every frame. */
  .hh-comfort-set .sticky-cart-bar__undo-progress{
    position:absolute; left:0; right:0; bottom:-6px;
    height:3px; border-radius:999px;
    background:var(--brass-bright);
    transform-origin:left center;
    transform:scaleX(1);
  }
  /* The full pill used to also appear on mobile (auto-expanding once the
     shopper scrolled past the main product, auto-collapsing to a small
     icon near it) - now desktop-only. On mobile it's one floating shape
     too many next to the buy-box's own controls and the cart-fab below;
     the fab alone (with its own live total - see .cart-fab) is the sole
     mobile cart affordance now, so this never shows there regardless of
     scroll position or the is-visible/is-collapsed classes the script
     still (harmlessly) tracks for its own bookkeeping. */
  @media (max-width: 780px){
    .hh-comfort-set .sticky-cart-bar{ display:none !important; }
  }
  /* The floating mobile cart icon - the ONLY mobile cart affordance once
     the shopper scrolls past the main product (its own Add to Cart/View
     Cart controls are redundant with this while still in view - see
     applyStickyBarAutoState in the script). A single tap always opens the
     cart drawer directly (no "tap to expand / hold to open" distinction).
     Two shapes, same element/listeners throughout (only CSS changes -
     applyStickyBarAutoState just toggles .is-visible exactly as before):
     resting/default is a compact "docked" half-pill flush against the
     screen's right edge (rounded only on its inner side, so it reads as a
     semi-circle tab poking in from off-screen) - shown whenever the fab
     isn't the full expanded pill, i.e. it no longer disappears entirely
     the way it used to; .is-visible (once scrolled past the buy-box)
     expands it into the full pill with the live total, pulled in from the
     edge to its usual comfortable tap position. */
  .hh-comfort-set .cart-fab{
    position:fixed; bottom:20px; right:0;
    display:flex; align-items:center; justify-content:flex-start; gap:0;
    width:42px; height:52px; padding:0 0 0 13px;
    border-radius:999px 0 0 999px;
    background:var(--brass); color:#151318;
    border:none;
    box-shadow:-3px 6px 18px rgba(0,0,0,0.35);
    cursor:pointer; z-index:200;
    opacity:1; transform:scale(1);
    pointer-events:auto;
    /* transform was missing from this list entirely - the docked/
       expanded width|padding|border-radius|right|gap tween above was
       always smooth, but the press-scale the generic button.is-pressed
       rule applies (transform:scale(0.95), see near -webkit-tap-
       highlight-color at the top of the stylesheet) had nothing to
       animate it, so it snapped in and back out instantly on every tap.
       0.4s per request - slower than the docked/expanded tween's own
       0.35s, a deliberate, unhurried squish rather than a quick flick. */
    transition:width 0.35s cubic-bezier(0.22,1,0.36,1),
      padding 0.35s cubic-bezier(0.22,1,0.36,1),
      border-radius 0.35s cubic-bezier(0.22,1,0.36,1),
      right 0.35s cubic-bezier(0.22,1,0.36,1),
      gap 0.35s cubic-bezier(0.22,1,0.36,1),
      box-shadow 0.35s ease, background 0.15s ease,
      transform 0.4s cubic-bezier(0.32,0.72,0,1);
  }
  .hh-comfort-set .cart-fab.is-visible{
    width:auto; right:20px; gap:9px;
    padding:0 20px 0 14px;
    border-radius:var(--radius-pill);
    box-shadow:0 10px 24px rgba(0,0,0,0.4);
  }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .cart-fab:hover{ background:var(--brass-bright); }
  }
  /* Docked/compact state only: the live total has no room, so it's simply
     hidden. Previously the badge's usual top-right overhang (see
     .cart-fab__badge below - spills right:-10px past the icon there) was
     pulled all the way back to right:0 here, to stay inside the button's
     narrow 42px width - but that landed the badge almost squarely on top
     of the icon instead of in its corner (measured: ~10px of the icon's
     20px height sat directly under the badge), obscuring it rather than
     just tagging its corner. Fixed by measuring the actual clearance: the
     icon sits at the button's own right:0 edge with only ~9px of padding
     beyond it before the button (and the screen) truly end, so right:-7px
     spills the badge outward almost as far as the expanded state's -10px
     while staying a couple of px inside that edge (verified via bounding-
     box - no clipping). top:-9px matches the expanded state exactly (there
     was always plenty of headroom for it here). The expanded .is-visible
     state below is completely untouched. */
  .hh-comfort-set .cart-fab:not(.is-visible) .cart-fab__total{
    display:none;
  }
  .hh-comfort-set .cart-fab:not(.is-visible) .cart-fab__badge{
    top:-9px; right:-7px;
  }
  /* Long-press-to-clear, step 1 of 2 - a warm red wash fills in gradually
     WHILE held (JS sets this rule's transition-duration to match
     FAB_HOLD_MS exactly, the same "set transition then flip the target"
     trick startUndoProgress uses below for its countdown strip), so the
     colour change itself is the "keep holding" cue. Released early, it
     snaps back fast via the base rule's own 0.15s background transition
     instead (JS clears its inline override at the same moment) - only a
     completed hold ever reaches full red and starts the actual clear. */
  .hh-comfort-set .cart-fab.is-holding{ background:#8A4A4A; }
  /* Step 2 of 2 - the hold completed, so the fab itself steps out of the
     way (opacity only, not display:none - keeps its layout box, and a
     scroll-driven is-visible toggle mid-countdown can't un-hide it under
     .cart-fab-clearing) while that panel takes over the same fixed corner. */
  .hh-comfort-set .cart-fab.is-pending-clear{ opacity:0; pointer-events:none; }
  .hh-comfort-set .cart-fab__icon-wrap{
    position:relative; display:flex; align-items:center; justify-content:center;
    flex-shrink:0;
  }
  .hh-comfort-set .cart-fab svg{ width:20px; height:20px; display:block; }
  .hh-comfort-set .cart-fab__total{
    font-family:'Libre Caslon Display', serif;
    font-size:15px; font-weight:700; white-space:nowrap;
  }
  .hh-comfort-set .cart-fab__badge{
    position:absolute; top:-9px; right:-10px;
    min-width:17px; height:17px; padding:0 4px;
    border-radius:999px;
    background:var(--panel-raised); color:var(--brass-bright);
    border:1px solid var(--brass);
    font-size:10px; font-weight:700;
    display:flex; align-items:center; justify-content:center;
    line-height:1;
  }
  @media (min-width: 781px){
    /* Mobile-only affordance - the desktop sticky bar (above) is always
       shown there instead, so the fab never needs to appear on desktop. */
    .hh-comfort-set .cart-fab{ display:none; }
  }
  /* Long-press-to-clear result panel - sits in the exact same fixed
     bottom-right spot as the fab and swaps in for it the instant a
     long-press completes (see .cart-fab.is-pending-clear above and
     hhFabHoldTimer/startFabPendingClear in the script). Mirrors the
     desktop sticky-bar's own "Clearing... + Undo + depleting countdown
     strip" language (.sticky-cart-bar__cleared/undo-progress) rather than
     inventing a different pattern, just re-shaped to fit a small pill
     instead of a full-width bar - the strip sits inside the pill's own
     rounded bottom edge (clipped by overflow:hidden) since there's no
     bar underneath it to sit below the way the desktop version does. */
  .hh-comfort-set .cart-fab-clearing{
    position:fixed; bottom:20px; right:20px;
    display:none; align-items:center; gap:10px;
    height:52px; padding:0 14px 0 18px;
    border-radius:var(--radius-pill);
    background:var(--panel-raised); border:1px solid var(--brass);
    box-shadow:0 10px 24px rgba(0,0,0,0.4);
    z-index:200; overflow:hidden;
  }
  .hh-comfort-set .cart-fab-clearing.is-visible{ display:flex; }
  .hh-comfort-set .cart-fab-clearing__text{
    font-size:12.5px; font-weight:600; color:var(--text-dim);
    letter-spacing:0.01em; white-space:nowrap;
  }
  .hh-comfort-set .cart-fab-clearing__undo{
    background:none; border:1px solid var(--brass);
    border-radius:var(--radius-pill);
    color:var(--brass-bright); padding:7px 14px;
    font-size:12px; font-weight:700;
    cursor:pointer; white-space:nowrap;
    transition:background 0.15s ease, color 0.15s ease, transform 0.12s ease;
  }
  .hh-comfort-set .cart-fab-clearing__progress{
    position:absolute; left:0; right:0; bottom:0;
    height:3px; background:var(--brass-bright);
    transform-origin:left center; transform:scaleX(1);
  }
  /* The "…" after "Clearing cart" is three separate dots (aria-hidden -
     the announced text is just "Clearing cart", the dots are decoration
     only) rather than one static ellipsis character, so each can pulse
     on its own delay. The look is meant to read as caution rather than
     as an ordinary loading spinner, since there's a live Undo button
     sitting right beside it: each dot glows into --brass-bright (the
     same amber already used for this page's other alerts/highlights,
     not a new colour) and shrinks down small as it glows, as if it's
     being "used up" - echoing the countdown-bar language elsewhere in
     this file - then resets. The three dots are staggered 0.2s apart so
     the glow visibly ripples left to right on a loop, rather than all
     three pulsing in unison, which read more like a generic spinner in
     testing. */
  .hh-comfort-set .cart-fab-clearing__dots{
    display:inline-flex; align-items:center; gap:3px;
    margin-left:3px; vertical-align:-1px;
  }
  .hh-comfort-set .cart-fab-clearing__dot{
    width:4px; height:4px; border-radius:50%;
    background:var(--text-dim);
    animation:hh-clearing-dot-caution 1.4s ease-in-out infinite;
  }
  .hh-comfort-set .cart-fab-clearing__dot:nth-child(1){ animation-delay:0s; }
  .hh-comfort-set .cart-fab-clearing__dot:nth-child(2){ animation-delay:0.2s; }
  .hh-comfort-set .cart-fab-clearing__dot:nth-child(3){ animation-delay:0.4s; }
  @keyframes hh-clearing-dot-caution{
    0%, 100%{
      background:var(--text-dim);
      box-shadow:0 0 0 0 rgba(211,166,103,0);
      transform:scale(1);
    }
    35%{
      background:var(--brass-bright);
      box-shadow:0 0 5px 1px rgba(211,166,103,0.65);
      transform:scale(0.5);
    }
    65%{
      background:var(--brass-bright);
      box-shadow:0 0 2px 0 rgba(211,166,103,0.3);
      transform:scale(1);
    }
  }
  @media (prefers-reduced-motion: reduce){
    /* Static amber dots still carry the "caution" colour cue without
       any motion - not just frozen mid-pulse at some arbitrary frame. */
    .hh-comfort-set .cart-fab-clearing__dot{
      animation:none; background:var(--brass-bright);
    }
  }
  @media (min-width: 781px){
    .hh-comfort-set .cart-fab-clearing{ display:none !important; }
  }

  /* ---------- SLIDE-OUT CART DRAWER ---------- */
  .hh-comfort-set .cart-drawer-overlay{
    position:fixed; inset:0;
    background:rgba(10,11,14,0.6);
    z-index:300;
    opacity:0; pointer-events:none;
    transition:opacity 0.45s cubic-bezier(0.32,0.72,0,1);
    /* This backdrop has no scrollable content of its own - it only ever
       sits on top of the real page. touch-action:none stops a touch drag
       here from being read as a page-scroll gesture at all (see the
       matching wheel/touchmove listeners in openCartDrawer/closeCartDrawer's
       section of the script for the desktop-wheel/older-browser backstop) -
       replaces the old lockBodyScroll/unlockBodyScroll freeze-and-restore
       technique, which is what used to snap the shopper back to the top of
       the page on close (see that comment block in the script for why it
       was removed rather than patched again - the reviews-photo overlay
       had the exact same bug from the exact same kind of mechanism). */
    touch-action:none;
  }
  .hh-comfort-set .cart-drawer-overlay.is-open{ opacity:1; pointer-events:auto; }

  .hh-comfort-set .cart-drawer{
    position:fixed; top:0; right:0;
    height:100vh; height:100dvh;
    width:min(92%, 420px);
    background:var(--panel-raised);
    border-left:1px solid var(--hairline);
    box-shadow:-16px 0 40px rgba(0,0,0,0.4);
    z-index:301;
    display:flex; flex-direction:column;
    transform:translateX(100%);
    opacity:0;
    transition:transform 0.5s cubic-bezier(0.32,0.72,0,1), opacity 0.4s ease;
    will-change:transform;
    /* Same reasoning as the overlay above, for the drawer panel's own
       non-scrolling regions (header, continue button, assurance line,
       footer/checkout) - only .cart-drawer__items below actually needs to
       scroll, and it explicitly opts back into vertical panning. */
    touch-action:none;
  }
  .hh-comfort-set .cart-drawer.is-open{ transform:translateX(0); opacity:1; }

  .hh-comfort-set .cart-drawer__header{
    display:flex; align-items:center; justify-content:space-between;
    padding:22px 24px; border-bottom:1px solid var(--hairline);
    flex-shrink:0;
  }
  .hh-comfort-set .cart-drawer__header h3{ font-size:20px; }
  .hh-comfort-set .cart-drawer__close{
    background:none; border:none; color:var(--text-dim);
    font-size:26px; line-height:1; cursor:pointer; padding:4px 6px;
  }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .cart-drawer__close:hover{ color:var(--text); }
  }

  .hh-comfort-set .cart-drawer__items{
    flex:1; overflow-y:auto; padding:8px 24px;
    /* Opts back into vertical panning against the drawer panel's own
       touch-action:none above - this is the one region inside the drawer
       that's actually meant to scroll. overscroll-behavior:contain stops
       a swipe that reaches the top/bottom of this list from "spilling
       over" into scrolling the page behind the drawer once the list
       itself runs out of room to move (the classic iOS rubber-band
       scroll-chaining behaviour) - without it, touch-action alone still
       leaves that one edge case open. */
    touch-action:pan-y; overscroll-behavior:contain;
  }
  .hh-comfort-set .cart-drawer__empty{ color:var(--text-dim); font-size:14px; padding:24px 0; }

  .hh-comfort-set .cart-drawer__item{
    display:flex; align-items:center; gap:12px;
    padding:14px 0; border-bottom:1px solid var(--hairline);
    max-height:260px; overflow:hidden;
    transition:max-height 0.32s cubic-bezier(0.32,0.72,0,1), opacity 0.28s ease,
      padding 0.32s ease, border-color 0.32s ease;
  }
  .hh-comfort-set .cart-drawer__item:last-child{ border-bottom:none; }
  .hh-comfort-set .cart-drawer__item.is-removing{
    max-height:0; opacity:0; padding-top:0; padding-bottom:0; border-color:transparent;
  }
  /* One fixed size for every row's picture, full stop - no per-line
     overrides, so every product in the cart (however it got there) lines
     up on the same grid. */
  .hh-comfort-set .cart-drawer__item-media{
    position:relative;
    width:64px; height:64px; min-width:64px; border-radius:3px;
    background:#0F1115; border:1px solid var(--hairline);
  }
  /* border-radius now lives directly on the <img> rather than clipped via
     the container's own overflow:hidden - the flagship badge below is a
     sibling absolutely positioned on this container and deliberately
     protrudes slightly past its corner, which overflow:hidden here would
     have clipped straight off. */
  .hh-comfort-set .cart-drawer__item-media img{
    width:100%; height:100%; object-fit:cover; border-radius:3px; display:block;
  }
  /* Marks the Comfort Set specifically as the flagship product whenever it
     sits in the cart alongside the two accessories - a small crown badge
     pinned to the thumbnail's top-right corner, overhanging it by a few
     px the same way the other small corner badges on this page do (see
     .view-cart-btn__badge/.cart-fab__badge), rather than any text, so it
     reads at a glance without competing with the item title/price next to
     it. Applied in renderCartDrawerItems by comparing each line's variant
     id against VARIANTS.main.id - never hardcoded to a title string, so
     it still tracks correctly if the product is ever renamed. */
  .hh-comfort-set .cart-drawer__flagship-badge{
    position:absolute; top:-4px; right:-4px;
    width:18px; height:18px; border-radius:50%;
    background:var(--brass); color:#151318;
    display:flex; align-items:center; justify-content:center;
    box-shadow:0 1px 4px rgba(0,0,0,0.5);
  }
  .hh-comfort-set .cart-drawer__flagship-badge svg{ width:11px; height:11px; display:block; }
  .hh-comfort-set .cart-drawer__item-info{ display:flex; flex-direction:column; gap:9px; flex:1; min-width:0; }
  /* Back up to its original 13px (readable, matches .cart-drawer__item-price
     alongside it) now that there's room for it: still allowed to wrap onto
     a second line and capped there via line-clamp, and the picture beside
     it was grown a touch (62px -> 64px) alongside this so that even a
     worst-case two-line title, plus the gap, plus the controls row below,
     still fits inside the picture's height without pushing the stepper/bin
     icons past its bottom edge. In practice most of these labels sit on
     one line, which just means extra breathing room rather than a tight
     fit. */
  .hh-comfort-set .cart-drawer__item-title{
    font-size:13px; line-height:1.25; color:var(--text);
    display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical;
    overflow:hidden;
  }
  .hh-comfort-set .cart-drawer__item-controls{ display:flex; align-items:center; gap:10px; }
  .hh-comfort-set .cart-drawer__stepper{
    display:flex; align-items:center;
    border:1px solid var(--hairline); border-radius:var(--radius-pill);
  }
  .hh-comfort-set .cart-drawer__stepper-btn{
    background:none; border:none; color:var(--text);
    width:19px; height:19px; font-size:12px; line-height:1;
    display:flex; align-items:center; justify-content:center; cursor:pointer;
  }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .cart-drawer__stepper-btn:hover{ color:var(--brass-bright); }
  }
  .hh-comfort-set .cart-drawer__stepper-qty{ min-width:13px; text-align:center; font-size:11px; }
  .hh-comfort-set .cart-drawer__remove-btn{
    background:none; border:none; color:var(--text-faint);
    padding:2px; display:flex; align-items:center; justify-content:center;
    cursor:pointer; transition:color 0.15s ease;
  }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .cart-drawer__remove-btn:hover{ color:#E08585; }
  }
  .hh-comfort-set .cart-drawer__remove-btn svg{ width:14px; height:14px; display:block; }
  .hh-comfort-set .cart-drawer__item-price{ font-size:13px; color:var(--brass-bright); white-space:nowrap; }
  .hh-comfort-set .cart-drawer__item-price--discounted{
    display:flex; flex-direction:column; align-items:flex-end; gap:2px;
  }
  .hh-comfort-set .cart-drawer__item-price-original{
    font-size:11px; color:var(--text-dim); text-decoration:line-through; white-space:nowrap;
  }
  .hh-comfort-set .cart-drawer__item-price-final{
    font-size:13px; color:var(--brass-bright); white-space:nowrap;
  }
  .hh-comfort-set .cart-drawer__item-discount-badge{
    font-size:10.5px; font-weight:700; color:#151318; background:var(--brass-bright);
    padding:1px 6px; border-radius:999px; white-space:nowrap;
  }

  /* ---------- Empty-cart / cross-sell suggestions ---------- */
  /* Shown for whichever of the 3 catalog products ISN'T already sitting in
     the cart - covers both a fully empty cart (all 3 shown, replacing the
     old plain "Your cart is empty" line) and a partially-filled one (only
     the still-missing products shown, alongside the real item rows above).
     Deliberately smaller than a real cart row in every dimension (media,
     type) so it never gets mistaken for one. Pushed down by roughly one
     extra row's worth of space (rather than sitting right under the last
     real item with just its own hairline border) plus a divider of its
     own, so this reads as a clearly separate block, not another cart line. */
  /* Wider gap than a normal section break, and no dividing border - the
     extra whitespace alone is enough to read the suggestions as a distinct
     group below the real cart items, without a hard line cutting across
     the drawer (per request). */
  .hh-comfort-set .cart-drawer__suggestions{
    margin-top:28px;
  }
  .hh-comfort-set .cart-drawer__suggestions-title{
    font-size:11px; color:var(--text-faint); margin:0 0 8px;
    text-transform:uppercase; letter-spacing:0.05em;
  }
  .hh-comfort-set .cart-drawer__suggestions-row{
    display:flex; flex-wrap:wrap; gap:8px;
  }
  /* One bespoke duration/curve (0.25s, the same cubic-bezier(0.32,0.72,0,1)
     "smooth settle" used throughout this page) shared by every part of
     this tile that reacts to hover: the tile's own background, the
     media frame's border, the image's zoom, and the title's colour used
     to each run on their own separate duration/easing (0.15s/0.2s/0.25s,
     all plain "ease") - close enough to look almost simultaneous but not
     quite, which read as the tile reacting twice in quick succession
     rather than once. Landing all four on the exact same timing makes
     hovering into the thumbnail read as one single, smooth reaction. */
  .hh-comfort-set .cart-drawer__suggestion{
    display:flex; flex-direction:column; align-items:center; gap:6px;
    width:74px; background:none; border:none; padding:6px 4px;
    cursor:pointer; border-radius:6px; font-family:inherit;
    transition:background 0.25s cubic-bezier(0.32,0.72,0,1);
  }
  .hh-comfort-set .cart-drawer__suggestion:focus-visible{
    background:var(--panel-raised);
  }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .cart-drawer__suggestion:hover{
      background:var(--panel-raised);
    }
  }
  .hh-comfort-set .cart-drawer__suggestion-media{
    width:48px; height:48px; border-radius:3px; overflow:hidden;
    background:#0F1115; border:1px solid var(--hairline);
    transition:border-color 0.25s cubic-bezier(0.32,0.72,0,1);
  }
  .hh-comfort-set .cart-drawer__suggestion-media img{
    width:100%; height:100%; object-fit:cover; display:block;
    transition:transform 0.25s cubic-bezier(0.32,0.72,0,1);
  }
  .hh-comfort-set .cart-drawer__suggestion:focus-visible .cart-drawer__suggestion-media{
    border-color:var(--brass);
  }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .cart-drawer__suggestion:hover .cart-drawer__suggestion-media{
      border-color:var(--brass);
    }
  }
  .hh-comfort-set .cart-drawer__suggestion:focus-visible .cart-drawer__suggestion-media img{
    transform:scale(1.1);
  }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .cart-drawer__suggestion:hover .cart-drawer__suggestion-media img{
      transform:scale(1.1);
    }
  }
  .hh-comfort-set .cart-drawer__suggestion-title{
    font-size:10px; line-height:1.25; color:var(--text-dim);
    text-align:center; transition:color 0.25s cubic-bezier(0.32,0.72,0,1);
    /* One line only: the labels are now very short (Comfort Set / Sunshade /
       Screens x2), and this guarantees a tile can never grow tall enough to
       push the drawer into a scrollbar. */
    width:100%; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  }
  .hh-comfort-set .cart-drawer__suggestion:focus-visible .cart-drawer__suggestion-title{
    color:var(--brass-bright);
  }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .cart-drawer__suggestion:hover .cart-drawer__suggestion-title{
      color:var(--brass-bright);
    }
  }
  /* Price sits under the title, on every device (not just desktop) -
     small and dim rather than brass/bold, so it reads as supporting
     information alongside the title rather than competing with the
     drawer's real line-item prices (.cart-drawer__item-price). */
  .hh-comfort-set .cart-drawer__suggestion-price{
    font-size:10px; font-weight:700; line-height:1.25; color:var(--text-faint);
  }
  /* Briefly shown the instant a suggestion is tapped, while the add-to-cart
     request is in flight - the tile itself is about to disappear entirely
     (re-rendered away once the response comes back), this just stops a
     second impatient tap from firing a second add in the meantime. */
  .hh-comfort-set .cart-drawer__suggestion.is-adding{ opacity:0.5; pointer-events:none; }

  /* Sits directly above the grey divider that opens .cart-drawer__assurance-wrap
     just below it - a small, unobtrusive "close and keep shopping" affordance
     living right where the scrollable item list ends, so it's reachable
     without scrolling all the way down to the footer. Only shown while the
     order is still under the checkout minimum (toggled in JS alongside
     .cart-drawer__min-notice, both driven by updateCheckoutButtonState) -
     once there's enough in the cart to check out, this makes way for the
     Checkout button as the one obvious next step rather than nudging a
     ready-to-buy shopper back to browsing. Left-aligned with a door icon
     (an exit back out of the cart into the rest of the store), kept apart
     from the primary Checkout button below so the two calls-to-action read
     as clearly distinct rather than competing for the same corner. */
  .hh-comfort-set .cart-drawer__continue-wrap{
    padding:0 24px 12px; flex-shrink:0; display:flex; align-items:center; justify-content:flex-start;
  }
  .hh-comfort-set .cart-drawer__continue-btn{
    display:inline-flex; align-items:center; gap:5px;
    background:none; border:none; padding:4px 2px;
    font-family:'Manrope', sans-serif; font-size:12.5px; font-weight:600;
    letter-spacing:0.02em; color:var(--text-dim); cursor:pointer;
    transition:color 0.15s ease, gap 0.15s ease;
  }
  .hh-comfort-set .cart-drawer__continue-btn:focus-visible{
    color:var(--brass-bright); gap:8px;
  }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .cart-drawer__continue-btn:hover{
      color:var(--brass-bright); gap:8px;
    }
  }
  .hh-comfort-set .cart-drawer__continue-btn svg{ width:13px; height:13px; display:block; flex-shrink:0; }

  .hh-comfort-set .cart-drawer__footer{
    padding:20px 24px 26px; border-top:1px solid var(--hairline); flex-shrink:0;
  }
  /* Sits between the scrollable item list and the footer below it - its
     own top border is the grey divider line above the notice, and the
     footer's existing border-top (right beneath this block) is the second
     dividing line the notice sits cleanly above. */
  .hh-comfort-set .cart-drawer__assurance-wrap{
    padding:14px 24px; border-top:1px solid var(--hairline); flex-shrink:0;
  }
  .hh-comfort-set .cart-drawer__assurance{
    margin:0; font-size:12px; color:var(--brass-bright); text-align:left;
  }
  /* Shown only once the real cart actually holds 4+ units of the Comfort
     Set - the same threshold the live "Full Cabin Comfort 7% Off"
     automatic discount in Shopify Admin uses (see cartQualifiesFor
     ComfortSetDeal/updateComfortSetDealNote in the script) - hidden by
     default via the [hidden] attribute rather than display:none in CSS,
     so there's no layout to fight when JS toggles it. */
  .hh-comfort-set .cart-drawer__kit-savings{
    margin:0 0 12px; padding:10px 12px; border-radius:6px;
    background:rgba(211,166,103,0.12);
    font-size:12.5px; font-weight:700; color:var(--brass-bright);
  }
  .hh-comfort-set .cart-drawer__discount-row{
    display:flex; justify-content:space-between; align-items:baseline;
    font-size:13px; color:var(--brass-bright); margin-bottom:8px;
  }
  .hh-comfort-set .cart-drawer__subtotal{
    display:flex; justify-content:space-between; align-items:baseline;
    font-size:14px; color:var(--text-dim); margin-bottom:16px;
  }
  .hh-comfort-set .cart-drawer__subtotal span:last-child{
    font-family:'Libre Caslon Display', serif; font-size:20px; color:var(--brass-bright);
  }
  .hh-comfort-set .cart-drawer__checkout-btn{
    width:100%; background:var(--brass); color:#151318;
    border:none; padding:16px 20px; font-size:15px; font-weight:700;
    letter-spacing:0.01em; border-radius:var(--radius-pill); cursor:pointer;
    transition:background 0.15s ease, transform 0.12s ease;
  }
  @media (hover: hover) and (pointer: fine){
    .hh-comfort-set .cart-drawer__checkout-btn:hover{ background:var(--brass-bright); }
  }
  .hh-comfort-set .cart-drawer__checkout-btn:disabled{ opacity:0.5; cursor:not-allowed; }
  .hh-comfort-set .cart-drawer__min-notice{
    font-size:12.5px; color:var(--text-faint); margin:-6px 0 14px;
    display:flex; align-items:center; gap:6px;
  }
  /* Purely decorative - a small gold warning triangle in front of the
     minimum-order copy, kept as its own fixed-colour element rather than
     inheriting the text's `color` so the blink animation just below (which
     pulses that `color` on the text itself) never touches it; the text
     and its blink effect are otherwise completely untouched. */
  .hh-comfort-set .cart-drawer__min-notice-icon{
    width:13px; height:13px; flex-shrink:0; color:var(--brass-bright);
  }
  /* A quick, gentle highlight on this notice - two soft pulses toward a
     warm gold glow, then back to normal - when a tap on the (disabled)
     checkout button below tries to proceed under the minimum. Restarted
     by removing/re-adding the class in JS rather than relying on a second
     trigger of an already-finished animation. */
  .hh-comfort-set .cart-drawer__min-notice.is-blinking{
    animation: hh-min-notice-blink 0.6s ease-in-out 2;
  }
  @keyframes hh-min-notice-blink{
    0%, 100% { color:var(--text-faint); text-shadow:none; }
    50% { color:var(--brass-bright); text-shadow:0 0 8px rgba(211,166,103,0.5); }
  }
  /* Wraps the checkout button so a transparent "catcher" can sit exactly
     over it: a native disabled <button> never dispatches click/pointer
     events at all, so there'd otherwise be no way to notice a shopper
     tapping it while under the minimum. The catcher only intercepts while
     locked (see .is-locked below) - once the minimum is met it's inert,
     leaving the real button to handle its own click normally. */
  .hh-comfort-set .cart-drawer__checkout-wrap{ position:relative; }
  .hh-comfort-set .cart-drawer__checkout-catcher{
    position:absolute; inset:0;
    pointer-events:none;
  }
  .hh-comfort-set .cart-drawer__checkout-wrap.is-locked .cart-drawer__checkout-catcher{
    pointer-events:auto;
    cursor:not-allowed;
  }
  @media (max-width: 480px){
    .hh-comfort-set .cart-drawer{ width:100%; }
  }
  /* ---------- Judge.me review widget ----------
     Container for the widget Judge.me renders into
     #judgeme_product_reviews (see REVIEW CARDS in the main file). Judge.me
     injects its own markup and default light styling, so this only lines
     it up with the page: full-width inside .hh-wrap, page font, and colours
     mapped onto this theme's dark variables. Fine-tune colours for the
     widget itself in Judge.me's admin (Settings > Widgets) - anything set
     there wins over the fallbacks below where the two disagree. */
  .hh-comfort-set .hh-jdgm-widget-wrap{ max-width:1100px; margin:32px auto 0; }
  .hh-comfort-set .hh-jdgm-widget-wrap .jdgm-widget,
  .hh-comfort-set .hh-jdgm-widget-wrap .jdgm-rev-widg{
    font-family:inherit; color:var(--text);
  }
  .hh-comfort-set .hh-jdgm-widget-wrap .jdgm-rev-widg__title,
  .hh-comfort-set .hh-jdgm-widget-wrap .jdgm-rev__author,
  .hh-comfort-set .hh-jdgm-widget-wrap .jdgm-rev__title{ color:var(--text); }
  .hh-comfort-set .hh-jdgm-widget-wrap .jdgm-rev__body,
  .hh-comfort-set .hh-jdgm-widget-wrap .jdgm-rev__timestamp,
  .hh-comfort-set .hh-jdgm-widget-wrap .jdgm-rev-widg__summary-text{ color:var(--text-dim); }
  .hh-comfort-set .hh-jdgm-widget-wrap .jdgm-star{ color:var(--brass-bright); }
  .hh-comfort-set .hh-jdgm-widget-wrap .jdgm-write-rev-link,
  .hh-comfort-set .hh-jdgm-widget-wrap .jdgm-rev-widg__summary a{ color:var(--brass-bright); }
  /* Spacing + heading tidy for the Judge.me widget (checked live in the
     browser first). The section already has its own "In their own words"
     heading, so the widget's own "Customer Reviews" title is hidden to avoid
     saying it twice, and the stacked gaps (heading margin + wrapper margin +
     the widget's built-in 48px top/bottom padding + 100px section padding)
     are pulled in so the section no longer floats in empty space. Selectors
     are Judge.me's current revamp classes (.jm-*); if a future Judge.me
     update renames them these rules simply stop matching and the widget
     falls back to its own spacing - nothing breaks. */
  .hh-comfort-set section.review-cards .reviews-section-head{ margin-bottom:8px; }
  .hh-comfort-set section.review-cards{ padding-bottom:72px; }
  .hh-comfort-set .hh-jdgm-widget-wrap{ margin-top:0; }
  .hh-comfort-set .hh-jdgm-widget-wrap .jm-review-widget{ padding-top:8px; padding-bottom:0; }
  .hh-comfort-set .hh-jdgm-widget-wrap .jm-review-widget-minimal-header__title{ display:none; }
  /* Judge.me "Write a review" button restyled to match this theme's own
     primary buttons (brass fill, dark text, pill shape, bold 14px - same
     values as .add-to-cart) instead of Judge.me's slightly different gold
     with white text. Checked live in the browser first. */
  .hh-comfort-set .hh-jdgm-widget-wrap .jm-button--primary{
    background:var(--brass); border-color:var(--brass); color:#151318;
    border-radius:var(--radius-pill); font-weight:700; font-size:14px;
    padding:11px 22px; transition:background .2s ease, border-color .2s ease;
  }
  .hh-comfort-set .hh-jdgm-widget-wrap .jm-button--primary *{ color:inherit; }
  .hh-comfort-set .hh-jdgm-widget-wrap .jm-button--primary:hover{
    background:var(--brass-bright); border-color:var(--brass-bright); color:#151318;
  }
  /* Once the Judge.me widget has actually rendered (it brings its own
     "be the first to write a review" prompt and form), retire the fallback
     empty-state card so the section never says it twice. If Judge.me fails
     to load, #judgeme_product_reviews stays empty and the fallback stays visible. */
  .hh-comfort-set section.review-cards:has(#judgeme_product_reviews > *) .reviews-empty{ display:none; }
