/* =========================================================
   Y'ALLTERNATIVE LIVING — shared design system
   Goth meets Southern-alt. Leather, whiskey, moonlight,
   with a rainbow that only shows up when it means something.
   ========================================================= */

/* Fonts are loaded from Google Fonts (see the <link>s in each page <head>).
   Heading: Gloock          -- var(--font-display) / var(--font-heading)
   Body:    DM Sans         -- var(--font-body)
   Neither Cormorant Garamond nor Outfit (what this comment used to name)
   has ever been loaded by this site; don't reintroduce them as fallbacks. */

/* ---------------------------------------------------------
   THEME TOKENS
   Dark is the brand's native mode (moody, leather, moonlit);
   light is a clean daytime read (cream/paper, same accents).
   Everything color-related routes through these custom
   properties -- one attribute flip repaints the whole site.
   --------------------------------------------------------- */
:root {
  color-scheme: dark;
  /* core palette -- DARK (default) */
  --ink: #17130f; /* elevated near-black, not pure #000 */
  --ink-2: #1e1815; /* raised panel */
  --ink-3: #262019; /* card / border fill */
  --hide: #4a3a2e; /* border / rule (raised contrast) */
  --paper: #f3ead9; /* warm off-white text */
  --paper-dim: #cfc0a8; /* muted body text on dark */
  --whiskey: #d69b5c; /* amber accent */
  --whiskey-dim: #8a5c30;
  --rose: #c65a6d; /* dusty rose / wine accent (NOT for text!) */
  --rose-dim: #7d3140;
  /* --rose is a bit too close in luminance to our dark surfaces to clear
     4.5:1 as body/UI TEXT (only ~3.9-4.5:1 against ink/ink-2/ink-3) --
     --rose-text is a brightened tint reserved for that use (error text,
     link-hover, etc.) so it reads clearly against dark backgrounds. */
  --rose-text: #d17b8a;
  --sage: #7c8f6e; /* faded sage, secondary accent */
  /* The .in-stock badge in the search results tints its own background
     with rgba(92,168,108,.15), which lifts the effective backdrop to
     ~#272e22 in dark and ~#dbdfc8 in light. --sage as the label on that
     measured 4.00:1 (dark) and 4.42:1 (light) -- both under the 4.5:1 AA
     floor, and at 10.9px/600 the large-text carve-out does not apply
     (audit C, finding M6). One step of separation each way clears it
     with margin: 5.4:1 dark, 5.8:1 light. Scoped to that badge so the
     --sage accent everywhere else is untouched. */
  --sage-strong: #93a884;

  /* Semantic Tokens */
  --error: #e65c5c;
  --success: #5ca86c;
  --focus-ring: var(--whiskey);

  --shadow: 0 12px 30px -12px rgba(0, 0, 0, 0.55);
  /* Fully opaque -- a frosted/translucent header let the hero's radial
     glow bleed through and blur behind the logo, which read as a muddy
     vignette rather than a clean brand mark in some renderers. A solid
     header reads more polished and renders identically everywhere. */
  --nav-bg: rgb(23, 19, 15);
  --footer-bg: #0f0c0a; /* a touch darker than --ink for depth */
}

:root[data-theme="light"] {
  color-scheme: light;
  /* core palette -- LIGHT */
  --ink: #faf5ea; /* warm paper background */
  --ink-2: #f1e9d8; /* raised panel */
  --ink-3: #ece2cd; /* card fill */
  --hide: #c4a880; /* border / rule (raised contrast) */
  --paper: #221a14; /* near-black warm text */
  --paper-dim: #5b4d3d; /* muted body text on light */
  /* #a8631f (the original "darkened for AA contrast" amber) still fell
     short at the small text sizes .eyebrow/.card-cat actually use --
     4.3:1 vs the 4.5:1 AA floor. #93571b cleared 4.5:1 against flat --ink
     and --ink-2, but not against the amber-TINTED chip fills this file
     builds with `oklch(from var(--whiskey) l c h / <alpha>)`: tinting a
     light surface with a dark amber darkens the background, so
     .dispatch-badge (.12 tint, 4.10:1) and .concern-pill.active (.18
     tint, 4.17:1) both landed under the floor on every product card.
     Darkened to #7f4a13, which clears 4.5:1 on flat surfaces AND on the
     .10-.18 self-tints (4.6:1-5.1:1). --whiskey is only ever used in
     light mode as text on a light surface or as a fill under --ink text,
     so darkening only ever raises contrast. */
  --whiskey: #7f4a13;
  --whiskey-dim: #7a4816;
  --rose: #9c2f45; /* wine accent, darkened for contrast (NOT for text!) */
  --rose-dim: #7d3140;
  --rose-text: var(--rose); /* already >=4.5:1 as text in light mode */
  --sage: #4f6a45;
  --sage-strong: #41573a;

  /* Semantic Tokens */
  --error: #d13b3b;
  /* Same tint story as the amber above. The old #3b8248 as text on its own
     .12 tint was 3.39:1 (.receipt-status-badge on thank-you). #276030 clears
     4.7:1+ on the tints and lifts white-on-fill (.timeline-step.step-done,
     .search-add-btn.is-added) from 4.70:1 to 7.49:1.
     NB: scripts/qa-check.js parses this block with a regex that does not
     strip comments, so never write "--token: #hex" in prose here -- it is
     picked up as a real declaration and shadows the one below. */
  --success: #276030;
  --focus-ring: var(--whiskey);

  --shadow: 0 12px 26px -14px rgba(60, 40, 20, 0.28);
  --nav-bg: rgb(250, 245, 234);
  --footer-bg: #ece2cd; /* a touch deeper than --ink for depth */
}

/* Respect OS preference for first-time visitors who haven't
   toggled yet (no data-theme attribute set by JS/localStorage) */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]):not([data-theme="light"]) {
    color-scheme: light;
    --ink: #faf5ea;
    --ink-2: #f1e9d8;
    --ink-3: #ece2cd;
    --hide: #c4a880;
    --paper: #221a14;
    --paper-dim: #5b4d3d;
    --whiskey: #7f4a13;
    --whiskey-dim: #7a4816;
    --rose: #9c2f45;
    --rose-dim: #7d3140;
    --rose-text: var(--rose);
    --sage: #4f6a45;
    --sage-strong: #41573a;
    --error: #d13b3b;
    --success: #276030;
    --shadow: 0 12px 26px -14px rgba(60, 40, 20, 0.28);
    --nav-bg: rgb(250, 245, 234);
    --footer-bg: #ece2cd;
  }
}

@font-face {
  font-family: "CleanAmpersand";
  src: local("DM Sans"), local("Helvetica Neue"), local("Arial"), sans-serif;
  unicode-range: U+0026; /* Match ONLY the & character */
}

:root {
  /* Fixed (non-theme-flipping) pair for solid rose-filled buttons/badges.
     --paper flips to a DARK color in light mode (right for body text on
     the light page background, wrong for text sitting on top of a
     mid-tone rose fill) -- these two stay constant across both themes
     so button contrast doesn't collapse when the theme switches. */
  --on-fill: #f3ead9;
  --rose-fill-hover: #612631;

  --pride: linear-gradient(90deg, #e0505a, #e8935a, #e8c65a, #5fae7a, #4f8fc7, #9a6bc9);

  --font-display: "CleanAmpersand", "Gloock", "Georgia", serif;
  --font-body:
    "CleanAmpersand", "DM Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;

  --container: 1320px;
  --radius: 8px;
  --radius-lg: 16px;

  /* Compatibility aliases.
     Later feature work (the Apothecary Quiz in shop.html, plus a few rules
     further down this file) was written against these four names, but they
     were never actually defined anywhere -- 39 references in total, every one
     of them resolving to nothing. An undefined var() in a shorthand makes the
     whole declaration invalid, so `border: 1px solid var(--border-color)`
     silently fell back to a currentColor border and the radii to square
     corners. Defined here as aliases of the real tokens rather than
     find-and-replaced at each call site, so they stay theme-aware: --hide and
     --paper-dim are both re-declared per theme, and var() resolves at use
     time, so these follow dark/light automatically. */
  --border-color: var(--hide);
  --paper-muted: var(--paper-dim);
  --radius-sm: 6px;
  --radius-md: var(--radius);
  --radius-large: var(--radius-lg);
  /* --radius-xl (Build-Your-Own-Box card, Apothecary Quiz modal) and --ink-1
     (box-builder thumbnail/checkbox fills, restock modal panels) were the
     same story as the block above -- referenced but never defined, so
     border-radius silently fell back to square corners and those
     backgrounds/checkmarks fell back to transparent/inherited. Aliased here
     for the same reason. */
  --radius-xl: 24px;
  --ink-1: var(--ink);
  --bg: var(--ink);
  --crimson: var(--error);
  --font-heading: var(--font-display);
  /* Order-status timeline "step complete" green. Was only ever referenced as
     var(--moss), never declared -- two of its three uses had no fallback, so
     the active step lost its border and focus ring entirely. Value taken from
     the one call site that did carry a fallback, so nothing changes visually
     where it already worked. */
  --moss: #4a6b5d;
}

/* ---------------------------------------------------------
   Z-INDEX BANDS
   Everything in this file (and cart.css) should land in one
   of these, so a new overlay can be placed without reading
   the whole stylesheet:

     0-10    in-flow decoration (card badges, gallery dots,
             carousel arrows, lightbox chrome)
     90-99   viewport-pinned page chrome that any overlay must
             be able to cover: .pdp-sticky-bar (90), mobile
             .nav-links drawer (99)
     100-199 header band: .site-header (100),
             .announcement-bar (101), .wish-backdrop (198),
             .wish-drawer (199)
     200-999 escapes the header: .skip-link (200),
             .lang-dropdown (200)
     1000+   modal layer: dialog.global-search-modal (1000)
     9999    always-on-top: .sw-update-toast, and the cart
             drawer's non-popover fallback in cart.css

   Real <dialog>s opened with showModal() (.lightbox-modal,
   .gift-modal, the search modal) and the cart drawer's
   popover path render in the browser's top layer, above all
   of this regardless of z-index -- the values above only
   decide the fallback ordering.

   The tawk.to chat bubble is injected by a third party with
   its own very high inline z-index and sits above everything
   here; nothing in this file can reorder it.
   --------------------------------------------------------- */

/* Prevent CSS Grid blowout bug in Chrome/Safari */
.hero-grid > *,
.footer-grid > *,
.value-strip .container > * {
  min-width: 0;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

/* Baseline keyboard-focus ring for every interactive element. A handful
   of controls (gallery dots, variant selects, form fields, sort select,
   skip link) already define their own more specific :focus-visible --
   those still win on specificity. Everything else -- nav/theme/cart/
   wish toggles, filter pills, every .btn variant -- was relying on
   nothing but the browser's own default, which is inconsistent across
   browsers and not guaranteed visible against this dark UI.

   `summary` is in the list because <summary> is focusable with no tabindex
   and matches none of the other selectors here. .card-ingredients summary and
   .faq-accordion-summary each ship their own ring, but .pdp-accordion-summary
   (three per product page) had nothing of its own -- only
   `.pdp-accordion:has(:focus-visible) { border-color }`, a colour-only change
   on the parent, which is exactly the weak indicator this baseline exists to
   replace. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--whiskey);
  outline-offset: 2px;
  border-radius: 2px;
}

/* overflow-x is a defensive safety net: nothing here should ever be
   wider than the viewport, but this catches the odd overlooked
   element before it causes an ugly sideways scroll on a phone. */
html {
  scroll-behavior: smooth;
  overflow-x: hidden;

  @media (prefers-reduced-motion: reduce) {
    scroll-behavior: auto;
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    transition-duration: 0.001ms !important;
  }
  /* The native View Transition crossfade (@view-transition below) runs on
     browser-generated pseudo-elements that the rule above doesn't reach --
     without this, a page navigation still animates for anyone who's told
     their OS they don't want motion. */
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }
}

body {
  margin: 0;
  overflow-x: hidden;
  background: var(--ink);
  color: var(--paper);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  transition:
    background 0.25s ease,
    color 0.25s ease;

  /* subtle grain/texture overlay */
  &::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    opacity: 0.05;
    mix-blend-mode: overlay;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  }
}

/* native, JS-free page transitions (Chrome/Edge 2025+, no-op elsewhere) */
@view-transition {
  navigation: auto;
}

/* Monoline SVG Icon System */
.yl-icon,
.yl-cart-icon {
  display: inline-block;
  vertical-align: -0.125em;
  flex-shrink: 0;
  stroke: currentColor;
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

img {
  max-width: 100%;
  height: auto;
  display: block;
}
a {
  color: inherit;
  text-decoration: none;
}
ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

h1,
h2,
h3,
h4 {
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: 0.02em;
  line-height: 1.15;
  margin: 0 0 0.5em;
  color: var(--paper);
  text-wrap: balance;
  overflow-wrap: break-word;
  word-break: normal;
}

h1 {
  font-size: clamp(1.65rem, 5vw, 3.2rem);
}
h2 {
  font-size: clamp(1.35rem, 3.8vw, 2.4rem);
}
h3 {
  font-size: clamp(1.05rem, 2.5vw, 1.35rem);
}
h4 {
  font-size: 1.05rem;
}
p {
  margin: 0 0 1em;
  color: var(--paper-dim);
  text-wrap: pretty;
  overflow-wrap: break-word;
}

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-family: var(--font-body);
  text-transform: uppercase;
  letter-spacing: 0.18em;
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--whiskey);
  flex-wrap: wrap;
}

.container {
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 32px;
  width: 100%;
  box-sizing: border-box;

  @media (max-width: 640px) {
    padding: 0 16px;
  }
}

section {
  padding: 88px 0;
  position: relative;
  container-type: inline-size; /* Dynamic sizing containment context */

  @media (max-width: 640px) {
    padding: 56px 0;
  }
}

.section-tight {
  padding: 56px 0;

  @media (max-width: 640px) {
    padding: 40px 0;
  }
}

.center {
  text-align: center;
}
.muted {
  color: var(--paper-dim);
}

/* =============== BUTTONS =============== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.92rem;
  letter-spacing: 0.03em;
  padding: 14px 30px;
  border-radius: var(--radius);
  border: 1px solid transparent;
  cursor: pointer;
  transition:
    transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1),
    background 0.3s ease,
    border-color 0.3s ease,
    color 0.3s ease,
    box-shadow 0.3s ease;
  white-space: nowrap;
  position: relative;
  overflow: hidden;

  &::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(to top, rgba(255, 255, 255, 0.15), transparent);
    opacity: 0;
    transition: opacity 0.3s ease;
    pointer-events: none;
  }

  &:hover {
    transform: translateY(-2px) scale(1.02);
    &::after {
      opacity: 1;
    }
  }

  &:active {
    transform: translateY(0) scale(0.98);
  }

  /* No disabled state existed anywhere on .btn -- three call sites
     (cart.js, main.js x2, including the box builder's "Add box to
     cart") set the native `disabled` attribute, which blocks clicks
     and :hover but leaves every color/shadow/gradient rule fully
     intact. Result: a bright, apparently-clickable button that
     silently does nothing. This is what actually read as "janky" in
     the box builder -- not the option cards -- since that button
     toggles disabled on every checkbox change. */
  &:disabled,
  &[aria-disabled="true"] {
    opacity: 0.45;
    cursor: not-allowed;
    box-shadow: none;
    transform: none;
    &:hover {
      transform: none;
      &::after {
        opacity: 0;
      }
    }
  }

  /* background/text use the fixed --rose-dim/--on-fill pair, not the
     theme-flipping --rose/--paper -- plain --rose + --paper only clears
     ~2.4-3.5:1 here (fails AA 4.5:1 for normal text), worst in light mode
     where --paper flips dark. See README a11y notes for the contrast math. */
  &.btn-primary {
    background: var(--rose-dim);
    color: var(--on-fill);
    box-shadow: var(--shadow);
    &:hover {
      background: var(--rose-fill-hover);
    }
  }

  &.btn-whiskey {
    background: var(--whiskey);
    color: var(--ink);
    box-shadow: var(--shadow);
    border-color: var(--whiskey);
    &:hover {
      background: var(--whiskey-dim);
      color: var(--on-fill);
    }
  }

  &.btn-outline {
    border-color: var(--whiskey);
    color: var(--paper);
    background: transparent;
    &:hover {
      background: var(--whiskey);
      color: var(--ink);
    }
  }

  &.btn-ghost {
    color: var(--whiskey);
    padding: 14px 6px;
    &:hover {
      color: var(--paper);
    }
  }

  &.btn-sm {
    padding: 10px 20px;
    font-size: 0.82rem;
  }
  &.btn-block {
    width: 100%;
  }
}

/* =============== NAV =============== */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: color-mix(in oklch, var(--nav-bg) 75%, transparent);
  backdrop-filter: blur(16px);
  border-bottom: 1px solid color-mix(in oklch, var(--hide) 40%, transparent);
  transition:
    background 0.3s ease,
    backdrop-filter 0.3s ease,
    padding 0.3s ease;
  padding-top: env(safe-area-inset-top, 0px);
}

.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: nowrap;
  gap: 12px;
  padding: 14px 24px;
  max-width: var(--container);
  margin: 0 auto;

  @media (max-width: 1024px) {
    padding: 12px 18px;
    gap: 10px;
  }
  @media (max-width: 600px) {
    padding: 10px 14px;
    gap: 8px;
  }
  @media (max-width: 360px) {
    padding: 8px 10px;
    gap: 6px;
  }
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 1;
  min-width: 0;

  @media (max-width: 600px) {
    gap: 6px;
  }

  /* The two logos are <picture> elements now (AVIF/WebP variants over a PNG
     fallback -- live audit 2026-09-02, H-1). `display: contents` keeps the
     <img> itself as the flex item, so the wrapper never becomes a zero-width
     child that the 10px gap still spaces around when its <img> is
     display:none at the other breakpoint. Layout is byte-for-byte what it
     was when these were bare <img> tags. */
  & picture {
    display: contents;
  }

  & img.logo-desktop {
    width: 44px;
    height: 44px;
    flex-shrink: 0;
  }

  & img.logo-mobile {
    display: none;
    width: auto;
    height: 44px;
    flex-shrink: 0;
  }

  @media (max-width: 600px) {
    & img.logo-desktop {
      display: none;
    }
    & img.logo-mobile {
      display: block;
      height: 32px;
      width: 32px;
    }
  }

  & .brand-word {
    font-family: var(--font-display);
    font-size: 1.4rem;
    letter-spacing: 0.03em;
    line-height: 1.1;
    white-space: nowrap;
    /* Never paint over the controls to the right. `.brand` shrinks
       (min-width: 0) but nowrap text ignores that box, and at 375-430px the
       six header controls left it drawing under the wishlist heart. */
    overflow: hidden;
    text-overflow: ellipsis;
    font-variation-settings:
      "opsz" 40,
      "wght" 420;

    /* "Living" inherits the same styling as "Y'allternative" appearing on the same line with a small left margin acting as a space. */
    & small {
      display: inline;
      margin-left: 0.25em;
      font-family: inherit;
      font-size: inherit;
      letter-spacing: inherit;
      text-transform: none;
      color: inherit;
      font-weight: inherit;
      font-variation-settings: inherit;

      @media (max-width: 600px) {
        display: none !important;
      }
    }

    @media (max-width: 768px) {
      font-size: 1.15rem;
    }
    @media (max-width: 480px) {
      font-size: 0.95rem;
    }
    /* Below 420px there is no room for the wordmark beside the six header
       controls (measured: 36px of overlap on a 375/390px phone). The logo
       mark carries the brand there. */
    @media (max-width: 420px) {
      display: none;
    }
  }
}
.nav-links {
  display: flex;
  align-items: center;
  gap: 34px;

  @media (max-width: 1200px) {
    gap: 20px;
  }

  html[lang="de"] &,
  html[lang="es"] &,
  html[lang="fr"] & {
    gap: 20px;

    @media (max-width: 1200px) {
      gap: 12px;
    }
  }

  & a {
    font-size: 0.86rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    font-weight: 600;
    color: var(--paper-dim);
    position: relative;
    padding: 6px 0;

    &:hover,
    &.active {
      color: var(--paper);
    }

    /* The pride underline is a hover/focus affordance, not a page-load
       badge. It used to sit permanently under `.active`, so the only time
       anyone ever saw it draw was when a new page finished loading -- it
       read as decoration that fired at the wrong moment. The current page
       is still marked by the brighter `--paper` colour above and by
       `aria-current="page"` in the markup, which is what assistive tech
       actually reads. */
    &::after {
      content: "";
      position: absolute;
      left: 0;
      right: 0;
      bottom: 0;
      height: 2px;
      background: var(--pride);
      transform: scaleX(0);
      transform-origin: left center;
      transition: transform 0.25s ease;
      pointer-events: none;
    }
    &:hover::after,
    &:focus-visible::after {
      transform: scaleX(1);
    }
  }

  @media (max-width: 1024px) {
    /* Explicit height, not `inset:100px 0 0 0`: a `height:auto` flex
       column here does NOT stretch to fill top->bottom the way a plain
       block box would -- it collapses to just its own padding (80px),
       leaving every link past the first rendered with no panel
       background behind it, floating directly on top of page content.
       Giving it an explicit height (100dvh accounts for mobile browser
       chrome; the plain vh line is the fallback for browsers without
       dvh support) makes it actually fill the viewport below the header. */
    position: fixed;
    top: 58px;
    left: 0;
    right: 0;
    z-index: 99;
    height: calc(100vh - 58px);
    height: calc(100dvh - 58px);
    background: var(--ink);
    flex-direction: column;
    justify-content: flex-start;
    padding: 32px 24px calc(32px + env(safe-area-inset-bottom, 0px));
    gap: 22px;
    overflow-y: auto;
    transform: translateY(-12px);
    opacity: 0;
    /* `visibility: hidden` keeps the closed drawer's links out of the tab
       order and out of the accessibility tree. It must NOT be animated on
       the way open: main.js focuses the first link in the same task as it
       adds `.open`, and an interpolating visibility is still `hidden` at
       that instant, so the focus() call would silently do nothing and a
       keyboard user's Tab would leave the menu they just opened. So the
       open direction flips visibility instantly (delay 0 below) and only
       the close direction waits for the fade to finish. */
    visibility: hidden;
    pointer-events: none;
    transition:
      transform 0.25s ease,
      opacity 0.2s ease,
      visibility 0s linear 0.2s;

    &.open {
      transform: translateY(0);
      opacity: 1;
      visibility: visible;
      pointer-events: auto;
      transition-delay: 0s;
    }
    & a {
      font-size: 1.1rem;
    }
  }
}

/* The 4.9-across-32 line is our whole Etsy shop; the list below it is the
   subset for goods still sold here (live audit M7). */
.reviews-scope-note {
  max-width: 62ch;
  margin: 12px auto 0;
  font-size: 0.86rem;
}

/* FAQ, Reviews and Policies live only in the footer, which is a long scroll
   away on a phone -- and the drawer was five links followed by ~900px of
   nothing (live audit L5). main.js appends them to the same <ul>, so they
   have to stay out of the desktop bar, where eight links do not fit. */
.nav-secondary {
  display: none;
}

.nav-secondary-heading {
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--paper-dim);
  opacity: 0.7;
  margin-top: 12px;
  padding-top: 16px;
  border-top: 1px solid var(--hide);
  width: 100%;
}

@media (max-width: 1024px) {
  .nav-links .nav-secondary {
    display: block;
  }
}

.nav-cta {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;

  @media (max-width: 480px) {
    gap: 4px;
  }

  @media (max-width: 600px) {
    gap: 6px;
  }

  & > * {
    flex-shrink: 0;
  }
}

.nav-toggle {
  display: none;
  background: none;
  border: 1px solid var(--hide);
  color: var(--paper);
  position: relative;
  width: 40px;
  height: 40px;
  border-radius: var(--radius);
  cursor: pointer;
  font-size: 1.1rem;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition:
    transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1),
    border-color 0.2s ease;

  @media (max-width: 1024px) {
    display: inline-flex;
  }
  @media (max-width: 600px) {
    width: 36px;
    height: 36px;
  }
}

/* light/dark theme toggle switch */
.theme-toggle {
  position: relative;
  width: 50px;
  height: 28px;
  border-radius: 28px;
  border: 1px solid var(--hide);
  background: var(--ink-3);
  cursor: pointer;
  flex-shrink: 0;
  padding: 0;
  display: inline-flex;
  align-items: center;
  transition:
    transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1),
    border-color 0.2s ease;

  @media (max-width: 600px) {
    width: 44px;
    height: 24px;
  }

  & .knob {
    position: absolute;
    top: 2px;
    left: 2px;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: var(--whiskey);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.7rem;
    transition:
      transform 0.25s ease,
      background 0.25s ease;

    @media (max-width: 600px) {
      width: 18px;
      height: 18px;
      top: 2px;
      left: 2px;
    }

    & .icon-sun {
      display: none;
    }
    & .icon-moon {
      display: block;
    }

    :root[data-theme="light"] & {
      transform: translateX(22px);
      background: #e58e26;
      color: #ffffff;
      & .icon-sun {
        display: block;
      }
      & .icon-moon {
        display: none;
      }

      @media (max-width: 600px) {
        transform: translateX(20px);
      }
    }

    @media (prefers-color-scheme: light) {
      :root:not([data-theme="dark"]):not([data-theme="light"]) & {
        transform: translateX(22px);
        background: #e58e26;
        color: #ffffff;
        & .icon-sun {
          display: block;
        }
        & .icon-moon {
          display: none;
        }

        @media (max-width: 600px) {
          transform: translateX(20px);
        }
      }
    }
  }
}

/* =============== HERO =============== */
.hero {
  min-height: 55dvh; /* dynamic viewport height accounts for dynamic browser chrome */
  display: flex;
  align-items: center;
  padding: 80px 0 60px;
  background:
    radial-gradient(ellipse at 20% 20%, rgba(181, 73, 91, 0.18), transparent 55%),
    radial-gradient(ellipse at 80% 80%, rgba(201, 138, 75, 0.14), transparent 55%), var(--ink);
  border-bottom: 1px solid var(--hide);
  container-type: inline-size;

  @media (max-width: 900px) {
    min-height: auto;
    padding: 32px 0 36px;
  }
  @media (max-width: 480px) {
    padding: 24px 0 28px;
  }

  & h1 {
    margin-bottom: 0.5em;
  }
  & .lede {
    font-size: 1.15rem;
    max-width: 78ch;
    margin-bottom: 22px;
  }

  /* The hero stays left-aligned at every width, same as the desktop
     layout. It briefly centred the h1/lede/buttons below 900px on the
     premise that ".shop-hero-header already centers itself here" -- but
     that rule is `align-items: center`, which centres flex items on the
     CROSS axis (vertically). It has no justify-content, so the eyebrow
     and rating row stayed hard left. The result on a phone was a
     left-aligned eyebrow sitting above a centred headline and a centred
     three-line paragraph: the exact mismatch the centring was meant to
     fix. Centred body copy is also the harder thing to read, since every
     line starts at a different x.

     The buttons go full-width instead of centred: two CTAs of very
     different label lengths ("Shop Salves, Soaks & More" vs "Read Our
     Story") look ragged however they're aligned, and matching their
     width settles that while giving each a bigger tap target. */
  @media (max-width: 480px) {
    & .lede {
      font-size: 1rem;
      margin-bottom: 16px;
    }
    & .hero-actions {
      gap: 10px;
    }
    & .hero-actions .btn {
      padding: 13px 20px;
      font-size: 0.9rem;
      width: 100%;
    }
  }
}

.hero-grid {
  display: grid;
  grid-template-columns: 1.3fr 0.7fr;
  gap: 48px;
  align-items: center;

  @container (max-width: 1050px) {
    grid-template-columns: 1.2fr 0.8fr;
    gap: 40px;
  }

  @container (max-width: 900px) {
    grid-template-columns: 1fr;
    gap: 28px;
  }
}

.hero-actions {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
  align-items: center;
  margin-top: 8px;
}

.tag {
  display: inline-flex;
  gap: 6px;
  align-items: center;
  justify-content: center;
  line-height: 1;
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--paper-dim);
  border: 1px solid var(--hide);
  padding: 8px 14px 6px 10px;
  border-radius: 20px;
}

.hero-art {
  position: relative;
  justify-self: end;

  @container (max-width: 900px) {
    margin: 0 auto 16px;
    justify-self: center;
  }

  & picture {
    display: block;
    max-width: 320px;

    @container (max-width: 900px) {
      max-width: 320px;
    }
    @container (max-width: 480px) {
      max-width: 240px;
    }
  }
  & img {
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow);
    border: 1px solid var(--hide);
  }
}

.shop-hero-header {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 12px;
  margin-top: 8px;
  margin-bottom: 16px;
}

.hero-separator {
  color: var(--paper-dim);
  margin: 0;
  font-weight: bold;
  font-size: 0.85rem;

  @media (max-width: 600px) {
    display: none;
  }
}

.shop-rating-inline {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  font-size: 0.82rem;
  color: var(--paper-dim);
  text-transform: uppercase;
  letter-spacing: 0.05em;

  & .stars {
    color: var(--whiskey);
    letter-spacing: 1px;
    font-size: 0.9rem;
    display: inline-flex;
    align-items: center;
  }

  & b {
    color: var(--paper);
    font-weight: 700;
  }

  & .rating-text {
    display: inline;
    overflow-wrap: break-word;
  }
}

/* =============== VALUE STRIP =============== */
.value-strip {
  border-bottom: 1px solid var(--hide);
  background: var(--ink-2);
  container-type: inline-size;

  & .container {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 28px;
    padding: 36px 24px;

    @container (max-width:820px) {
      grid-template-columns: repeat(2, 1fr);
    }
    @container (max-width:520px) {
      grid-template-columns: 1fr;
      gap: 22px;
    }
  }
}

.value-item {
  display: flex;
  gap: 12px;
  align-items: flex-start;

  & .glyph {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--whiskey);
    margin-top: 2px;
    flex-shrink: 0;

    & svg {
      width: 22px;
      height: 22px;
    }
  }

  /* h2, not h4 -- these sit directly under the page's single h1 with no
     intervening section heading on index.html, so h4 skipped two levels
     (a real heading-hierarchy issue for screen-reader users navigating by
     heading). Kept visually identical; this rule just now targets h2. */
  & h2 {
    font-family: var(--font-body);
    font-weight: 700;
    font-size: 0.92rem;
    margin: 0 0 4px;
    letter-spacing: 0.02em;
  }
  & p {
    font-size: 0.86rem;
    margin: 0;
  }
}

/* =============== SECTION HEADERS =============== */
/* Left-aligned by default -- an editorial kicker+heading+dek block reads
   as more considered/custom than every section on every page centering
   its intro above a symmetric grid, which is the templated look we're
   deliberately avoiding here. */
.section-head {
  max-width: 960px;
  margin: 0 0 48px;
  text-align: left;

  & .eyebrow {
    justify-content: flex-start;
    margin-bottom: 14px;
  }

  &.center {
    text-align: center;
    margin: 0 auto 48px;
    & .eyebrow {
      justify-content: center;
    }
  }
}

/* =============== PRODUCT CARDS / GRID =============== */
.grid {
  display: grid;
  gap: 28px;
}

.grid-3 {
  grid-template-columns: repeat(3, 1fr);

  @container (max-width:980px) {
    grid-template-columns: repeat(2, 1fr);
  }
  @container (max-width:600px) {
    grid-template-columns: 1fr;
  }
}

.card {
  background: var(--ink-2);
  border: 1px solid var(--hide);
  border-radius: var(--radius-lg);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition:
    transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1),
    border-color 0.3s ease,
    box-shadow 0.3s ease;

  /* Keyboard focus styling of parent cards via :has() for superior keyboard accessibility */
  &:hover,
  &:has(:focus-visible) {
    transform: translateY(-6px) scale(1.01);
    border-color: var(--whiskey-dim);
    box-shadow: 0 20px 40px -15px rgba(0, 0, 0, 0.4);

    :root[data-theme="light"] & {
      box-shadow: 0 20px 40px -15px rgba(60, 40, 20, 0.15);
    }
  }
}

.card-media {
  position: relative;
  aspect-ratio: 4/3.4;
  overflow: hidden;
  background: var(--ink-2);
  cursor: pointer;

  & picture {
    display: block;
    width: 100%;
    height: 100%;
  }
  & img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.5s ease;

    .card:hover & {
      transform: scale(1.05);
    }
  }
}

/* Product photo gallery -- most products now carry a few extra real
   Etsy listing photos alongside the hero shot (see cardGalleryHTML()
   in main.js). Slides stack absolutely and only the active one shows;
   dots below switch which is active. Products with just one photo
   never render this wrapper at all, so nothing changes for them. */
.card-gallery {
  position: relative;
  width: 100%;
  height: 100%;

  & .card-gallery-slide {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.25s ease;

    &.active {
      opacity: 1;
      visibility: visible;
    }
  }

  & .card-gallery-dots {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 6px;
    display: flex;
    justify-content: center;
    gap: 2px;
    z-index: 2;
  }

  & .card-gallery-dot {
    position: relative;
    width: 38px;
    height: 38px; /* WCAG 2.5.8 target-size floor; visible dot stays small */
    display: flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: none;
    padding: 0;
    margin: 0;
    cursor: pointer;
    transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);

    &::after {
      content: "";
      display: block;
      width: 6px;
      height: 6px;
      border-radius: 50%;
      background: rgba(255, 255, 255, 0.55);
      box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25);
      transition:
        background 0.2s ease,
        transform 0.2s ease;
    }

    &.active::after {
      background: #fff;
      transform: scale(1.25);
    }
    &:focus-visible {
      outline: 2px solid var(--whiskey);
      outline-offset: 1px;
      border-radius: 50%;
    }
  }
}

.card-body {
  padding: 20px 22px 24px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  flex: 1;

  /* `text-wrap: balance` (set globally on h1-h4) evens out a heading's line
     lengths. That is right for a big hero title and wrong for a card title in
     a narrow column: it broke "Bug Off B*tch Natural Bug Spray" at 113px of an
     available 242px on a 320px screen, leaving half the line empty and reading
     like a bug rather than a choice. Fill the line instead.

     Below 600px the cards are the narrowest they ever get (~288px on a 320px
     screen, ~380px on a Pixel 7), which is the only place long product names
     actually run out of room. Easing the title down there fits nearly all of
     them on one line -- measured over all 26 products, wrapping goes 3/26 ->
     0/26 on a Pixel 7 and 3/26 -> 1/26 on an iPhone 14. A 320px screen still
     wraps 5; no type size fixes that without shrinking past legibility. */
  & h3 {
    margin: 0;
    font-family: var(--font-body);
    font-weight: 700;
    font-size: 1.02rem;
    text-wrap: wrap;

    @media (max-width: 600px) {
      font-size: 0.9rem;
    }
  }
  & p {
    font-size: 0.88rem;
    margin: 0;
  }
}

.card-cat {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--whiskey);
  font-weight: 700;
}

/* Real per-product Etsy review data (see products-data.js/apply-etsy-
   snapshot.js) -- only rendered for products that actually have >=1 real
   review, so this never appears next to an empty/fabricated rating. */
.card-rating {
  display: flex;
  align-items: center;
  gap: 1px;
  font-size: 0.85rem;
  color: var(--whiskey);
  margin: -4px 0 0;
}

/* Only ever rendered when Savanna has set a real p.stock number -- see
   stockBadgeHTML() in main.js. Never a fabricated urgency claim. */
.stock-badge {
  display: inline-block;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 3px 9px;
  border-radius: 20px;
  margin: -2px 0 2px;

  &.low-stock {
    background: rgba(214, 155, 92, 0.16);
    color: var(--whiskey);
  }
  &.sold-out {
    background: rgba(180, 70, 70, 0.16);
    color: var(--rose-text);
  }
  &.sale-badge {
    background: var(--rose-dim);
    color: var(--on-fill);
  }
}

/* In light theme the .16 amber tint darkens the badge fill to ~#edddc4.
   The old --whiskey (#93571b) dropped to 4.34:1 there -- just under the
   4.5:1 AA floor (axe-core color-contrast) -- so this pinned the text to
   --whiskey-dim (#7a4816, ~5.7:1). --whiskey has since been darkened to
   #7f4a13 for the same class of tint failures and now clears it on its
   own; the pin stays because "lowest stock" reads better a shade deeper
   than the other amber chips. Dark theme's lighter amber text already
   passes, so scope to light only. Covers both explicit toggle and
   OS-preference-only visitors. */
:root[data-theme="light"] .stock-badge.low-stock,
:root:not([data-theme="dark"]):not([data-theme="light"]) .stock-badge.low-stock {
  color: var(--whiskey-dim);
}

/* Bundle cards reuse .card entirely; these only cover what's actually
   different -- the included-items list and the struck-through full price. */
.bundle-includes {
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 0.85rem;
  color: var(--paper-dim);

  & li {
    padding-left: 1.2em;
    position: relative;
    margin-bottom: 2px;
    &::before {
      content: "+";
      position: absolute;
      left: 0;
      color: var(--whiskey);
      font-weight: 700;
    }
  }
}

/* ---------- Gift-set option pickers (live audit C1) ----------
   A set that contains a tee (4 sizes) or the shimmer oil (3 scents) used to
   render no control at all, so $45 was taken and the shop never learned
   which size or scent to pack. */
.bundle-variants {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 4px 0 2px;
  padding: 12px;
  border: 1px solid var(--hide);
  border-radius: var(--radius);
  background: var(--ink-3);
}

.bundle-variants-hint {
  margin: 0;
  font-size: 0.76rem;
  color: var(--paper-dim);
}

.bundle-variant-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.bundle-variant-label {
  font-size: 0.76rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--paper);
}

.bundle-variant-select {
  width: 100%;
  min-height: 44px;
  padding: 10px 12px;
  border-radius: var(--radius);
  border: 1px solid var(--hide);
  background: var(--ink-2);
  color: var(--paper);
  font-family: inherit;
  font-size: 0.86rem;
}

.bundle-variant-select:focus-visible {
  outline: 2px solid var(--whiskey);
  outline-offset: 1px;
}

/* Shown only when Add Set is pressed with a choice still outstanding. */
.bundle-variant-error {
  margin: 0;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--rose-text, var(--rose));
}

.bundle-full-price,
.original-price {
  color: var(--paper-dim);
  font-size: 0.8rem;
  font-weight: 400;
  margin-left: 6px;
}

/* Collapsed by default (<details> with no [open]) -- real per-product
   ingredient data, but shown on demand so it doesn't compete with the
   price/Add to Cart button for space on every single card. */
.card-ingredients {
  &:first-of-type {
    border-top: 1px solid var(--hide);
  }

  & summary {
    cursor: pointer;
    color: var(--paper-dim);
    font-weight: 600;
    list-style: none;
    padding: 12px 0;
    display: flex;
    justify-content: space-between;
    align-items: center;

    &::-webkit-details-marker {
      display: none;
    }

    &::after {
      content: "+";
      transition: transform 0.2s ease;
      color: var(--whiskey);
      font-size: 1.2rem;
      line-height: 1;
      font-weight: 300;
    }
    &:focus-visible {
      outline: 2px solid var(--whiskey);
      outline-offset: 2px;
      border-radius: 2px;
    }
  }

  &[open] summary {
    padding-bottom: 4px;
  }
  &[open] summary::after {
    transform: rotate(45deg);
  }
  & ul {
    margin: 0;
    padding-left: 1.1em;
  }
  & li {
    margin-bottom: 2px;
  }
}

.ingredients-note {
  margin: 12px 0 16px;
  font-style: italic;
}
.ingredients-caveat {
  margin: 12px 0 16px;
  font-size: 0.8rem;
}

/* contact.html's 3 contact cards sit directly under the page h1 with no
   h2 in between, so their headings were promoted h3->h2 to close that
   skip; this keeps them visually identical to the product-card h3 style. */
.contact-card .card-body h2 {
  margin: 0;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 1.02rem;
}

/* margin-top:auto is what keeps every price row in a grid row aligned, but
   a card with neither a rating nor a stock/volume badge is ~60px shorter
   than its row-mates and collected all of that slack as one visible hole
   above the price (live audit nit). A hairline turns the space into a
   deliberate footer rather than a rendering gap. */
.card-foot {
  margin-top: auto;
  padding-top: 14px;
  border-top: 1px solid var(--hide);

  & .card-foot-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
  }
}

.price {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 1.15rem;
  color: var(--paper);
}

/* Size/scent/blend picker -- only rendered for products whose real Etsy
   listing actually sells more than one option (see variantSelectHTML()
   in main.js). Same visual language as .shop-sort select, just smaller
   and full-width so it sits naturally above the price/Add to Cart row. */
.variant-select-wrap {
  display: block;
  margin-bottom: 8px;
}

.variant-select-label {
  display: block;
  margin-bottom: 4px;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--paper-dim);
}

.variant-select {
  width: 100%;
  appearance: none; /* Standard unprefixed appearance */
  background: var(--ink-2)
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%2393571b'/%3E%3C/svg%3E")
    no-repeat right 12px center;
  background-size: 10px 6px;
  border: 1px solid var(--hide);
  color: var(--paper);
  padding: 8px 30px 8px 12px;
  border-radius: var(--radius);
  font-family: var(--font-body);
  font-size: 0.8rem;
  cursor: pointer;

  &:focus-visible {
    outline: 2px solid var(--whiskey);
    outline-offset: 1px;
    border-color: var(--whiskey);
  }
}

/* =============== TESTIMONIALS =============== */
.quote-card {
  background: var(--ink-2);
  border: 1px solid var(--hide);
  border-radius: var(--radius-lg);
  padding: 28px;
  height: 100%;

  & .stars {
    color: var(--whiskey);
    letter-spacing: 2px;
    margin-bottom: 10px;
    display: block;
  }
  & p {
    font-size: 1rem;
    color: var(--paper);
    font-style: italic;
  }
  & footer {
    font-size: 0.8rem;
    color: var(--paper-dim);
    margin-top: 14px;
  }
}

/* =============== CTA BAND =============== */
.cta-band {
  background: linear-gradient(180deg, var(--ink-2), var(--ink));
  border-top: 1px solid var(--hide);
  border-bottom: 1px solid var(--hide);
  text-align: center;

  & h2 {
    margin-bottom: 0.3em;
  }
  & p {
    max-width: 72ch;
    margin: 0 auto 28px;
  }
}

/* =============== CUSTOMER REVIEWS (site-submitted, shop.html) ===============
   Site-submitted reviews, kept visually + structurally separate from the
   Etsy-sourced "4.9 average / 32 Etsy reviews" line up in .shop-trust --
   see assets/js/site-reviews-data.js for why they're never merged into
   one number. Cards reuse .quote-card (same component as the homepage
   testimonials) rather than a near-duplicate style, since visually
   they're the same idea: a short quoted review with a byline. */
/* Left-aligned to match .section-head's sitewide convention (see the
   homepage's own left-aligned "What Y'all Are Saying" testimonials
   header) -- this used to be centered, which was an inconsistency, not
   a deliberate exception like .cta-band or .reviews-empty are. */
.reviews-head {
  text-align: left;
  max-width: 960px;
  margin: 0 0 32px;

  & .muted a {
    color: var(--whiskey);
    text-decoration: underline;
    &:hover {
      color: var(--paper);
    }
  }
}

.reviews-list {
  margin-bottom: 8px;

  /* No JS needed to toggle this: an unpopulated (or genuinely empty)
     .reviews-list has zero children, so :empty matches automatically --
     once main.js renders real review cards into it, this stays hidden. */
  &:empty + .reviews-empty {
    display: block;
  }
}

.reviews-empty {
  display: none;
  text-align: center;
  margin: 0 0 32px;
}

/* Reviews Filter & Search Bar */
.reviews-filter-container {
  display: flex;
  flex-direction: column;
  gap: 16px;
  margin-bottom: 24px;
}

@media (min-width: 768px) {
  .reviews-filter-container {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
  }
}

.reviews-search-field {
  flex: 1;
  max-width: 480px;
  margin: 0;
}

.search-input-wrap {
  position: relative;
  display: flex;
  align-items: center;
}

.search-input-wrap .icon-search {
  position: absolute;
  left: 14px;
  color: var(--paper-dim);
  pointer-events: none;
}

.search-input-wrap input,
.search-input-wrap input[type="text"],
.search-input-wrap input[type="search"] {
  width: 100%;
  padding: 10px 14px 10px 42px !important;
  background: var(--ink-2);
  border: 1px solid var(--hide);
  border-radius: var(--radius-md, 8px);
  color: var(--paper);
  font-size: 0.95rem;
  transition:
    border-color 0.2s ease,
    box-shadow 0.2s ease;
}

.search-input-wrap input:focus,
.search-input-wrap input[type="text"]:focus,
.search-input-wrap input[type="search"]:focus {
  border-color: var(--whiskey);
  outline: 2px solid var(--whiskey);
  outline-offset: 1px;
}

.review-rating-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.review-card-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
  gap: 8px;
}

.review-card-top .stars {
  margin-bottom: 0;
}

.badge-verified {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 0.75rem;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: 999px;
  background: rgba(76, 175, 80, 0.15);
  color: #4caf50;
  border: 1px solid rgba(76, 175, 80, 0.3);
}

/* #2e7d32 sat at 3.66:1 on its own .12 green tint (55 nodes across
   shop/reviews). Matched to the light --success green (#276030), which
   clears 5.3:1 on the same tint. The second selector covers
   OS-preference-only visitors, who previously fell through to the
   dark-theme #4caf50 on a light fill. */
:root[data-theme="light"] .badge-verified {
  background: rgba(39, 96, 48, 0.12);
  color: #276030;
  border-color: rgba(39, 96, 48, 0.28);
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]):not([data-theme="light"]) .badge-verified {
    background: rgba(39, 96, 48, 0.12);
    color: #276030;
    border-color: rgba(39, 96, 48, 0.28);
  }
}

.reviews-count-banner {
  font-size: 0.9rem;
  color: var(--paper-dim);
  margin-bottom: 20px;
}

.reviews-empty-state {
  text-align: center;
  padding: 48px 24px;
  background: var(--ink-2);
  border: 1px dashed var(--hide);
  border-radius: var(--radius-lg);
  margin: 24px 0 40px;
}

.reviews-empty-state p {
  color: var(--paper-dim);
  margin-bottom: 16px;
  font-size: 1.05rem;
}

.review-form-wrap {
  background: var(--ink-2);
  border: 1px solid var(--hide);
  border-radius: var(--radius-lg);
  padding: 32px;
  margin: 40px auto 0;
  max-width: 640px;

  @media (max-width: 600px) {
    padding: 24px;
  }

  & h3 {
    margin-bottom: 0.25em;
    text-align: center;
  }

  &.is-submitted {
    & .review-form {
      display: none;
    }
    & .review-form-confirm {
      display: flex;
    }
  }
}

.review-form-confirm {
  display: none;
  margin: 16px 0 0;
  font-size: 0.95rem;
  color: var(--paper);
  align-items: center;
  gap: 10px;
  justify-content: center;
  & .glyph {
    color: var(--whiskey);
    font-weight: 700;
  }
}

.review-form {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 16px;
  margin-top: 20px;

  @media (max-width: 600px) {
    grid-template-columns: 1fr;
  }

  & .field-wide {
    grid-column: 1 / -1;
  }
  & button {
    grid-column: 1 / -1;
    justify-self: start;
  }
  & .review-form-note {
    grid-column: 1 / -1;
    font-size: 0.78rem;
    color: var(--paper-dim);
    margin: 4px 0 0;
  }
}

/* =============== FOOTER =============== */
.site-footer {
  background: var(--footer-bg);
  border-top: 1px solid var(--hide);
  padding: 64px 0 28px;
  container-type: inline-size;
}

.footer-grid {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr 1fr;
  gap: 40px;
  margin-bottom: 48px;

  @container (max-width:820px) {
    grid-template-columns: repeat(2, 1fr);
  }

  /* Two columns all the way down, not one. Collapsing to a single column
     turned the footer into ~20 links stacked one per row -- 1610px on a
     390px-wide phone, nearly two full screens of nothing but footer to
     scroll past. The Explore and Shop lists are short labels that sit
     side by side fine at this width; only the brand blurb and the
     contact block need the full row, so they span it. */
  @container (max-width:560px) {
    grid-template-columns: repeat(2, 1fr);
    gap: 28px 20px;

    & > .footer-brand {
      grid-column: 1 / -1;
    }
    & > :last-child {
      grid-column: 1 / -1;
    }
  }

  /* h3, not h5 -- the footer's last preceding heading on every page is an
     h2, so h5 skipped two levels there too. Now matches the newsletter
     heading beside it, which was already h3. */
  & h3 {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.16em;
    color: var(--whiskey);
    margin: 0 0 16px;
    font-weight: 700;
  }
  & li {
    margin-bottom: 10px;
  }
  & a {
    color: var(--paper-dim);
    font-size: 0.92rem;
    &:hover {
      color: var(--paper);
    }
  }
}

/* No ch cap: the 1.4fr grid column (~360-400px desktop) is already the
   real constraint. A 42ch cap (~300px) was narrower than that column,
   causing lines to wrap a word or two early for no reason. */
.footer-brand p {
  max-width: 100%;
  font-size: 0.9rem;
}
.footer-brand .brand {
  margin-bottom: 16px;
}

.social-row {
  display: flex;
  gap: 14px;
  margin-top: 16px;

  & a {
    position: relative;
    width: 38px;
    height: 38px;
    border: 1px solid var(--hide);
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.9rem;
    color: var(--paper-dim);
    transition:
      border-color 0.2s ease,
      color 0.2s ease,
      transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);

    & svg {
      width: 17px;
      height: 17px;
    }
    &:hover {
      border-color: var(--whiskey);
      color: var(--whiskey);
      transform: translateY(-2px);
    }
  }
}

/* skip-link (a11y) */
.skip-link {
  position: absolute;
  left: -999px;
  top: auto;
  background: var(--rose-dim);
  color: var(--on-fill);
  padding: 12px 20px;
  z-index: 200;
  border-radius: 0 0 var(--radius) 0;

  &:focus {
    left: 0;
    top: 0;
  }
}

/* opacity was dropped -- at .72rem (small text, needs 4.5:1) the old
   opacity:.85 blended --paper-dim toward the light-theme footer background
   just barely over the AA floor (~4.52:1), too close for comfort. Plain
   --paper-dim alone clears it with real margin in both themes. */
.footer-disclaimer {
  font-size: 0.72rem;
  color: var(--paper-dim);
  margin: 0 0 16px;
  max-width: 100%;
}

.footer-bottom {
  border-top: 1px solid var(--hide);
  padding-top: 24px;
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  font-size: 0.78rem;
  color: var(--paper-dim);
}

/* =============== NEWSLETTER SIGNUP (footer strip) ===============
   Plain <form method="post"> straight to the email provider -- no
   fetch(), no preventDefault() on the real subscribe submit, so it
   still works with JavaScript fully off. The "you're on the list"
   state below only ever gets toggled by the small ?subscribed=1
   check in main.js, after the provider's own post-signup redirect
   lands back on this site. See README for the real setup steps. */
.footer-signup {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  flex-wrap: wrap;
  background: var(--ink-2);
  border: 1px solid var(--hide);
  border-radius: var(--radius-lg);
  padding: 28px 32px;
  margin-bottom: 48px;

  @media (max-width: 700px) {
    flex-direction: column;
    align-items: stretch;
    padding: 24px;
  }

  & .footer-signup-text {
    max-width: 100%;
    flex: 1 1 380px;

    /* flex-basis:380px above sizes this as a *width* in the desktop row
       layout. Once .footer-signup goes flex-direction:column below, the
       same flex-basis controls *height* instead -- pinning this block to
       380px tall no matter how short its actual text is, and leaving a
       big dead gap before the email field. Let it size to its content
       once it's stacked. */
    @media (max-width: 700px) {
      flex-basis: auto;
    }

    & h3 {
      margin-bottom: 0.25em;
    }
    & p {
      margin: 0;
      font-size: 0.9rem;
    }
  }

  & .footer-signup-form {
    display: flex;
    align-items: flex-end;
    gap: 12px;
    flex-wrap: wrap;
    flex: 0 0 auto;
    @media (max-width: 700px) {
      flex-direction: column;
      align-items: stretch;
    }

    & .field {
      margin-bottom: 0;
      min-width: 220px;
      @media (max-width: 700px) {
        min-width: 0;
      }
    }

    & .btn {
      @media (max-width: 700px) {
        width: 100%;
      }
    }
  }

  & .footer-signup-confirm {
    display: none;
    margin: 0;
    font-size: 0.95rem;
    color: var(--paper);
  }

  &.is-subscribed {
    & .footer-signup-text,
    & .footer-signup-form {
      display: none;
    }
    & .footer-signup-confirm {
      display: flex;
      align-items: center;
      gap: 10px;
    }
  }
}

/* Honeypot: present in the markup for any bot that fills every field,
   invisible and untabbable for real visitors -- same off-screen trick
   as .skip-link above, just permanently hidden instead of focus-revealed.
   Shared by every plain-POST form on the site (newsletter signup below,
   the review form further down) rather than duplicated per form. */
.form-hp {
  position: absolute;
  left: -999px;
  top: auto;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* =============== FORMS =============== */
.field {
  margin-bottom: 18px;

  & label {
    display: block;
    font-size: 0.78rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--paper-dim);
    margin-bottom: 8px;
    font-weight: 600;
    transition: color 0.25s ease;
  }

  & input,
  & textarea,
  & select {
    width: 100%;
    background: var(--ink);
    border: 1px solid var(--hide);
    color: var(--paper);
    padding: 13px 14px;
    border-radius: var(--radius);
    font-family: var(--font-body);
    font-size: 0.95rem;
    transition: border-color 0.25s ease;

    &:focus-visible {
      outline: 2px solid var(--whiskey);
      outline-offset: 1px;
      border-color: var(--whiskey);
    }
  }

  /* Style label when child form controls are focused using SOTA CSS :has() */
  &:has(input:focus, textarea:focus, select:focus) label {
    color: var(--whiskey);
  }
}

/* ── Build-Your-Own Box ───────────────────────────────── */
.custom-box-card {
  background: linear-gradient(
    160deg,
    var(--ink-2) 0%,
    oklch(from var(--ink-2) calc(l - 0.03) c h) 100%
  );
  border: 1px solid oklch(from var(--whiskey) l c h / 0.25);
  border-radius: var(--radius-xl);
  padding: 2rem;
  box-shadow:
    0 16px 40px -12px rgba(0, 0, 0, 0.5),
    inset 0 1px 0 rgba(255, 255, 255, 0.05);
}

.custom-box-head {
  text-align: center;
  margin-bottom: 1.75rem;

  & .custom-box-badge {
    display: inline-block;
    letter-spacing: 0.15em;
    font-size: 0.75rem;
    font-weight: 700;
    color: var(--whiskey);
    background: oklch(from var(--whiskey) l c h / 0.12);
    border: 1px solid oklch(from var(--whiskey) l c h / 0.3);
    padding: 0.3rem 0.8rem;
    border-radius: 999px;
    margin-bottom: 0.5rem;
  }

  & h2 {
    font-family: var(--font-display);
    margin: 0.4rem 0 0.5rem;
    font-size: 2rem;
  }
  & .muted {
    max-width: 520px;
    margin: 0 auto 1.25rem;
    font-size: 0.95rem;
  }
}

.custom-box-tracker {
  display: flex;
  gap: 0.5rem;
  justify-content: center;
  flex-wrap: wrap;
  margin-top: 1rem;
}

.custom-box-slot {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.35rem 0.75rem;
  border-radius: 999px;
  font-size: 0.8rem;
  font-weight: 600;
  transition: all 0.25s ease;

  &.is-filled {
    background: oklch(from var(--whiskey) l c h / 0.18);
    border: 1px solid var(--whiskey);
    color: var(--whiskey);
    box-shadow: 0 2px 8px oklch(from var(--whiskey) l c h / 0.15);
  }

  &.is-required {
    background: rgba(255, 255, 255, 0.03);
    border: 1px dashed var(--hide);
    color: var(--paper-dim);
  }

  &.is-optional {
    background: rgba(255, 255, 255, 0.015);
    border: 1px dashed oklch(from var(--hide) calc(l - 0.05) c h);
    color: oklch(from var(--paper-dim) calc(l - 0.15) c h);
  }

  & .custom-box-slot-thumb,
  & picture img {
    width: 20px;
    height: 20px;
    border-radius: 50%;
    object-fit: cover;
    border: 1px solid var(--whiskey);
  }

  & picture {
    display: inline-flex;
    flex-shrink: 0;
  }
}

.custom-box-options {
  list-style: none;
  margin: 0 0 1.5rem;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 0.85rem;
}

.custom-box-option {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  padding: 0.85rem 1rem;
  background: var(--ink-3);
  border: 1px solid var(--hide);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition:
    transform 0.2s cubic-bezier(0.16, 1, 0.3, 1),
    border-color 0.2s ease,
    background 0.2s ease,
    box-shadow 0.2s ease;
  position: relative;

  &:hover,
  &:focus-within {
    border-color: oklch(from var(--whiskey) l c h / 0.5);
    background: oklch(from var(--ink-3) calc(l + 0.04) c h);
    transform: translateY(-2px);
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.35);
  }

  &.is-chosen {
    border-color: var(--whiskey);
    box-shadow:
      0 0 0 1px var(--whiskey),
      0 4px 18px oklch(from var(--whiskey) l c h / 0.25);
    background: linear-gradient(
      135deg,
      oklch(from var(--whiskey) l c h / 0.16),
      oklch(from var(--whiskey) l c h / 0.04)
    );
  }

  &.is-disabled {
    opacity: 0.45;
    cursor: not-allowed;
    transform: none !important;
    box-shadow: none !important;
  }
}

.custom-box-option-img-wrap {
  flex-shrink: 0;
  width: 48px;
  height: 48px;
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--ink-1);
  border: 1px solid rgba(255, 255, 255, 0.08);
}

.custom-box-option-img,
.custom-box-option-img-wrap img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.custom-box-option-img-wrap picture {
  display: block;
  width: 100%;
  height: 100%;
}

.custom-box-option-img-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--whiskey);
  font-size: 1.1rem;
}

.custom-box-option-body {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}

.custom-box-option-name {
  font-weight: 600;
  font-size: 0.9rem;
  line-height: 1.3;
  color: var(--paper);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.custom-box-option-cat {
  font-size: 0.7rem;
  letter-spacing: 0.05em;
  color: var(--paper-dim);
  text-transform: uppercase;
}

.custom-box-option-meta {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.35rem;
  margin-left: auto;
}

.custom-box-option-price {
  font-weight: 700;
  color: var(--paper);
  font-size: 0.9rem;
  font-variant-numeric: tabular-nums;
}

.custom-box-checkbox-wrap {
  position: relative;
  width: 22px;
  height: 22px;

  & input[type="checkbox"] {
    position: absolute;
    opacity: 0;
    width: 100%;
    height: 100%;
    cursor: inherit;
    margin: 0;
    z-index: 2;
  }
}

.custom-box-check-badge {
  position: absolute;
  top: 0;
  left: 0;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 2px solid oklch(from var(--paper-dim) calc(l - 0.1) c h);
  background: var(--ink-1);
  display: flex;
  align-items: center;
  justify-content: center;
  color: transparent;
  transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
  z-index: 1;

  .custom-box-option:hover & {
    border-color: var(--whiskey);
  }

  .custom-box-option.is-chosen & {
    background: var(--whiskey);
    border-color: var(--whiskey);
    color: var(--ink-1);
    box-shadow: 0 2px 8px oklch(from var(--whiskey) l c h / 0.4);
  }
}

.custom-box-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  background: rgba(0, 0, 0, 0.25);
  border: 1px solid var(--hide);
  border-radius: var(--radius-lg);
  padding: 1.25rem 1.5rem;
}

.custom-box-summary-block {
  flex: 1 1 auto;
}

.custom-box-summary {
  margin: 0;
  font-size: 0.95rem;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
}

.custom-box-count-pill {
  background: oklch(from var(--whiskey) l c h / 0.15);
  border: 1px solid oklch(from var(--whiskey) l c h / 0.3);
  color: var(--whiskey);
  padding: 0.2rem 0.65rem;
  border-radius: 999px;
  font-size: 0.8rem;
  font-weight: 700;
}

.custom-box-price-tag {
  font-size: 1.1rem;

  & strong {
    color: var(--paper);
    font-size: 1.25rem;
  }
}

.custom-box-full-price {
  color: var(--paper-dim);
  font-size: 0.9rem;
  margin-right: 0.25rem;
}

.custom-box-saving {
  background: oklch(from var(--success) l c h / 0.15);
  border: 1px solid oklch(from var(--success) l c h / 0.3);
  color: var(--success);
  font-weight: 700;
  font-size: 0.82rem;
  padding: 0.2rem 0.65rem;
  border-radius: 999px;
}

.custom-box-empty-msg {
  color: var(--paper-dim);
  font-size: 0.9rem;
}

.custom-box-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.75rem 1.4rem;
  font-weight: 700;

  &.is-ready {
    box-shadow: 0 4px 20px oklch(from var(--whiskey) l c h / 0.35);
  }
}

/* Order-tracking-unavailable notice. Same reasoning as .form-fallback-note
   below: state plainly that the lookup isn't wired up rather than inventing
   an order status. */
.order-lookup-unavailable {
  margin: 1rem 0 0;
  padding: 16px;
  border: 1px solid var(--hide);
  border-radius: var(--radius, 8px);
  background: var(--ink-3);
  color: var(--paper-dim);
  font-size: 0.88rem;
  line-height: 1.5;

  & a {
    color: var(--whiskey);
    font-weight: 600;
    text-decoration: underline;
  }
}

/* "This form isn't connected yet" notice -- see showFormFallback() in
   assets/js/main.js. Deliberately styled as a warning, not a success. */
.form-fallback-note {
  margin: 12px 0 0;
  padding: 10px 12px;
  border: 1px solid var(--error);
  border-radius: var(--radius);
  background: oklch(from var(--error) l c h / 0.12);
  color: var(--paper);
  font-size: 0.85rem;
  line-height: 1.5;

  & a {
    color: var(--rose-text);
    font-weight: 600;
  }
}

.contact-form-col.is-submitted {
  & .contact-form,
  & .contact-form-desc {
    display: none;
  }
  & .contact-form-confirm {
    display: flex !important;
  }
}

/* =============== SEARCH (shop page) =============== */
.shop-search {
  position: relative;
  max-width: 420px;
  margin: 0 0 20px;

  & .shop-search-icon {
    position: absolute;
    left: 14px;
    top: 50%;
    transform: translateY(-50%);
    width: 16px;
    height: 16px;
    color: var(--paper-dim);
    pointer-events: none;
  }
  & input {
    width: 100%;
    background: var(--ink);
    border: 1px solid var(--hide);
    color: var(--paper);
    padding: 12px 14px 12px 40px;
    border-radius: 30px;
    font-family: var(--font-body);
    font-size: 0.92rem;

    @media (max-width: 600px) {
      font-size: 16px; /* iOS Safari auto-zoom prevention */
    }

    &::-webkit-search-cancel-button {
      cursor: pointer;
    }
    &:focus-visible {
      outline: 2px solid var(--whiskey);
      outline-offset: 1px;
      border-color: var(--whiskey);
    }
  }
}

/* =============== FILTER PILLS + SORT (shop page) =============== */
.shop-toolbar {
  display: flex;
  flex-direction: column;
  gap: 16px;
  align-items: stretch;
  margin-bottom: 20px;
}

@media (min-width: 900px) {
  .shop-toolbar {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
  }
}

.filter-row {
  display: flex;
  gap: 8px 10px;
  flex-wrap: wrap;
  justify-content: flex-start;
  margin-bottom: 0;
  max-width: 100%;
}

.filter-pill {
  position: relative;
  border: 1px solid var(--hide);
  background: transparent;
  color: var(--paper-dim);
  padding: 8px 18px;
  border-radius: 30px;
  font-size: 0.8rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  font-weight: 600;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  white-space: nowrap;
  flex-shrink: 0;
  transition: all 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
  box-shadow: 0 0 0 rgba(0, 0, 0, 0);

  &:hover {
    color: var(--paper);
    border-color: var(--whiskey-dim);
    transform: translateY(-2px);
  }
  &:active {
    transform: translateY(0);
  }
  &.active {
    background: var(--rose-dim);
    border-color: var(--rose-dim);
    color: var(--on-fill);
    transform: translateY(-2px);
    box-shadow: 0 4px 12px -2px rgba(224, 80, 90, 0.25);
  }

  &[data-tag] {
    border-style: dashed;
    &.active {
      border-style: solid;
    }
  }
}

.concern-filter-wrap {
  width: 100%;
  margin-top: 10px;
  min-height: 38px;
}

.concern-filter-row {
  display: flex;
  gap: 8px 10px;
  flex-wrap: wrap;
  justify-content: flex-start;
  margin-bottom: 0;
  max-width: 100%;
}

.concern-pill {
  position: relative;
  border: 1px solid var(--hide);
  background: var(--ink-2);
  color: var(--paper-dim);
  padding: 6px 14px;
  border-radius: 20px;
  font-size: 0.78rem;
  letter-spacing: 0.03em;
  font-weight: 500;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  justify-content: center;
  white-space: nowrap;
  flex-shrink: 0;
  transition: all 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
  box-shadow: 0 0 0 rgba(0, 0, 0, 0);

  &:hover {
    color: var(--paper);
    border-color: var(--whiskey-dim);
    transform: translateY(-2px);
  }
  &:active {
    transform: translateY(0);
  }
  &.active {
    background: oklch(from var(--whiskey) l c h / 0.18);
    border-color: var(--whiskey);
    color: var(--whiskey);
    font-weight: 700;
    transform: translateY(-2px);
    box-shadow: 0 4px 12px -2px rgba(212, 143, 56, 0.25);
  }
  &:focus-visible {
    outline: 2px solid var(--whiskey);
    outline-offset: 2px;
  }
}

.dispatch-badge-wrap {
  min-height: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 4px 0 8px 0;
}

.dispatch-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 0.74rem;
  font-weight: 600;
  color: var(--whiskey);
  background: oklch(from var(--whiskey) l c h / 0.12);
  border: 1px solid oklch(from var(--whiskey) l c h / 0.25);
  border-radius: var(--radius-sm, 6px);
  padding: 3px 8px;
  white-space: nowrap;
  line-height: 1.3;
}

.shop-sort {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;

  & #scentFieldWrap,
  & .sort-field-wrap {
    display: inline-flex;
    align-items: center;
    gap: 8px;
  }

  & #scentFieldWrap[hidden] {
    display: none !important;
  }

  @media (max-width: 600px) {
    width: 100%;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;

    & #scentFieldWrap,
    & .sort-field-wrap {
      flex: 1 1 auto;
    }

    & label[for="sortSelect"] {
      margin-left: 0;
    }

    & #sortSelect {
      flex: 1 1 120px;
    }

    & > .btn {
      width: 100%;
      text-align: center;
      margin-top: 4px;
    }
  }

  & label {
    font-size: 0.72rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--paper-dim);
    font-weight: 600;
  }

  & select {
    appearance: none; /* Standard unprefixed appearance */
    background: var(--ink-2)
      url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%2393571b'/%3E%3C/svg%3E")
      no-repeat right 14px center;
    background-size: 10px 6px;
    border: 1px solid var(--hide);
    color: var(--paper);
    padding: 9px 32px 9px 14px;
    border-radius: var(--radius);
    font-family: var(--font-body);
    font-size: 0.88rem;
    cursor: pointer;

    @media (max-width: 600px) {
      font-size: 16px; /* iOS Safari auto-zoom prevention */
    }

    &:focus-visible {
      outline: 2px solid var(--whiskey);
      outline-offset: 1px;
      border-color: var(--whiskey);
    }
  }
}

.shop-count {
  font-size: 0.82rem;
  color: var(--paper-dim);
  margin: 0 0 8px;
}
.shop-policy-note {
  font-size: 0.82rem;
  color: var(--paper-dim);
  margin: 0 0 24px;
  max-width: 1040px;
  & a {
    color: var(--whiskey);
    text-decoration: underline;
    &:hover {
      color: var(--paper);
    }
  }
}

/* =============== WISHLIST / SAVE FOR LATER =============== */
@keyframes heartPop {
  0% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.3);
  }
  100% {
    transform: scale(1);
  }
}

.wish-btn {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 2;
  position: relative;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: rgba(20, 16, 14, 0.55);
  backdrop-filter: blur(3px);
  border: 1px solid rgba(255, 255, 255, 0.3);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: #fff;
  transition:
    transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1),
    background 0.2s ease;

  &:hover {
    transform: scale(1.08);
  }
  & svg {
    width: 18px;
    height: 18px;
  }
  &.active {
    background: var(--rose);
    border-color: var(--rose);
    animation: heartPop 0.3s ease-out;
    & svg {
      fill: currentColor;
    }
  }
}

.wish-toggle {
  position: relative;
  background: none;
  border: 1px solid var(--hide);
  color: var(--paper);
  width: 42px;
  height: 42px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  flex: 0 0 auto;
  padding: 0 !important;
  box-sizing: border-box !important;
  line-height: 1 !important;
  transition:
    transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1),
    border-color 0.2s ease;

  @media (max-width: 420px) {
    width: 34px;
    height: 34px;
    flex-shrink: 0;
  }

  & svg {
    width: 19px;
    height: 19px;
  }
  & .badge {
    position: absolute;
    top: -6px;
    right: -6px;
    background: var(--rose-dim);
    color: var(--on-fill);
    font-size: 0.65rem;
    font-weight: 700;
    min-width: 18px;
    height: 18px;
    border-radius: 9px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 4px;
    line-height: 1;
    &:empty {
      display: none;
    }
  }
}

/* Cart trigger -- cart.js hooks into this .cart-toggle button itself (opens
   the drawer on click) and keeps its .cart-count badge in sync; this just
   styles the wrapper to match the wishlist heart button next to it. Amber
   badge (vs. the wishlist's rose one) keeps the two icons easy to tell apart. */
.cart-toggle {
  position: relative;
  background: none;
  border: 1px solid var(--hide);
  color: var(--paper);
  width: 42px;
  height: 42px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  flex: 0 0 auto;
  padding: 0 !important;
  box-sizing: border-box !important;
  line-height: 1 !important;
  transition:
    transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1),
    border-color 0.2s ease;

  @media (max-width: 420px) {
    width: 34px;
    height: 34px;
    flex-shrink: 0;
  }

  & svg {
    width: 19px;
    height: 19px;
  }
  & .badge {
    position: absolute;
    top: -6px;
    right: -6px;
    background: var(--whiskey);
    color: var(--ink);
    font-size: 0.65rem;
    font-weight: 700;
    min-width: 18px;
    height: 18px;
    border-radius: 9px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 4px;
    line-height: 1;
    &:empty {
      display: none;
    }
  }
}

.wish-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(10, 8, 6, 0.55);
  z-index: 198;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease;
  &.open {
    opacity: 1;
    pointer-events: auto;
  }
}

.wish-drawer {
  position: fixed;
  top: 0;
  right: 0;
  height: 100dvh;
  width: min(410px, 92dvw); /* Modern dynamic viewport height and width */
  background: var(--ink-2);
  border-left: 1px solid var(--hide);
  z-index: 199;
  transform: translateX(100%);
  transition: transform 0.3s ease;
  display: flex;
  flex-direction: column;
  box-shadow: var(--shadow);

  &.open {
    transform: translateX(0);
  }
}

.wish-drawer-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: calc(22px + env(safe-area-inset-top, 0px)) 24px 22px;
  border-bottom: 1px solid var(--hide);
  & h3 {
    margin: 0;
    font-family: var(--font-body);
    font-weight: 700;
    font-size: 1.1rem;
  }
}

.wish-drawer-close {
  background: none;
  border: none;
  color: var(--paper-dim);
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  /* Every other icon control on the site (wish/cart toggles, gallery dots)
     is explicitly sized to clear WCAG 2.2's 24x24 CSS px target-size floor
     -- this one only had font-metrics deciding its hit box until now. */
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius);
  &:hover {
    color: var(--paper);
  }
}

.wish-drawer-body {
  flex: 1;
  overflow-y: auto;
  padding: 8px 24px;
}

.wish-item {
  display: flex;
  gap: 14px;
  padding: 16px 0;
  border-bottom: 1px solid var(--hide);
  & picture {
    display: block;
    flex-shrink: 0;
  }
  & img {
    width: 64px;
    height: 64px;
    object-fit: cover;
    border-radius: var(--radius);
    flex-shrink: 0;
  }
}

.wish-item-body {
  flex: 1;
  min-width: 0;
  & h4 {
    font-family: var(--font-body);
    font-size: 0.92rem;
    font-weight: 700;
    margin: 0 0 4px;
  }
  & .price {
    font-size: 0.95rem;
  }
}

/* Three controls -- "Coming Soon", "Notify Me When Back in Stock" and
   "Remove" -- were packed into a single ~284px nowrap row, so both button
   labels were clipped mid-word ("oming So", "e When Back") and collided
   (live audit H3). Let the row wrap, give the long notify button a line of
   its own, and stop .btn's white-space:nowrap from forcing the overflow. */
.wish-item-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 14px;
  margin-top: 8px;
  min-width: 0;
}

.wish-item-actions .btn {
  white-space: normal;
  text-align: center;
  max-width: 100%;
}

.wish-item-actions .yl-notify-toggle {
  flex: 1 1 100%;
}

.wish-remove {
  background: none;
  border: none;
  color: var(--paper-dim);
  font-size: 0.78rem;
  text-decoration: underline;
  cursor: pointer;
  padding: 0;
  &:hover {
    color: var(--rose-text);
  }
}

.wish-empty {
  text-align: center;
  padding: 70px 24px;
  color: var(--paper-dim);
  & .glyph {
    font-size: 1.6rem;
    color: var(--whiskey);
    display: block;
    margin-bottom: 12px;
  }
}

.wish-drawer-foot {
  padding: 18px 24px calc(18px + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--hide);
  & p {
    font-size: 0.78rem;
    margin: 10px 0 0;
  }
}

/* =============== WELCOME PAGE (post-confirm discount) =============== */
/* Shown on welcome.html only, where Kit sends a subscriber after they click
   the confirmation link. The code is a thing people retype into Stripe's
   promo box, so it is set in a monospaced face at a size that survives being
   read off a phone, with generous letter-spacing so O/0 and I/1 stay apart. */
.welcome-code-card {
  max-width: 380px;
  margin: 28px auto 22px;
  padding: 22px 24px;
  border: 1px solid var(--hide);
  border-radius: var(--radius-lg);
  background: var(--ink-2);
  text-align: center;

  & .welcome-code-label {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--whiskey);
    font-weight: 700;
    margin: 0 0 6px;
  }
  & .welcome-code {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: clamp(1.5rem, 6vw, 2rem);
    font-weight: 700;
    letter-spacing: 0.12em;
    color: var(--paper);
    margin: 0 0 10px;
    /* Long codes should wrap rather than push the card wide on a 320px screen. */
    overflow-wrap: anywhere;
  }
  & .welcome-code-hint {
    font-size: 0.82rem;
    margin: 0;
    color: var(--paper-dim);
  }
}

/* The lede sits directly above the code card, so it stays short and does not
   compete with it -- the code is what the visitor came for. */
.welcome-lede {
  max-width: 34ch;
  margin-left: auto;
  margin-right: auto;
}

.welcome-footnote {
  max-width: 46ch;
  margin: 28px auto 0;
  font-size: 0.84rem;
  color: var(--paper-dim);
}

/* =============== EVENTS =============== */
.event-card {
  & .card-body {
    gap: 6px;
  }
}

.event-directions-links {
  font-size: 0.85em;
  color: var(--paper-muted);
}

.event-directions-links .event-map-link {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
  transition: color 0.15s ease;
}

.event-directions-links .event-map-link:hover,
.event-directions-links .event-map-link:focus-visible {
  color: var(--paper);
}

.pickup-market-notice {
  margin: 1.5rem 0 1rem;
}

.pickup-notice-inner {
  background: var(--surface);
  border: 1px solid var(--accent);
  border-radius: var(--radius, 8px);
  padding: 0.85rem 1.25rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  font-size: 0.95rem;
  color: var(--paper);
}

.pickup-notice-inner strong {
  color: var(--accent);
}

/* ── Past-events carousel ────────────────────────────── */

/* Wide screens: all cards visible side by side */
.events-carousel {
  position: relative;
  width: 100%;
  margin: 0 auto;
}

.events-carousel-inner {
  display: flex;
  gap: 24px;
  width: 100%;
}

.events-carousel .event-card {
  flex: 1 1 0;
  min-width: 0;
  box-sizing: border-box;
}

/* Hide carousel controls on wide screens */
.carousel-arrow,
.carousel-dots {
  display: none;
}

/* ── Narrow screens: single-card sliding carousel ──── */
@media (max-width: 768px) {
  .events-carousel {
    overflow: hidden;
  }

  .events-carousel-inner {
    gap: 0;
    transition: transform 0.6s cubic-bezier(0.25, 1, 0.5, 1);
  }

  .events-carousel .event-card {
    flex: 0 0 100%;
    width: 100%;
    opacity: 0.4;
    transition: opacity 0.6s ease;
  }

  .events-carousel .event-card.active {
    opacity: 1;
  }

  /* Arrow controls */
  .carousel-arrow {
    display: flex;
    position: absolute;
    top: 50%;
    transform: translateY(-60%);
    background: var(--ink-2);
    color: var(--paper);
    border: 1px solid var(--hide);
    width: 36px;
    height: 36px;
    border-radius: 50%;
    font-size: 1.4rem;
    line-height: 1;
    cursor: pointer;
    z-index: 3;
    align-items: center;
    justify-content: center;
    transition:
      background 0.2s,
      border-color 0.2s;
  }
  .carousel-arrow:hover {
    background: var(--whiskey);
    border-color: var(--whiskey);
    color: var(--ink);
  }
  .carousel-prev {
    left: -4px;
  }
  .carousel-next {
    right: -4px;
  }

  /* Dot indicators */
  .carousel-dots {
    display: flex;
    justify-content: center;
    gap: 0;
    margin-top: 16px;
  }
  /* WCAG 2.2 SC 2.5.8 wants a 24x24 CSS-pixel target. These were 10x10 with
     an 8px gap, so axe measured 12px of safe clickable space -- the only
     violation in the whole static sweep (audit C, finding L1). The BUTTON is
     now 24x24 and the 10px dot is drawn by ::before, so nothing looks
     different; the gap drops to 0 because the padding now supplies the
     visual spacing (24px pitch vs the old 18px) and touching 24x24 targets
     still satisfy the SC. */
  .carousel-dot {
    width: 24px;
    height: 24px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: none;
    background: transparent;
    cursor: pointer;
    padding: 0;
  }
  .carousel-dot::before {
    content: "";
    display: block;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    border: 1.5px solid var(--paper-dim);
    background: transparent;
    box-sizing: border-box;
    transition:
      background 0.25s,
      border-color 0.25s;
  }
  .carousel-dot.active::before {
    background: var(--whiskey);
    border-color: var(--whiskey);
  }
  .carousel-dot:hover::before {
    border-color: var(--paper);
  }
}

/* SW update toast */
.sw-update-toast {
  position: fixed;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%) translateY(120%);
  background: var(--ink-2);
  color: var(--paper);
  border: 1px solid var(--hide);
  border-radius: var(--radius-lg);
  padding: 12px 20px;
  display: flex;
  align-items: center;
  gap: 8px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
  z-index: 9999;
  font-size: 0.9rem;
  opacity: 0;
  transition:
    transform 0.4s cubic-bezier(0.25, 1, 0.5, 1),
    opacity 0.4s ease;
}
.sw-update-toast.visible {
  transform: translateX(-50%) translateY(0);
  opacity: 1;
}

.event-empty {
  grid-column: 1 / -1;
  text-align: center;
  max-width: 560px;
  margin: 0 auto;
  background: var(--ink-2);
  border: 1px dashed var(--hide);
  border-radius: var(--radius-lg);
  padding: 56px 32px;

  & .glyph {
    font-size: 1.8rem;
    color: var(--whiskey);
    display: block;
    margin-bottom: 14px;
  }
  & h3 {
    font-family: var(--font-body);
    font-weight: 700;
    margin-bottom: 10px;
  }
}

/* =============== PAGE HERO (inner pages) =============== */
/* Left-aligned, matching the homepage's asymmetric hero rather than
   falling back to a plain centered banner on every inner page (404's
   error state is the one deliberate exception -- centering is the
   right call there since there's no grid or content to align against). */
.page-hero {
  padding: 64px 0 48px;
  border-bottom: 1px solid var(--hide);
  background: radial-gradient(ellipse at 18% 0%, rgba(181, 73, 91, 0.14), transparent 60%);

  /* Cap the whole title+copy block to one consistent column width -- on
     wide viewports an unconstrained h1 plus a 62ch paragraph can drift to
     different right edges and read as loose/unfinished against all that
     open banner space. Keeping everything in the page-hero to one shared
     measure makes it read as a deliberate column, not sparse text.
     820px (not the original 640px): at the h1's clamped max size (3.6rem,
     see h1{} above), several real headlines here -- "The Full Collection,
     Y'all", "Part Goth, Part Grit, All Heart" -- were wrapping to 2 lines
     inside 640px even on a wide desktop viewport, with most of the banner
     sitting empty to the right. 820px is wide enough for every current
     page-hero h1 to sit on one line while still reading as a deliberate,
     narrower column than the full container. The paragraph below used to
     keep its own tighter 62ch cap regardless, which wrapped short ledes
     into 3 ragged lines with the banner mostly empty to the right -- it
     now shares the same 1040px cap as the shop intro below (independent
     of the 820px title column above; the p:not() rule has higher
     specificity so it already wins on max-width) so body copy actually
     uses the open space, consistently across every page-hero. */
  & .container > * {
    max-width: 960px;
  }
  & p:not(.breadcrumb) {
    max-width: 1040px;
    margin: 14px 0 0;
    font-size: 1.05rem;
  }
}

.policy-prose {
  max-width: 76ch;
}

.breadcrumb {
  font-size: 0.78rem;
  color: var(--paper-dim);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-bottom: 18px;
  & a:hover {
    color: var(--whiskey);
  }
}

/* =============== UTILS =============== */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
/* Scroll reveal. The hidden state is armed by main.js (`.reveal-armed`),
   never applied by default. It used to be the default, which meant every
   `.reveal` block stayed at opacity:0 until a 165KB deferred main.js had
   downloaded and run. about.html is the page that made that visible: its
   entire story -- both content sections -- is `.reveal`, so on a slow
   connection the page painted a hero over a blank white expanse for
   seconds and looked like it had failed to load. Content now paints
   immediately and only elements main.js has measured as below the fold get
   hidden to animate in, which can't flash because they are off-screen at
   the moment it happens. */
.reveal {
  transition:
    opacity 0.6s ease,
    transform 0.6s ease;
  &.reveal-armed {
    opacity: 0;
    transform: translateY(18px);
  }
  &.in {
    opacity: 1;
    transform: none;
  }
}

.stagger > * {
  transition-delay: calc(var(--i, 0) * 70ms);
}
hr.rule {
  border: none;
  border-top: 1px solid var(--hide);
  margin: 48px 0;
}

.two-col {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 56px;
  align-items: center;

  @container (max-width:880px) {
    grid-template-columns: 1fr;
  }
}

.img-frame {
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1px solid var(--hide);
  box-shadow: var(--shadow);
  & picture {
    display: block;
  }
}

/* ── Announcement bar ─────────────────────────────────── */
.announcement-bar {
  background: var(--whiskey);
  color: var(--ink);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0.6rem 1rem 0.5rem;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  position: sticky;
  top: 0;
  z-index: 101;
  font-family: var(--font-body);
  line-height: 1.2;
  min-height: 38px;
  box-sizing: border-box;
  font-variant-numeric: tabular-nums;
  flex-wrap: wrap;
  gap: 0 1.5rem;
  text-align: center;

  /* Divider between the countdown and the free-shipping message that main.js
     folds into this same bar (rather than stacking a second one). A middot got
     visually lost against ~95 characters of countdown, so this is a proper
     vertical rule with real breathing room on each side -- the two messages
     read as two distinct concepts rather than one run-on sentence.
     The element itself is aria-hidden, so this is purely decorative. */
  & .announcement-sep {
    width: 1px;
    align-self: stretch;
    margin: 0.15rem 0.35rem;
    background: currentColor;
    opacity: 0.35;
  }

  /* The countdown string alone is long ("79 days, 11 hours, 15 mins, 05 secs
     until Autumn Apothecary Faire (Landrum, SC)"), so below roughly a laptop
     width the two segments wrap to two or three lines -- a taller bar than the
     two stacked ones this replaced. Drop the free-shipping half instead and
     keep the bar to a single line; the same message still appears on the
     product cards and live in the cart drawer's shipping meter, so nothing is
     actually lost. .announcement-segment only exists on pages where the two
     bars merged, so the standalone bar on every other page is untouched. */
  @media (max-width: 1100px) {
    & .announcement-sep,
    & .announcement-segment {
      display: none;
    }
  }

  /* The bar's link was a 676x14px strip -- a full-width tap target 14px tall
     on a phone, sitting between the skip link and the brand link in the tab
     order (audit C, finding L10). axe exempts it as inline text, so this is
     a judgement call rather than a violation, but 24px costs nothing. The
     negative block margin cancels the padding's effect on layout, so the bar
     itself is exactly as tall as it was. */
  & a {
    color: inherit;
    text-decoration: underline;
    text-underline-offset: 2px;
    display: inline-flex;
    align-items: center;
    min-height: 24px;
    margin-block: -5px;
  }

  & + .site-header {
    top: auto; /* Fixes stacking overlap when both are sticky */
  }
}

.events-countdown-banner {
  font-variant-numeric: tabular-nums;
}

/* The "Next Live Appearance" hero restates the first upcoming event, which
   the list below already publishes with its own <h3>. It is styled like a
   heading but is a <p>, so the same event name no longer appears twice in
   the document outline (audit C, nit N5). Values copied from the h3 rule
   near the top of this file plus the inline font-family the card used. */
.countdown-card-title {
  margin: 0.4rem 0 0.6rem;
  font-family: var(--font-heading, var(--font-display));
  font-size: clamp(1.05rem, 2.5vw, 1.35rem);
  font-weight: 400;
  letter-spacing: 0.02em;
  line-height: 1.15;
  color: var(--paper);
  text-wrap: balance;
  overflow-wrap: break-word;
}

/* ── Cart shipping progress bar ───────────────────────── */
.shipping-progress {
  padding: 0.75rem 1rem;
  font-size: 0.8rem;
  font-family: var(--font-body);
  text-align: center;
  border-bottom: 1px solid oklch(from var(--paper) l c h / 0.1);
}

.shipping-progress__bar {
  height: 6px;
  border-radius: 3px;
  background: oklch(from var(--paper) l c h / 0.12);
  margin-top: 0.5rem;
  overflow: hidden;
}

.shipping-progress__fill {
  height: 100%;
  border-radius: 3px;
  background: var(--whiskey);
  transition: width 0.4s ease;
}

.shipping-progress--done {
  color: var(--whiskey);
  font-weight: 600;
}

/* ── Cart cross-sell ──────────────────────────────────── */
.cart-cross-sell {
  padding: 0.75rem 1rem;
  border-top: 1px solid oklch(from var(--paper) l c h / 0.1);
  font-family: var(--font-body);
  font-size: 0.8rem;

  &__heading {
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-size: 0.7rem;
    color: var(--paper-dim);
    margin-bottom: 0.5rem;
  }

  &__item {
    display: flex;
    align-items: center;
    gap: 0.75rem;
  }

  &__img {
    width: 48px;
    height: 48px;
    border-radius: var(--radius);
    object-fit: cover;
  }

  &__info {
    flex: 1;
  }

  &__name {
    font-weight: 600;
    font-size: 0.82rem;
  }

  &__price {
    color: var(--paper-dim);
    font-size: 0.78rem;
  }

  &__add {
    padding: 0.35rem 0.75rem;
    background: var(--whiskey);
    color: var(--ink);
    border: none;
    border-radius: var(--radius);
    font-size: 0.75rem;
    font-weight: 600;
    cursor: pointer;
    transition: opacity 0.2s;
    &:hover {
      opacity: 0.85;
    }
  }
}

/* ── Product tag pills ────────────────────────────────── */
.tag-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin-top: 0.35rem;
}

.tag-pill {
  display: inline-flex;
  gap: 4px;
  align-items: center;
  justify-content: center;
  line-height: 1;
  font-size: 0.65rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--paper-dim);
  border: 1px solid var(--hide);
  padding: 3px 10px 3px 6px;
  border-radius: 20px;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── Language Selector & Translation ──────────────────── */
.lang-selector-wrap {
  position: relative;
  display: inline-block;
}

.lang-toggle {
  position: relative;
  background: none;
  border: 1px solid var(--hide);
  color: var(--paper);
  height: 42px;
  border-radius: 21px;
  display: flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  flex: 0 0 auto;
  transition:
    border-color 0.2s ease,
    background-color 0.2s ease;
  padding: 0 10px 0 8px;
  font-family: var(--font-body);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.05em;

  &:hover,
  &:focus-visible {
    border-color: var(--whiskey);
    background-color: var(--ink-3);
  }

  @media (max-width: 600px) {
    height: 36px;
    padding: 0 7px 0 6px;
    gap: 3px;
    font-size: 0.68rem;
  }
  @media (max-width: 380px) {
    padding: 0 8px;
    & .lang-current-code {
      display: none;
    }
  }

  & svg {
    width: 17px;
    height: 17px;
  }

  & .lang-current-code {
    transform: translateY(-0.5px);
  }
}

.lang-dropdown {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  background: rgba(30, 24, 21, 0.85); /* transparent ink-2 matching */
  border: 1px solid var(--hide);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 6px 0;
  min-width: 150px;
  z-index: 200;
  display: none;
  flex-direction: column;
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  transition:
    opacity 0.2s ease,
    transform 0.2s ease;
  opacity: 0;
  transform: translateY(-8px);
  pointer-events: none;

  @media (max-width: 480px) {
    right: -10px;
    min-width: 130px;
  }

  &.open {
    display: flex;
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
  }
}

:root[data-theme="light"] .lang-dropdown {
  background: rgba(241, 233, 216, 0.85); /* transparent ink-2 in light mode */
}

.lang-option {
  background: none;
  border: none;
  color: var(--paper-dim);
  padding: 10px 16px;
  min-height: 44px;
  box-sizing: border-box;
  text-align: left;
  font-family: var(--font-body);
  font-size: 0.85rem;
  cursor: pointer;
  transition:
    background 0.2s ease,
    color 0.2s ease;
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;

  &:hover,
  &:focus-visible {
    background: var(--ink-3);
    color: var(--paper);
  }

  &.active {
    color: var(--whiskey);
    font-weight: 700;
  }
}

/* ── Print Styles ─────────────────────────────────────── */
@page {
  size: portrait;
  margin: 12mm;
}

@media print {
  .site-header,
  .site-footer,
  .nav-cta,
  .hero-actions,
  .filter-row,
  .btn,
  .cart-toggle,
  .skip-link,
  .announcement-bar,
  .thank-you-badge-wrap,
  .thank-you-actions,
  .thank-you-sub-actions,
  .btn-copy-ref,
  .birthday-club-section,
  .review-prompt-section,
  dialog.gift-modal,
  .shop-search {
    display: none !important;
  }
  body,
  html {
    background: #fff !important;
    color: #000 !important;
  }
  /* The order confirmation is the one page people print. Keep the receipt
     card and the support line, and drop the dark hero so page one is not a
     solid block of ink. */
  .thank-you-hero,
  .thank-you-hero *,
  .thank-you-card,
  .thank-you-card *,
  .thank-you-support-callout,
  .thank-you-support-callout * {
    background: transparent !important;
    color: #000 !important;
    box-shadow: none !important;
    text-shadow: none !important;
  }
  .thank-you-card,
  .thank-you-support-callout,
  .thank-you-session-row {
    border: 1px solid #999 !important;
  }
  .card {
    border: 1px solid #ccc !important;
    page-break-inside: avoid;
  }
}

/* ── Shop Page Specifics ───────────────────────────── */
.shop-lede {
  max-width: 1040px;
  margin: 0 0 22px;
  font-size: 1.05rem;
}
.shop-cta-actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  margin-top: 28px;
}
.shop-cta-secondary {
  font-size: 0.88rem;
  color: var(--paper-dim);
}
.shop-cta-secondary a {
  color: var(--whiskey);
  text-decoration: underline;
}
.shop-cta-secondary a:hover {
  color: var(--paper);
}

/* ── Gift Card Modal (SOTA 2026 Native Dialog Styling) ── */
dialog.gift-modal {
  background: var(--ink-2);
  border: 1px solid var(--hide);
  border-radius: var(--radius-lg);
  width: 100%;
  max-width: 900px;
  padding: 40px 48px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6);
  color: var(--paper);
  overflow-y: auto;
  max-height: 90vh;
  max-height: 90dvh;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) scale(0.96);
  margin: 0;
  opacity: 0;
  transition:
    opacity 0.3s ease,
    transform 0.3s ease,
    display 0.3s allow-discrete;
}
dialog.gift-modal[open] {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
}
@starting-style {
  dialog.gift-modal[open] {
    opacity: 0;
    transform: translate(-50%, -50%) scale(0.96);
  }
}

dialog.gift-modal::backdrop {
  background: rgba(10, 8, 7, 0.85);
  backdrop-filter: blur(8px);
  opacity: 0;
  transition:
    opacity 0.3s ease,
    display 0.3s allow-discrete;
}
dialog.gift-modal[open]::backdrop {
  opacity: 1;
}
@starting-style {
  dialog.gift-modal[open]::backdrop {
    opacity: 0;
  }
}

.gift-modal-close {
  position: absolute;
  top: 24px;
  right: 28px;
  background: none;
  border: none;
  color: var(--paper);
  font-size: 2.2rem;
  line-height: 1;
  cursor: pointer;
  padding: 4px;
  transition: color 0.2s ease;
  z-index: 5;
}
.gift-modal-close:hover {
  color: var(--whiskey);
}

.gift-modal-header {
  margin-bottom: 24px;
  /* Leave room for the absolutely-positioned close button so a long title
     does not run underneath it on a phone. */
  padding-right: 44px;
}
.gift-modal-header h2 {
  font-size: 2rem;
  margin: 0;
  color: var(--paper);
}
.gift-modal-header p {
  color: var(--paper-dim);
  font-size: 0.9rem;
  margin: 4px 0 0 0;
}

::placeholder {
  color: var(--paper-dim);
  opacity: 1;
}
/* ── Gift Card Widget (SOTA 2026) ─────────────────── */
/* The widget is a two-column grid with THREE children, and auto-placement
   gave the terms note the whole right column (84px tall, ~400px of dead
   space beneath it) while the controls were pushed onto row 2 inside the
   narrow 296px track -- which is why the email/name inputs rendered 141px
   wide and Add to Cart fell below the fold (live audit M3). Place all three
   explicitly: preview and controls side by side, terms note underneath. */
.gift-card-widget > .gift-card-preview {
  grid-column: 1;
  grid-row: 1;
}

.gift-card-widget > .gift-card-controls {
  grid-column: 2;
  grid-row: 1;
}

.gift-card-widget > .gift-terms-note {
  grid-column: 1 / -1;
  grid-row: 2;
  margin: 0;
}

.gift-card-widget {
  display: grid;
  grid-template-columns: minmax(220px, 1fr) minmax(320px, 1.6fr);
  gap: 28px 36px;
  background: var(--ink);
  border: 1px solid var(--hide);
  border-radius: var(--radius-large);
  padding: 36px;
  max-width: 920px;
  margin: 24px auto 0;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.25);
  align-items: start;
}
.gift-card-preview {
  aspect-ratio: 1.586;
  background: var(--ink) url("../img/gift-card.png") no-repeat center center / cover;
  border: 1.5px solid #d69b5c;
  border-radius: 16px;
  padding: 16px 18px;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  color: #f3ead9;
  position: relative;
  overflow: hidden;
  box-shadow:
    0 16px 36px rgba(0, 0, 0, 0.4),
    inset 0 1px 0 rgba(255, 255, 255, 0.1);
}
.gift-card-preview::after {
  content: "";
  position: absolute;
  top: -50%;
  right: -50%;
  width: 100%;
  height: 100%;
  background: radial-gradient(circle, rgba(214, 155, 92, 0.1) 0%, transparent 70%);
  pointer-events: none;
}
.card-brand-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  z-index: 2;
}
.gift-card-preview .card-badge {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: #d69b5c;
  background: rgba(18, 14, 11, 0.88);
  border: 1px solid rgba(214, 155, 92, 0.45);
  padding: 4px 10px;
  border-radius: 6px;
  font-weight: 700;
  backdrop-filter: blur(4px);
}
.card-amount-large {
  font-size: 1.35rem;
  font-weight: 700;
  font-family: var(--font-display);
  color: #d69b5c;
  background: rgba(18, 14, 11, 0.88);
  border: 1px solid rgba(214, 155, 92, 0.45);
  padding: 3px 10px;
  border-radius: 6px;
  backdrop-filter: blur(4px);
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.8);
  margin: 0;
  z-index: 2;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

/* Controls */
.gift-card-controls {
  display: flex;
  flex-direction: column;
  gap: 16px;
  text-align: left;
}
.gift-section-label {
  display: block;
  font-size: 0.92rem;
  font-weight: 700;
  color: var(--paper);
  margin-bottom: 10px;
}
.preset-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 8px;
}
.preset-btn {
  background: var(--ink-3);
  border: 1px solid var(--hide);
  color: var(--paper);
  border-radius: var(--radius, 8px);
  padding: 10px 4px;
  font-weight: 600;
  font-size: 0.92rem;
  cursor: pointer;
  transition: all 0.15s ease;
  text-align: center;
}
.preset-btn:hover {
  border-color: var(--whiskey);
  color: var(--whiskey);
  background: oklch(from var(--whiskey) l c h / 0.1);
}
.preset-btn.active {
  background: var(--whiskey);
  border-color: var(--whiskey);
  color: var(--ink);
  box-shadow: 0 2px 10px oklch(from var(--whiskey) l c h / 0.35);
}

.custom-input-wrap {
  margin-top: 10px;
}
.custom-input-wrap label {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--paper-dim);
  display: block;
  margin-bottom: 4px;
}
.custom-amount-input-wrap {
  position: relative;
  display: inline-flex;
  align-items: center;
  max-width: 180px;
  width: 100%;
}
.custom-amount-input-wrap .currency-prefix {
  position: absolute;
  left: 12px;
  color: var(--whiskey);
  font-weight: 700;
  pointer-events: none;
}
.custom-amount-input-wrap input {
  padding: 10px 14px 10px 26px;
  background: var(--ink-2);
  border: 1px solid var(--hide);
  color: var(--paper);
  border-radius: var(--radius, 8px);
  font-size: 1rem;
  font-weight: 600;
  width: 100%;
}
.custom-amount-input-wrap input:focus {
  outline: none;
  border-color: var(--whiskey);
}

.gift-fields-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}
.gift-card-controls .field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.gift-card-controls .field label {
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--paper-dim);
}
.gift-card-controls .field label .required-star {
  color: var(--whiskey);
}
.gift-card-controls .field label .optional-tag {
  color: var(--paper-dim);
  font-weight: 400;
  font-size: 0.75rem;
}
.gift-card-controls .field input,
.gift-card-controls .field textarea {
  width: 100%;
  padding: 10px 14px;
  background: var(--ink-2);
  border: 1px solid var(--hide);
  border-radius: var(--radius, 8px);
  color: var(--paper);
  font-size: 0.9rem;
  font-family: inherit;
  transition:
    border-color 0.2s ease,
    box-shadow 0.2s ease;
}
.gift-card-controls .field input:focus,
.gift-card-controls .field textarea:focus {
  outline: none;
  border-color: var(--whiskey);
  box-shadow: 0 0 0 3px oklch(from var(--whiskey) l c h / 0.15);
}

.gift-card-actions {
  display: flex;
  gap: 12px;
  margin-top: 10px;
}
.gift-card-actions button {
  margin: 0;
  width: 100%;
  min-height: 48px;
  font-size: 0.96rem;
  font-weight: 700;
}

@media (max-width: 768px) {
  .gift-card-widget {
    grid-template-columns: 1fr;
    gap: 28px;
    padding: 24px;
  }
  /* One column: let the three children fall back to DOM order. */
  .gift-card-widget > .gift-card-preview,
  .gift-card-widget > .gift-card-controls,
  .gift-card-widget > .gift-terms-note {
    grid-column: 1;
    grid-row: auto;
  }
  .preset-grid {
    grid-template-columns: repeat(3, 1fr);
  }
  .gift-fields-grid {
    grid-template-columns: 1fr;
  }
}
@media (max-width: 600px) {
  dialog.gift-modal {
    padding: 32px 18px 24px;
    width: calc(100vw - 24px);
    max-width: calc(100vw - 24px);
    max-height: 92dvh;
  }
  .gift-modal-close {
    top: 14px;
    right: 14px;
  }
  .gift-card-actions {
    flex-direction: column;
  }
}

/* ── Event Card Specifics ──────────────────────────── */
.event-card .card-body h3 {
  margin-bottom: 8px;
}
.event-date {
  font-weight: 600;
  font-size: 0.88rem;
  color: var(--paper);
  margin: 0 0 4px;
}
.event-location {
  margin-bottom: 12px;
}
.event-desc {
  font-size: 0.85rem;
  color: var(--paper-dim);
}
.event-cta {
  margin-top: auto;
  padding-top: 12px;
}
.btn-block {
  width: 100%;
  text-align: center;
}

/* Scoped and utility layout overrides for centralization */
.hero-actions.center {
  justify-content: center;
}
.grid-action {
  text-align: center;
  margin-top: 48px;
}
.cta-band p a {
  color: var(--whiskey);
  text-decoration: underline;
}
.cta-band p a:hover {
  color: var(--paper);
}
.tight-hero {
  min-height: 65vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 60px 0;
}

/* --- State-of-the-Art 2026 Lightbox Modal --- */
.lightbox-modal {
  border: none;
  background: rgba(13, 9, 10, 0.85); /* semi-transparent black-velvet */
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  padding: 0;
  max-width: 100vw;
  max-height: 100vh;
  width: 100%;
  height: 100%;
  justify-content: center;
  align-items: center;
  display: none;
  color: var(--paper);
}
.lightbox-modal[open] {
  display: flex;
}
.lightbox-modal::backdrop {
  background: rgba(13, 9, 10, 0.85);
  backdrop-filter: blur(10px);
}
.lightbox-content {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 90%;
  max-width: 900px;
  height: 80vh;
}
.lightbox-content img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  border-radius: 8px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
  border: 1px solid rgba(198, 90, 109, 0.2); /* faint gold/pink border */
}
.lightbox-close {
  position: absolute;
  top: 24px;
  right: 24px;
  background: none;
  border: none;
  color: var(--paper);
  font-size: 2.5rem;
  cursor: pointer;
  z-index: 10;
  line-height: 1;
  opacity: 0.7;
  transition:
    opacity 0.2s,
    transform 0.2s;
}
.lightbox-close:hover {
  opacity: 1;
  transform: scale(1.1);
}
.lightbox-prev,
.lightbox-next {
  position: absolute;
  background: rgba(13, 9, 10, 0.6);
  border: 1px solid rgba(255, 255, 255, 0.15);
  color: var(--paper);
  font-size: 2rem;
  width: 54px;
  height: 54px;
  border-radius: 50%;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition:
    background 0.2s,
    transform 0.2s,
    border-color 0.2s;
  z-index: 5;
  user-select: none;
}
.lightbox-prev:hover,
.lightbox-next:hover {
  background: var(--rose);
  border-color: var(--rose);
  transform: scale(1.05);
}
.lightbox-prev {
  left: 20px;
}
.lightbox-next {
  right: 20px;
}
.lightbox-dots {
  position: absolute;
  bottom: 40px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: 2px;
  z-index: 5;
}
/* Same WCAG 2.5.8 target-size pattern the shop-card gallery dots already use
   (see .card-gallery-dot): the button itself is a 38px tap target and the
   visible dot is drawn small inside it. These used to be bare 10px buttons
   12px apart -- half the 24px floor, and the one control a phone user reaches
   for most while flipping through a product's photos. */
.lightbox-dot {
  width: 38px;
  height: 38px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  cursor: pointer;
  padding: 0;
  margin: 0;
}
.lightbox-dot::after {
  content: "";
  display: block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.3);
  transition:
    background 0.2s,
    transform 0.2s;
}
.lightbox-dot.active::after {
  background: var(--whiskey);
  transform: scale(1.2);
}
.lightbox-dot:hover::after {
  background: var(--paper);
}
.lightbox-dot:focus-visible {
  outline: 2px solid var(--whiskey);
  outline-offset: -8px;
  border-radius: 50%;
}

/* Adjust layout on smaller screens.
   .lightbox-modal is display:flex with no flex-direction, so its two in-flow
   children -- the photo column and the "Complete the Ritual" panel -- sat
   SIDE BY SIDE at every width. On a 375px screen that left the photo column
   119px wide (a 119x90 thumbnail with the arrows on top of it), pushed the
   ritual panel's heading above the viewport and put "Add All to Cart" 73px
   below the fold with no way to scroll to it (live audit H2). Stack them,
   and let the dialog itself scroll. */
@media (max-width: 768px) {
  .lightbox-modal[open] {
    flex-direction: column;
    flex-wrap: nowrap;
    align-items: stretch;
    justify-content: flex-start;
    gap: 12px;
    padding: 56px 12px calc(20px + env(safe-area-inset-bottom));
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  .lightbox-content {
    width: 100%;
    max-width: 100%;
    height: auto;
    max-height: 44dvh;
    flex: 0 0 auto;
  }
  .lightbox-content img {
    width: 100%;
    max-height: 44dvh;
  }
  /* Absolutely positioned, this floated over whatever the column happened to
     scroll under it. In a stacked layout it belongs in flow. */
  .lightbox-dots {
    position: static;
    transform: none;
    justify-content: center;
    flex: 0 0 auto;
  }
  .lightbox-ritual-wrap {
    margin-top: 0;
    width: 100%;
    max-width: 100%;
    flex: 0 0 auto;
  }
  .lightbox-prev,
  .lightbox-next {
    width: 44px;
    height: 44px;
    font-size: 1.5rem;
  }
  .lightbox-prev {
    left: 10px;
  }
  .lightbox-next {
    right: 10px;
  }
}

/* ── Apothecary Quiz Section Styles ───────────────────── */
.quiz-option-card {
  transition:
    border-color 0.2s,
    background 0.2s,
    transform 0.2s;
  cursor: pointer;
  /* --ink, --ink-2 and --ink-3 sit within a few percent lightness of each
     other, so page / panel / card all read as one flat brown slab and the
     options stop looking like discrete choices. Lift the card off the panel
     and give it a border with actual presence. */
  background: oklch(from var(--ink-3) calc(l + 0.02) c h) !important;
  border-color: var(--hide) !important;
}

.quiz-option-card:hover,
.quiz-option-card:focus-within {
  border-color: var(--whiskey) !important;
  /* Hover must go LIGHTER than the resting fill to read as raised. An earlier
     pass used --ink-2 here, which is actually darker than the --ink-3 card
     (#1e1815 vs #262019), so hovering made the card recede instead. */
  background: oklch(from var(--ink-3) calc(l + 0.06) c h) !important;
  transform: translateY(-2px);
}

/* The chosen option was distinguishable only by the small native radio dot.
   Give the whole card a selected state so the current answer is obvious at a
   glance -- and don't rely on colour alone: the border also thickens. */
.quiz-option-card:has(input:checked) {
  border-color: var(--whiskey) !important;
  box-shadow: inset 0 0 0 1px var(--whiskey);
  background: oklch(from var(--whiskey) l c h / 0.1) !important;
}

/* ── Alt-Points loyalty badge ─────────────────────────── */
.alt-points-badge {
  display: inline-block;
  font-size: 0.78rem;
  color: var(--whiskey);
  font-weight: 600;
  margin-top: 4px;
}
/* =========================================================================
   ACCESSIBILITY: WCAG 2.5.8 MINIMUM TOUCH TARGETS
   =========================================================================
   Ensures all small interactive elements have at least a 44x44px clickable 
   area without compromising their physical/visual design by using an invisible 
   ::after pseudo-element that spans beyond the visual bounds.
*/
.nav-toggle::after,
.theme-toggle::after,
.wish-btn::after,
.wish-toggle::after,
.cart-toggle::after,
.filter-pill::after,
.social-row a::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 44px;
  height: 44px;
  min-width: 100%;
  min-height: 100%;
  transform: translate(-50%, -50%);
  z-index: 1;
}

/* For filter-pills which already have text, we want the pseudo element 
   behind the text so it doesn't block selection, or we can just keep z-index: 1 
   since it's a button and pointer-events handles clicks. */

/* =============== UGC / COMMUNITY SOCIAL PROOF STRIP =============== */
.ugc-section {
  padding: 80px 0;
  background: var(--ink-2);
  border-top: 1px solid var(--hide);
  border-bottom: 1px solid var(--hide);
  transition: background 0.3s ease;
}

@media (max-width: 768px) {
  .ugc-section {
    padding: 50px 0;
  }
}

.ugc-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
  margin-bottom: 32px;
}

@container (max-width: 900px) {
  .ugc-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 900px) {
  .ugc-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 20px;
  }
}

@media (max-width: 600px) {
  .ugc-grid {
    grid-template-columns: 1fr;
    gap: 24px;
  }
}

.ugc-card {
  background: var(--ink-3);
  border: 1px solid var(--hide);
  border-radius: var(--radius-lg);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  box-shadow: var(--shadow);
  transition:
    transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1),
    border-color 0.3s ease,
    box-shadow 0.3s ease;
}

.ugc-card:hover,
.ugc-card:has(:focus-visible) {
  transform: translateY(-6px) scale(1.01);
  border-color: var(--whiskey-dim);
  box-shadow: 0 20px 40px -15px rgba(0, 0, 0, 0.5);
}

:root[data-theme="light"] .ugc-card:hover,
:root[data-theme="light"] .ugc-card:has(:focus-visible) {
  box-shadow: 0 20px 40px -15px rgba(60, 40, 20, 0.15);
}

.ugc-card-media {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  background: var(--ink);
  overflow: hidden;
}

.ugc-card-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.5s ease;
}

.ugc-card:hover .ugc-card-media img {
  transform: scale(1.05);
}

.ugc-media-badge {
  position: absolute;
  top: 12px;
  right: 12px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  background: rgba(23, 19, 15, 0.85);
  backdrop-filter: blur(8px);
  color: #f3ead9;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border-radius: 20px;
  border: 1px solid rgba(255, 255, 255, 0.15);
  pointer-events: none;
}

:root[data-theme="light"] .ugc-media-badge {
  background: rgba(250, 245, 234, 0.9);
  color: #221a14;
  border-color: rgba(0, 0, 0, 0.1);
}

.ugc-product-tag {
  position: absolute;
  bottom: 12px;
  left: 12px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  background: var(--ink-2);
  color: var(--whiskey);
  font-size: 0.78rem;
  font-weight: 600;
  border-radius: var(--radius-sm);
  border: 1px solid var(--hide);
  text-decoration: none;
  transition:
    background 0.2s ease,
    color 0.2s ease,
    transform 0.2s ease;
  z-index: 2;
}

.ugc-product-tag:hover {
  background: var(--whiskey);
  color: var(--ink);
  transform: translateY(-2px);
}

.ugc-product-tag:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}

.ugc-card-body {
  padding: 20px;
  display: flex;
  flex-direction: column;
  flex-grow: 1;
  gap: 12px;
}

.ugc-author-row {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.ugc-author-name {
  font-family: var(--font-display);
  font-size: 1.1rem;
  font-weight: 600;
  color: var(--paper);
  line-height: 1.2;
}

.ugc-author-handle {
  font-size: 0.82rem;
  color: var(--paper-dim);
  font-weight: 500;
}

.ugc-caption {
  font-size: 0.92rem;
  line-height: 1.5;
  color: var(--paper);
  margin: 0;
  flex-grow: 1;
}

.ugc-post-link {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  align-self: flex-start;
  font-size: 0.84rem;
  font-weight: 600;
  color: var(--whiskey);
  text-decoration: none;
  margin-top: 4px;
  transition:
    color 0.2s ease,
    transform 0.2s ease;
}

.ugc-post-link:hover {
  color: var(--paper);
  transform: translateX(2px);
}

.ugc-post-link:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}

.ugc-cta {
  text-align: center;
  margin-top: 32px;
}

/* =============== FAQ ACCORDION & REVIEW PROMPT =============== */
.shop-faq-section {
  background: var(--ink-2);
  border-top: 1px solid var(--hide);
  border-bottom: 1px solid var(--hide);
  padding: 72px 0;
}

:root[data-theme="light"] .shop-faq-section {
  background: var(--ink-2);
}

.faq-accordion {
  display: flex;
  flex-direction: column;
  gap: 16px;
  max-width: 840px;
  margin: 0 auto;
}

.faq-accordion-item {
  background: var(--ink-3);
  border: 1px solid var(--hide);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow);
  transition:
    border-color 0.25s ease,
    box-shadow 0.25s ease,
    transform 0.25s ease;
}

.faq-accordion-item:hover,
.faq-accordion-item:has(:focus-visible) {
  border-color: var(--whiskey-dim);
}

.faq-accordion-item[open] {
  border-color: var(--whiskey);
  box-shadow: 0 16px 36px -12px rgba(0, 0, 0, 0.4);
}

:root[data-theme="light"] .faq-accordion-item[open] {
  box-shadow: 0 16px 36px -12px rgba(60, 40, 20, 0.15);
}

.faq-accordion-summary {
  padding: 20px 24px;
  cursor: pointer;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  font-family: var(--font-display);
  font-size: 1.2rem;
  font-weight: 600;
  color: var(--paper);
  list-style: none;
  transition:
    color 0.2s ease,
    background 0.2s ease;
}

.faq-accordion-summary::-webkit-details-marker {
  display: none;
}

.faq-accordion-summary::after {
  content: "+";
  font-family: var(--font-body);
  font-size: 1.5rem;
  font-weight: 300;
  color: var(--whiskey);
  transition:
    transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1),
    color 0.2s ease;
  flex-shrink: 0;
  line-height: 1;
}

.faq-accordion-item[open] .faq-accordion-summary::after {
  transform: rotate(45deg);
  color: var(--rose-text);
}

.faq-accordion-summary:hover {
  color: var(--whiskey);
}

.faq-accordion-summary:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: -2px;
}

.faq-accordion-content {
  padding: 0 24px 20px;
  color: var(--paper-dim);
  font-size: 0.98rem;
  line-height: 1.65;
  border-top: 1px solid color-mix(in oklch, var(--hide) 30%, transparent);
  margin-top: 4px;
  padding-top: 16px;
}

.faq-accordion-content p {
  margin: 0 0 0.8em;
}

.faq-accordion-content p:last-child {
  margin: 0;
}

.faq-accordion-content a {
  color: var(--whiskey);
  text-decoration: underline;
  transition: color 0.2s ease;
}

.faq-accordion-content a:hover {
  color: var(--paper);
}

.review-prompt-section {
  padding: 64px 0;
  background: var(--ink-2);
  border-top: 1px solid var(--hide);
  border-bottom: 1px solid var(--hide);
}

.review-prompt-card {
  background: var(--ink-3);
  border: 1px solid var(--hide);
  border-radius: var(--radius-lg);
  padding: 44px 36px;
  max-width: 720px;
  margin: 0 auto;
  text-align: center;
  box-shadow: var(--shadow);
  transition:
    transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1),
    border-color 0.3s ease,
    box-shadow 0.3s ease;
}

.review-prompt-card:hover {
  border-color: var(--whiskey-dim);
}

.review-prompt-card h2 {
  font-family: var(--font-display);
  font-size: clamp(1.6rem, 3vw, 2.2rem);
  margin-bottom: 12px;
  color: var(--paper);
}

.review-prompt-card p {
  color: var(--paper-dim);
  font-size: 1rem;
  line-height: 1.6;
  max-width: 560px;
  margin: 0 auto 28px;
}

.review-prompt-actions {
  display: flex;
  gap: 16px;
  justify-content: center;
  flex-wrap: wrap;
  align-items: center;
}

@media (max-width: 600px) {
  .faq-accordion-summary {
    padding: 16px 18px;
    font-size: 1.05rem;
  }
  .faq-accordion-content {
    padding: 0 18px 16px;
    font-size: 0.92rem;
  }
  .review-prompt-card {
    padding: 32px 20px;
  }
  .review-prompt-actions {
    flex-direction: column;
    width: 100%;
  }
  .review-prompt-actions .btn {
    width: 100%;
  }
}

/* ── Restock Alert Modal (Native Dialog Styling) ── */
dialog.restock-alert-modal {
  max-width: 540px;
}
.restock-product-preview {
  display: flex;
  align-items: center;
  gap: 16px;
  margin: 16px 0 24px;
  padding: 14px 18px;
  background: var(--ink-1);
  border-radius: var(--radius-md);
  border: 1px solid var(--hide);
}
.restock-success-state {
  padding: 24px 16px;
  background: var(--ink-1);
  border-radius: var(--radius-md);
  border: 1px solid var(--whiskey-glow, rgba(212, 143, 56, 0.2));
}

/* ── Thank You / Order Confirmation Page (SOTA 2026) ── */
.thank-you-hero {
  padding: 48px 0 56px;
}
.thank-you-badge-wrap {
  display: flex;
  justify-content: center;
  margin-bottom: 16px;
}
.thank-you-badge {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: oklch(from var(--whiskey) l c h / 0.12);
  border: 1.5px solid var(--whiskey);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--whiskey);
  box-shadow: 0 0 24px oklch(from var(--whiskey) l c h / 0.3);
}
.thank-you-check-icon {
  width: 26px;
  height: 26px;
}
.thank-you-title {
  font-family: var(--font-display);
  font-size: clamp(2.2rem, 4.5vw, 3.2rem);
  margin: 10px 0 12px;
  color: var(--paper);
}
.thank-you-lede {
  max-width: 600px;
  margin: 0 auto 32px;
  color: var(--paper-dim);
  font-size: 1.05rem;
  line-height: 1.6;
}

/* Order Receipt & Details Card */
.thank-you-card {
  background: var(--ink-2);
  border: 1px solid var(--hide);
  border-radius: var(--radius-lg, 16px);
  padding: 28px 32px;
  max-width: 580px;
  margin: 0 auto 32px;
  text-align: left;
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.4);
}
.thank-you-card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--hide);
}
.receipt-status-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--success, #5ca86c);
  background: oklch(from var(--success, #5ca86c) l c h / 0.12);
  border: 1px solid oklch(from var(--success, #5ca86c) l c h / 0.3);
  padding: 4px 12px;
  border-radius: 20px;
}
.status-pulse {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
  box-shadow: 0 0 8px currentColor;
}
.receipt-date-label {
  font-size: 0.82rem;
  color: var(--paper-dim);
  font-weight: 500;
}

.thank-you-amount-row {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: 12px 16px;
  padding: 20px 0 16px;
}
/* Several blocks here set their own `display`, which beats the UA's
   `[hidden]` rule -- the Order Reference row rendered (empty, with a live
   Copy button) on every URL without a session because of exactly that. */
.thank-you-hero [hidden] {
  display: none !important;
}
.amount-group .amount-label {
  font-size: 0.74rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--paper-dim);
  font-weight: 700;
  display: block;
}
.amount-group .amount-val {
  font-size: 2.2rem;
  font-weight: 700;
  font-family: var(--font-display);
  color: var(--paper);
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
  margin-top: 4px;
}
.receipt-discount-note {
  display: block;
  width: fit-content;
  font-size: 0.75rem;
  color: var(--whiskey);
  background: oklch(from var(--whiskey) l c h / 0.12);
  border: 1px solid oklch(from var(--whiskey) l c h / 0.25);
  padding: 3px 8px;
  border-radius: 4px;
  margin-top: 6px;
  font-weight: 600;
}
.receipt-secure-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.76rem;
  color: var(--whiskey);
  background: var(--ink-1);
  padding: 6px 12px;
  border-radius: 6px;
  border: 1px solid var(--hide);
  font-weight: 500;
}

.thank-you-session-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 14px;
  background: var(--ink-1);
  border: 1px solid var(--hide);
  border-radius: 8px;
  font-size: 0.8rem;
  margin-bottom: 20px;
}
.session-label-group {
  display: flex;
  flex-direction: column;
  gap: 2px;
  overflow: hidden;
  text-align: left;
}
.session-label {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--paper-dim);
  font-weight: 700;
}
.session-code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  color: var(--whiskey);
  font-size: 0.8rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 360px;
}
.btn-copy-ref {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border-radius: 6px;
  background: var(--ink-2);
  border: 1px solid var(--hide);
  color: var(--paper);
  font-size: 0.75rem;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s ease;
  flex-shrink: 0;
}
.btn-copy-ref:hover {
  border-color: var(--whiskey);
  color: var(--whiskey);
  background: var(--ink-3);
}

/* Timeline Tracker inside Receipt Card */
.thank-you-timeline {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-top: 20px;
  border-top: 1px solid var(--hide);
  gap: 8px;
}
.thank-you-timeline .timeline-step {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 0 0 auto;
}
.thank-you-timeline .timeline-marker {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.75rem;
  font-weight: 700;
  background: var(--ink-1);
  border: 1.5px solid var(--hide);
  color: var(--paper-dim);
  flex-shrink: 0;
}
.thank-you-timeline .step-complete .timeline-marker {
  background: var(--whiskey);
  border-color: var(--whiskey);
  color: var(--ink);
}
.thank-you-timeline .step-current .timeline-marker {
  border-color: var(--whiskey);
  background: oklch(from var(--whiskey) l c h / 0.15);
  color: var(--whiskey);
  box-shadow: 0 0 12px oklch(from var(--whiskey) l c h / 0.35);
}
.thank-you-timeline .timeline-title {
  font-size: 0.82rem;
  font-weight: 700;
  display: block;
  color: var(--paper);
}
.thank-you-timeline .timeline-sub {
  font-size: 0.72rem;
  color: var(--paper-dim);
  display: block;
}
.thank-you-timeline .timeline-line {
  flex: 1 1 auto;
  height: 2px;
  background: var(--hide);
  margin: 0 6px;
}
.thank-you-timeline .timeline-line.complete {
  background: var(--whiskey);
}

.thank-you-actions-wrap {
  margin: 0 auto;
  max-width: 580px;
}
.thank-you-actions {
  display: flex;
  justify-content: center;
  gap: 14px;
  margin: 0 auto;
  flex-wrap: wrap;
}
.thank-you-sub-actions {
  margin-top: 14px;
  text-align: center;
}
.thank-you-home-link {
  font-size: 0.88rem;
  color: var(--paper-dim);
  text-decoration: none;
  font-weight: 500;
  transition: color 0.2s ease;
}
.thank-you-home-link:hover {
  color: var(--whiskey);
  text-decoration: underline;
}

.thank-you-support-callout {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 24px auto 0;
  padding: 14px 20px;
  background: var(--ink-2);
  border: 1px solid var(--hide);
  border-radius: var(--radius, 10px);
  text-align: left;
  font-size: 0.86rem;
  color: var(--paper-dim);
  max-width: 580px;
}
.thank-you-support-callout .support-callout-icon {
  font-size: 1.25rem;
  color: var(--whiskey);
  flex-shrink: 0;
  display: flex;
  align-items: center;
}
.thank-you-support-callout p {
  margin: 0;
  line-height: 1.5;
}
.thank-you-support-callout a {
  color: var(--whiskey);
  text-decoration: underline;
}
.thank-you-support-callout a:hover {
  color: var(--paper);
}

@media (max-width: 600px) {
  .thank-you-hero {
    padding: 32px 0 44px;
  }
  .thank-you-card {
    padding: 20px 18px;
  }
  .session-code {
    /* On a phone, wrap the reference instead of cutting it to 22
       characters: the shopper may need to read it to support, and the Copy
       button handles the rest. */
    max-width: none;
    white-space: normal;
    word-break: break-all;
  }
  .thank-you-timeline {
    position: relative;
    flex-direction: column;
    align-items: flex-start;
    gap: 16px;
    padding-left: 6px;
  }
  .thank-you-timeline::before {
    content: "";
    position: absolute;
    left: 20px;
    top: 24px;
    bottom: 24px;
    width: 2px;
    background: var(--hide);
    z-index: 1;
  }
  .thank-you-timeline .timeline-step {
    position: relative;
    z-index: 2;
    gap: 12px;
  }
  .thank-you-timeline .timeline-line {
    display: none;
  }
  .thank-you-actions {
    flex-direction: column;
    width: 100%;
  }
  .thank-you-actions .btn {
    width: 100%;
    justify-content: center;
  }
}

/* ── Order Status Modal & Timeline (SOTA 2026) ────── */
.order-status-modal {
  max-width: 620px;
}
.order-status-form .field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.order-status-form input {
  width: 100%;
  padding: 11px 14px;
  background: var(--ink-3);
  border: 1px solid var(--hide);
  border-radius: var(--radius, 8px);
  color: var(--paper);
  font-size: 0.92rem;
}
.order-status-form input:focus {
  outline: none;
  border-color: var(--whiskey);
  box-shadow: 0 0 0 3px oklch(from var(--whiskey) l c h / 0.15);
}

.timeline-step {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  position: relative;
  z-index: 2;
}
.timeline-step .step-icon {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--ink-2);
  border: 1.5px solid var(--hide);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--paper-dim);
  flex-shrink: 0;
}
.timeline-step.step-done .step-icon {
  background: var(--success, #5ca86c);
  border-color: var(--success, #5ca86c);
  color: #fff;
}
.timeline-step.step-active .step-icon {
  border-color: var(--whiskey);
  background: oklch(from var(--whiskey) l c h / 0.15);
  color: var(--whiskey);
  box-shadow: 0 0 10px oklch(from var(--whiskey) l c h / 0.4);
}
.timeline-step .step-text {
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.timeline-step .step-text strong {
  font-size: 0.88rem;
  color: var(--paper);
}
.timeline-step .step-text span {
  font-size: 0.76rem;
  color: var(--paper-dim);
}

/* ==========================================================================
   Milestone 3: Product Detail Pages (PDP) & Merchandising Enhancements
   ========================================================================== */

/* PDP Layout & Container */
.pdp-page {
  background: var(--ink);
  color: var(--paper);
  min-height: 100vh;
}

.pdp-container {
  padding: 2rem 1.5rem 4rem;
  max-width: 1100px;
  margin: 0 auto;
}

.breadcrumb-nav {
  margin-bottom: 1.5rem;
}

.breadcrumb-nav .breadcrumb {
  font-size: 0.85rem;
  color: var(--paper-dim);
}

.breadcrumb-nav .breadcrumb a {
  color: var(--whiskey);
  text-decoration: underline;
}

.breadcrumb-nav .breadcrumb a:hover {
  text-decoration: underline;
}

.pdp-layout {
  display: grid;
  grid-template-columns: 1fr 1.15fr;
  gap: 2.5rem;
  align-items: start;
  background: var(--ink-2);
  border: 1px solid var(--hide);
  border-radius: var(--radius-lg);
  padding: 2rem;
  box-shadow: var(--shadow);
}

@media (max-width: 820px) {
  .pdp-layout {
    grid-template-columns: minmax(0, 1fr);
    gap: 1.5rem;
    padding: 1.25rem;
  }
}

.pdp-gallery {
  position: relative;
  min-width: 0;
}

.pdp-main-image {
  width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: var(--radius-md);
  border: 1px solid var(--hide);
  box-shadow: var(--shadow);
  display: block;
}

.pdp-details {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  min-width: 0;
}

.pdp-details .eyebrow {
  color: var(--whiskey);
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-weight: 700;
}

.pdp-title {
  font-family: var(--font-heading);
  font-size: 1.85rem;
  line-height: 1.2;
  margin: 0;
  color: var(--paper);
}

.pdp-price-row {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
}

.pdp-price {
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--whiskey);
}

:root[data-theme="light"] .pdp-price {
  color: var(--whiskey-dim);
}

.pdp-price-row .original-price {
  font-size: 1.1rem;
  color: var(--paper-dim);
  text-decoration: line-through;
}

.pdp-blurb {
  font-size: 0.98rem;
  line-height: 1.6;
  color: var(--paper-dim);
  margin: 0;
}

/* Small-Batch Freshness Trust Badge */
.pdp-freshness-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px;
  background: oklch(from var(--whiskey) l c h / 0.12);
  border: 1px solid oklch(from var(--whiskey) l c h / 0.35);
  border-radius: var(--radius-full);
  color: var(--whiskey);
  font-size: 0.82rem;
  font-weight: 600;
  width: fit-content;
}

:root[data-theme="light"] .pdp-freshness-badge {
  color: var(--whiskey-dim);
  border-color: oklch(from var(--whiskey-dim) l c h / 0.4);
  background: oklch(from var(--whiskey-dim) l c h / 0.1);
}

.pdp-freshness-icon {
  flex-shrink: 0;
  stroke: currentColor;
}

/* Scent Profile & Notes */
.pdp-scent-profile {
  background: var(--ink-3);
  border: 1px solid var(--hide);
  border-radius: var(--radius-md);
  padding: 1.25rem;
}

.pdp-scent-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 0.85rem;
  padding-bottom: 0.6rem;
  border-bottom: 1px solid var(--hide);
}

.pdp-section-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1.1rem;
  color: var(--paper);
}

.pdp-intensity-bar {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 0.8rem;
  color: var(--paper-dim);
  background: var(--ink-2);
  padding: 4px 10px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--hide);
}

.pdp-intensity-bar strong {
  color: var(--whiskey);
}

:root[data-theme="light"] .pdp-intensity-bar strong {
  color: var(--whiskey-dim);
}

.intensity-meter {
  display: inline-block;
  width: 50px;
  height: 6px;
  background: var(--ink-1);
  border-radius: 3px;
  overflow: hidden;
  vertical-align: middle;
}

.intensity-fill {
  display: block;
  height: 100%;
  background: var(--whiskey);
  border-radius: 3px;
}

:root[data-theme="light"] .intensity-fill {
  background: var(--whiskey-dim);
}

.scent-notes-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 10px;
}

.scent-note-card {
  background: var(--ink-2);
  border: 1px solid var(--hide);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
}

.scent-note-card .note-label {
  display: block;
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 700;
  color: var(--whiskey);
  margin-bottom: 4px;
}

:root[data-theme="light"] .scent-note-card .note-label {
  color: var(--whiskey-dim);
}

.scent-note-card .note-desc {
  margin: 0;
  font-size: 0.85rem;
  color: var(--paper);
  line-height: 1.35;
}

.pdp-scent-unscented-note {
  margin: 0;
  font-size: 0.88rem;
  color: var(--paper-dim);
  line-height: 1.5;
}

/* Ingredients Block */
.pdp-ingredients-block {
  background: var(--ink-3);
  border: 1px solid var(--hide);
  border-radius: var(--radius-md);
  padding: 1.25rem;
}

.pdp-ingredients-list {
  margin: 0.5rem 0 0;
  padding-left: 1.25rem;
  color: var(--paper-dim);
  font-size: 0.88rem;
  line-height: 1.5;
}

.pdp-ingredients-note {
  margin: 0.5rem 0 0;
  color: var(--paper-muted);
}

/* Expandable Usage Accordions */
.pdp-accordions-group {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0.5rem 0;
}

.pdp-accordion {
  background: var(--ink-3);
  border: 1px solid var(--hide);
  border-radius: var(--radius-md);
  overflow: hidden;
  transition:
    border-color 0.2s ease,
    box-shadow 0.2s ease;
}

.pdp-accordion:hover,
.pdp-accordion:has(:focus-visible) {
  border-color: var(--whiskey);
}

.pdp-accordion-summary {
  cursor: pointer;
  color: var(--paper);
  font-weight: 600;
  font-size: 0.92rem;
  list-style: none;
  padding: 12px 16px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  user-select: none;
}

.pdp-accordion-summary::-webkit-details-marker {
  display: none;
}

.pdp-accordion-summary::after {
  content: "+";
  color: var(--whiskey);
  font-size: 1.2rem;
  font-weight: 400;
  transition: transform 0.2s ease;
}

:root[data-theme="light"] .pdp-accordion-summary::after {
  color: var(--whiskey-dim);
}

.pdp-accordion[open] .pdp-accordion-summary::after {
  transform: rotate(45deg);
}

.pdp-accordion-content {
  padding: 0 16px 14px;
  color: var(--paper-dim);
  font-size: 0.88rem;
  line-height: 1.55;
}

.pdp-accordion-content p {
  margin: 0;
}

/* PDP Call to Action */
.pdp-actions {
  margin-top: 0.5rem;
}

.pdp-cta-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  padding: 14px 20px;
  font-size: 1rem;
  font-weight: 700;
}

/* ==========================================================================
   Milestone 4: Apothecary Journal & Content Hub Enhancements
   ========================================================================== */

/* Reading Time & Metadata in Journal Cards */
.journal-card-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 0.5rem;
}

.journal-reading-time {
  font-size: 0.78rem;
  color: var(--paper-dim);
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-weight: 500;
}

.journal-clock-icon {
  flex-shrink: 0;
  stroke: var(--whiskey);
}

:root[data-theme="light"] .journal-clock-icon {
  stroke: var(--whiskey-dim);
}

/* Topical Tag Chips */
.journal-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0.6rem 0;
}

.journal-tag,
.journal-tag-pill {
  font-family: inherit;
  font-size: 0.72rem;
  padding: 3px 9px;
  background: rgba(214, 155, 92, 0.12);
  color: var(--whiskey);
  border: 1px solid rgba(214, 155, 92, 0.25);
  border-radius: var(--radius-full, 9999px);
  font-weight: 600;
  letter-spacing: 0.02em;
  cursor: pointer;
  transition:
    background 0.15s ease,
    border-color 0.15s ease,
    color 0.15s ease;
  line-height: 1.3;
  text-decoration: none;
  display: inline-block;
}

.journal-tag:hover,
.journal-tag:focus-visible {
  background: rgba(214, 155, 92, 0.25);
  border-color: var(--whiskey);
  color: var(--paper);
}

:root[data-theme="light"] .journal-tag,
:root[data-theme="light"] .journal-tag-pill {
  color: var(--whiskey-dim);
  background: rgba(138, 92, 48, 0.1);
  border-color: rgba(138, 92, 48, 0.2);
}

:root[data-theme="light"] .journal-tag:hover,
:root[data-theme="light"] .journal-tag:focus-visible {
  background: rgba(138, 92, 48, 0.18);
  border-color: var(--whiskey-dim);
  color: var(--paper);
}

/* Tag Filter Active Banner */
.journal-filter-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: var(--ink-2);
  border: 1px solid var(--hide);
  border-radius: var(--radius-md, 8px);
  padding: 10px 16px;
  margin-bottom: 1.5rem;
  font-size: 0.9rem;
  color: var(--paper);
}

.journal-filter-banner strong {
  color: var(--whiskey);
}

/* Journal Detail View Meta & Tags */
.journal-detail .meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  font-size: 0.9rem;
  color: var(--paper-dim);
  margin-bottom: 1rem;
}

.journal-meta-sep {
  color: var(--hide);
}

.journal-detail-tags {
  margin-bottom: 1.5rem;
}

/* Inline "Featured in this Article" Mini-Product Card */
.journal-featured-card {
  margin: 2.5rem 0 1.5rem;
  background: var(--ink-2);
  border: 1px solid rgba(214, 155, 92, 0.35);
  border-radius: var(--radius-lg, 12px);
  box-shadow: var(--shadow);
  overflow: hidden;
  transition:
    border-color 0.2s ease,
    box-shadow 0.2s ease;
}

.journal-featured-card:hover {
  border-color: var(--whiskey);
}

.journal-featured-inner {
  padding: 1.5rem;
}

.journal-featured-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 1rem;
  padding-bottom: 0.75rem;
  border-bottom: 1px solid var(--hide);
}

.journal-featured-pill {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 700;
  color: var(--whiskey);
}

:root[data-theme="light"] .journal-featured-pill {
  color: var(--whiskey-dim);
}

.journal-featured-header h4 {
  margin: 0;
  font-size: 0.85rem;
  color: var(--paper-dim);
  font-weight: 500;
}

.journal-featured-body {
  display: flex;
  gap: 1.25rem;
  align-items: center;
  flex-wrap: wrap;
}

.journal-featured-thumb {
  width: 96px;
  height: 96px;
  border-radius: var(--radius-md, 8px);
  object-fit: cover;
  border: 1px solid var(--hide);
  flex-shrink: 0;
}

.journal-featured-details {
  flex: 1 1 240px;
  min-width: 0;
}

.journal-featured-badges {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin-bottom: 4px;
}

.journal-featured-cat,
.journal-featured-scent {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 700;
  padding: 2px 7px;
  border-radius: var(--radius-sm, 4px);
  background: var(--ink-1, #120e0b);
  border: 1px solid var(--hide);
  color: var(--paper-dim);
}

.journal-featured-scent {
  color: var(--whiskey);
  border-color: rgba(214, 155, 92, 0.3);
}

:root[data-theme="light"] .journal-featured-scent {
  color: var(--whiskey-dim);
  border-color: rgba(138, 92, 48, 0.3);
}

.journal-featured-title {
  margin: 4px 0 6px;
  font-family: var(--font-heading, "Gloock", Georgia, serif);
  font-size: 1.25rem;
  line-height: 1.25;
}

.journal-featured-title a {
  color: var(--paper);
  text-decoration: none;
  transition: color 0.15s ease;
}

.journal-featured-title a:hover {
  color: var(--whiskey);
}

.journal-featured-blurb {
  font-size: 0.85rem;
  color: var(--paper-dim);
  margin: 0 0 12px;
  line-height: 1.45;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.journal-featured-action {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}

.journal-featured-price {
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--paper);
}

.journal-featured-action .btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 16px;
  font-size: 0.85rem;
  font-weight: 700;
}

/* =============== ORDER STATUS & PACKING SLIP (Milestone 6: R6) =============== */
.hero-order-status {
  padding: 56px 0 64px;
}

.order-status-header {
  margin-bottom: 32px;
}

.order-status-header h1 {
  margin: 8px 0 12px;
}

.order-lookup-card {
  background: var(--ink-2);
  border: 1px solid var(--hide);
  border-radius: var(--radius-lg);
  padding: 28px;
  margin-bottom: 32px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
}

.order-status-page-form .form-actions {
  margin-top: 16px;
}

.order-status-result-section {
  display: flex;
  flex-direction: column;
  gap: 28px;
  margin-top: 16px;
}

.order-actions-group .btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 16px;
  font-size: 0.88rem;
  font-weight: 600;
}

/* =============== PRINT MEDIA STYLES =============== */
@media print {
  body {
    background: #ffffff !important;
    color: #000000 !important;
    font-size: 11pt !important;
  }

  .site-header,
  .site-footer,
  .nav,
  .order-lookup-card,
  .order-items-container,
  .order-status-header,
  .hero-actions,
  .btn,
  .theme-toggle,
  .cart-toggle,
  .skip-link,
  #order-status-modal,
  #yl-cart-drawer,
  #yl-cart-backdrop,
  #sw-update-toast {
    display: none !important;
  }

  main,
  .section,
  .container {
    padding: 0 !important;
    margin: 0 !important;
    max-width: 100% !important;
  }

  .order-status-result-section {
    display: block !important;
  }
}

/* ==================== GLOBAL SEARCH SUITE (2026 SOTA) ==================== */
.nav-search-btn {
  position: relative;
  background: none;
  border: 1px solid var(--hide);
  color: var(--paper);
  width: 42px;
  height: 42px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  flex: 0 0 auto;
  padding: 0 !important;
  box-sizing: border-box !important;
  line-height: 1 !important;
  transition:
    transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1),
    border-color 0.2s ease,
    color 0.2s ease;
}

.nav-search-btn:hover,
.nav-search-btn:focus-visible {
  border-color: var(--whiskey);
  color: var(--whiskey);
  transform: scale(1.05);
  outline: none;
}

.nav-search-btn:focus-visible {
  box-shadow:
    0 0 0 2px var(--ink),
    0 0 0 4px var(--whiskey);
}

@media (max-width: 420px) {
  .nav-search-btn {
    width: 34px;
    height: 34px;
    flex-shrink: 0;
  }
}

.nav-search-btn svg {
  width: 19px;
  height: 19px;
}

/* --- Search Modal Dialog --- */
dialog.global-search-modal {
  display: none;
  position: fixed;
  inset: 0;
  margin: auto;
  border: none;
  padding: 0;
  background: transparent;
  width: min(680px, 94vw);
  max-width: 680px;
  max-height: min(85vh, 760px);
  z-index: 1000;
  color: var(--paper);
  box-sizing: border-box;
}

dialog.global-search-modal[open] {
  display: flex;
  flex-direction: column;
  animation: searchModalFadeIn 0.2s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

@keyframes searchModalFadeIn {
  from {
    opacity: 0;
    transform: translateY(-8px) scale(0.98);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

dialog.global-search-modal::backdrop {
  background: rgba(10, 8, 6, 0.78);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}

:root[data-theme="light"] dialog.global-search-modal::backdrop {
  background: rgba(40, 30, 20, 0.45);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}

.global-search-container {
  display: flex;
  flex-direction: column;
  background: var(--ink-2);
  border: 1px solid var(--hide);
  border-radius: var(--radius-lg, 16px);
  box-shadow: 0 24px 64px rgba(0, 0, 0, 0.65);
  overflow: hidden;
  width: 100%;
}

/* --- Modal Header / Search Bar --- */
.global-search-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1px solid var(--hide);
  padding: 8px 16px;
  background: var(--ink-2);
  gap: 10px;
}

.global-search-input-wrapper {
  display: flex;
  align-items: center;
  flex: 1 1 auto;
  gap: 12px;
  position: relative;
}

.global-search-icon {
  color: var(--paper-dim);
  flex-shrink: 0;
}

.global-search-input {
  width: 100%;
  border: none;
  outline: none;
  background: transparent;
  font-family: var(--font-sans, inherit);
  font-size: 1.1rem;
  color: var(--paper);
  padding: 12px 0;
}
/* The dialog has its own clear and close buttons; WebKit's built-in cancel
   "x" on type=search made three of them in a row once you typed. */
.global-search-input::-webkit-search-cancel-button,
.global-search-input::-webkit-search-decoration {
  -webkit-appearance: none;
  appearance: none;
  display: none;
}

.global-search-input::placeholder {
  color: var(--paper-dim);
  opacity: 0.75;
}

.global-search-clear-btn {
  background: none;
  border: none;
  color: var(--paper-dim);
  cursor: pointer;
  padding: 6px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  transition:
    color 0.15s ease,
    transform 0.15s ease;
}

.global-search-clear-btn:hover {
  color: var(--paper);
  transform: scale(1.1);
}

.global-search-close-btn {
  background: none;
  border: none;
  color: var(--paper-dim);
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  padding: 6px 10px;
  border-radius: 6px;
  transition:
    color 0.15s ease,
    transform 0.15s ease;
}

.global-search-close-btn:hover {
  color: var(--whiskey);
  transform: scale(1.1);
}

/* --- Popular Search Quick Chips --- */
.global-search-chips-section {
  padding: 14px 20px;
  border-bottom: 1px solid var(--hide);
  background: var(--ink-2);
}

.global-search-chips-title {
  font-family: var(--font-heading, serif);
  text-transform: uppercase;
  font-size: 0.75rem;
  letter-spacing: 1px;
  color: var(--whiskey);
  margin: 0 0 10px 0;
  font-weight: 600;
}

.global-search-chips-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.search-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 14px;
  border-radius: 999px;
  font-size: 0.84rem;
  font-family: var(--font-sans, inherit);
  background: var(--ink-3);
  border: 1px solid var(--hide);
  color: var(--paper);
  cursor: pointer;
  transition:
    transform 0.15s ease,
    border-color 0.15s ease,
    background 0.15s ease,
    color 0.15s ease;
}

.search-chip:hover,
.search-chip:focus-visible {
  transform: translateY(-2px);
  border-color: var(--whiskey);
  background: oklch(from var(--whiskey) l c h / 0.15);
  color: var(--whiskey);
  outline: none;
}

/* --- Results Listbox & Sections --- */
.global-search-results-wrapper {
  max-height: min(56vh, 480px);
  overflow-y: auto;
  overscroll-behavior: contain;
}

.global-search-results-wrapper::-webkit-scrollbar {
  width: 6px;
}

.global-search-results-wrapper::-webkit-scrollbar-track {
  background: var(--ink-2);
}

.global-search-results-wrapper::-webkit-scrollbar-thumb {
  background: var(--hide);
  border-radius: 3px;
}

.search-results-section {
  display: flex;
  flex-direction: column;
}

.search-section-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 9px 20px;
  background: var(--ink-3);
  border-top: 1px solid var(--hide);
  border-bottom: 1px solid var(--hide);
  font-family: var(--font-heading, serif);
  font-size: 0.85rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.75px;
  color: var(--whiskey);
}

.search-results-section:first-child .search-section-header {
  border-top: none;
}

.search-section-count {
  background: var(--ink-2);
  border: 1px solid var(--hide);
  color: var(--paper-dim);
  font-size: 0.72rem;
  padding: 2px 8px;
  border-radius: 999px;
  font-family: var(--font-sans, inherit);
  font-weight: 600;
}

/* --- Result Item Rows --- */
.search-result-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 12px 20px;
  border-bottom: 1px solid var(--hide);
  cursor: pointer;
  text-decoration: none;
  color: inherit;
  transition:
    background 0.15s ease,
    border-left-color 0.15s ease;
  border-left: 3px solid transparent;
}

.search-result-item:last-child {
  border-bottom: none;
}

.search-result-item:hover,
.search-result-item.is-selected {
  background: var(--ink-3);
  border-left-color: var(--whiskey);
  outline: none;
}

/* The ARIA grid cell that wraps the row's main link (see setResultsGridRole()
   in main.js). Purely structural -- it inherits the flex behaviour the link
   used to have directly, so the row looks byte-identical to before. */
.search-item-cell {
  display: flex;
  align-items: center;
  flex: 1 1 auto;
  min-width: 0;
}

.search-item-main {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: 1 1 auto;
  min-width: 0;
  text-decoration: none;
  color: inherit;
}

.search-item-thumb {
  width: 52px;
  height: 52px;
  border-radius: 8px;
  object-fit: cover;
  border: 1px solid var(--hide);
  flex-shrink: 0;
  background: var(--ink-3);
}

.search-event-badge {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-width: 52px;
  height: 52px;
  background: var(--ink-3);
  border: 1px solid var(--whiskey);
  border-radius: 8px;
  color: var(--whiskey);
  font-weight: 700;
  font-size: 0.72rem;
  text-align: center;
  flex-shrink: 0;
  line-height: 1.2;
  padding: 2px;
}

.search-faq-icon {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--ink-3);
  border: 1px solid var(--hide);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--whiskey);
  font-weight: 700;
  flex-shrink: 0;
  font-size: 1.1rem;
}

.search-item-info {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.search-item-title {
  font-weight: 600;
  font-size: 0.94rem;
  color: var(--paper);
  margin: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.search-item-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.84rem;
  flex-wrap: wrap;
}

.search-item-price {
  color: var(--whiskey);
  font-weight: 700;
}

/* Search results only: the three status chips (in-stock / out-of-stock /
   coming-soon) share one compact, vertically-centred size so they line up
   with the price. Scoped to the modal because .coming-soon is also the PDP
   header badge, which keeps the larger .stock-badge pill there. */
.search-item-meta .stock-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  line-height: 1;
  font-size: 0.62rem;
  padding: 2px 6px;
  margin: 0;
  border-radius: 3px;
  letter-spacing: 0.02em;
  vertical-align: middle;
}

.stock-badge.in-stock {
  background: rgba(92, 168, 108, 0.15);
  /* --sage-strong, not --sage: see the token's comment at the top of this
     file. This is the only badge in the shop that was failing contrast. */
  color: var(--sage-strong);
  border: 1px solid var(--sage-strong);
  font-weight: 600;
}

.stock-badge.out-of-stock {
  background: rgba(209, 59, 59, 0.15);
  color: var(--error);
  border: 1px solid var(--error);
  font-weight: 600;
}

.search-tag-pill {
  display: inline-block;
  font-size: 0.7rem;
  padding: 1px 6px;
  border-radius: 4px;
  background: var(--ink-3);
  border: 1px solid var(--hide);
  color: var(--paper-dim);
}

.search-item-blurb {
  font-size: 0.8rem;
  color: var(--paper-dim);
  margin: 0;
  line-height: 1.35;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.search-item-action {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  flex-shrink: 0;
  min-width: 72px;
}

.search-variant-picker {
  display: none;
  align-items: center;
  gap: 6px;
  justify-content: flex-end;
}

.search-item-action.is-expanded .search-variant-trigger {
  display: none;
}

.search-item-action.is-expanded .search-variant-picker,
.search-variant-picker:not([hidden]) {
  display: flex;
  animation: variantPickerFadeIn 0.18s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

@keyframes variantPickerFadeIn {
  from {
    opacity: 0;
    transform: scale(0.96);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

.search-variant-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  justify-content: flex-end;
  align-items: center;
  max-width: 320px;
}

.search-variant-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 4px 10px;
  border-radius: var(--radius-pill, 999px);
  border: 1px solid var(--hide);
  background: var(--ink-3);
  color: var(--paper);
  font-family: var(--font-sans, inherit);
  font-size: 0.74rem;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  line-height: 1.2;
  transition:
    transform 0.15s ease,
    border-color 0.15s ease,
    background 0.15s ease,
    color 0.15s ease,
    box-shadow 0.15s ease;
}

.search-variant-chip:hover:not([disabled]):not(.is-sold-out),
.search-variant-chip:focus-visible:not([disabled]):not(.is-sold-out) {
  transform: translateY(-1px);
  border-color: var(--whiskey);
  background: rgba(214, 155, 92, 0.18);
  color: var(--whiskey);
  box-shadow: 0 0 0 2px rgba(214, 155, 92, 0.35);
  outline: none;
}

.search-variant-chip[aria-checked="true"] {
  border-color: var(--whiskey);
  background: var(--whiskey);
  color: var(--ink);
}

.search-variant-chip.is-sold-out,
.search-variant-chip[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
  text-decoration: line-through;
  border-color: var(--hide);
  background: var(--ink-2);
  color: var(--paper-dim);
}

/* A gift set needs one radiogroup per variant-bearing member, so its picker
   stacks instead of sitting on one line (live audit C1). */
.search-bundle-picker.search-variant-picker:not([hidden]),
.search-item-action.is-expanded .search-bundle-picker {
  flex-direction: column;
  align-items: flex-end;
  gap: 6px;
}

.search-variant-group {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 3px;
}

.search-variant-group-label {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--paper-dim);
}

.search-bundle-hint {
  margin: 0;
  font-size: 0.72rem;
  color: var(--whiskey);
  text-align: right;
}

.search-variant-chip.is-added {
  background: var(--success);
  color: #ffffff;
  border-color: var(--success);
  transform: scale(1.03);
}

@media (max-width: 600px) {
  .search-result-item {
    flex-wrap: wrap;
    gap: 8px;
  }
  .search-item-action {
    width: 100%;
    justify-content: flex-start;
    margin-top: 4px;
  }
  .search-variant-picker {
    max-width: 100%;
    width: 100%;
    justify-content: flex-start;
  }
  .search-variant-chips {
    max-width: 100%;
    justify-content: flex-start;
  }
}

.search-add-btn {
  background: var(--whiskey);
  color: var(--ink);
  border: none;
  border-radius: 6px;
  padding: 6px 12px;
  font-size: 0.8rem;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  transition:
    transform 0.15s ease,
    background 0.15s ease;
}

.search-add-btn:hover {
  transform: scale(1.04);
  background: var(--paper);
}

.search-add-btn.is-added {
  background: var(--success);
  color: #ffffff;
}

/* --- Empty / No Results State --- */
.search-empty-state {
  padding: 36px 20px;
  text-align: center;
  color: var(--paper-dim);
}

.search-empty-icon {
  font-size: 2rem;
  margin-bottom: 8px;
}

.search-empty-title {
  font-family: var(--font-heading, serif);
  font-size: 1.25rem;
  color: var(--paper);
  margin: 0 0 6px 0;
}

.search-empty-text {
  font-size: 0.88rem;
  line-height: 1.45;
  max-width: 440px;
  margin: 0 auto 16px;
}

.search-empty-suggestions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
}

/* --- Modal Footer / Keyboard Shortcut Hints --- */
.global-search-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 20px;
  background: var(--ink-3);
  border-top: 1px solid var(--hide);
  font-size: 0.75rem;
  color: var(--paper-dim);
}

/* "↑ ↓ Navigate · ↵ Select · ESC Close" names keys a touch build does not
   have (live audit L6), and the footer holds nothing else. A laptop with a
   touchscreen still reports a fine PRIMARY pointer, so it keeps them. Must
   come after the rule above: same specificity, later wins. */
@media (pointer: coarse) {
  .global-search-footer {
    display: none;
  }
}

.search-key-hint {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.search-key-hint kbd {
  background: var(--ink-2);
  border: 1px solid var(--hide);
  border-radius: 4px;
  padding: 2px 5px;
  font-size: 0.7rem;
  color: var(--whiskey);
  font-family: monospace;
}

@media print {
  #global-search-modal,
  .nav-search-btn {
    display: none !important;
  }
}

/* ── Recently Viewed Products Carousel (R4) ── */
.recently-viewed-section {
  position: relative;
  margin-top: 2.5rem;
  margin-bottom: 2.5rem;
}

.recently-viewed-track {
  display: flex;
  gap: 1rem;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  -webkit-overflow-scrolling: touch;
  padding: 0.5rem 0.25rem 1rem;
  scrollbar-width: thin;
  scrollbar-color: var(--whiskey) transparent;
}

.recently-viewed-track::-webkit-scrollbar {
  height: 6px;
}

.recently-viewed-track::-webkit-scrollbar-track {
  background: transparent;
}

.recently-viewed-track::-webkit-scrollbar-thumb {
  background: var(--hide);
  border-radius: 4px;
}

.recently-viewed-track:focus-visible {
  outline: 2px solid var(--whiskey);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

.recently-viewed-card {
  scroll-snap-align: start;
  flex: 0 0 240px;
  max-width: 240px;
  background: var(--ink-1);
  border: 1px solid var(--hide);
  border-radius: var(--radius-md);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition:
    transform 0.2s ease,
    border-color 0.2s ease,
    box-shadow 0.2s ease;
}

.recently-viewed-card:hover {
  transform: translateY(-2px);
  border-color: var(--whiskey);
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.3);
}

.recently-viewed-media {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  background: var(--ink-2);
  overflow: hidden;
}

.recently-viewed-media a {
  display: block;
  width: 100%;
  height: 100%;
}

.recently-viewed-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.3s ease;
}

.recently-viewed-card:hover .recently-viewed-img {
  transform: scale(1.03);
}

.recently-viewed-body {
  padding: 0.85rem 1rem 1rem;
  display: flex;
  flex-direction: column;
  flex: 1;
}

.recently-viewed-cat {
  display: inline-block;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--whiskey);
  margin-bottom: 0.35rem;
}

.recently-viewed-title {
  font-size: 0.95rem;
  font-family: var(--font-heading, serif);
  font-weight: 600;
  line-height: 1.3;
  margin: 0 0 0.5rem 0;
  color: var(--paper);
}

.recently-viewed-title a {
  color: inherit;
  text-decoration: none;
  transition: color 0.15s ease;
}

.recently-viewed-title a:hover,
.recently-viewed-title a:focus-visible {
  color: var(--whiskey);
  text-decoration: underline;
}

.recently-viewed-foot {
  margin-top: auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--ink-2);
}

.recently-viewed-foot .price {
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--paper);
}

.recently-viewed-btn {
  font-size: 0.78rem;
  padding: 4px 10px;
  min-height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

@media (max-width: 600px) {
  .recently-viewed-card {
    flex: 0 0 190px;
    max-width: 190px;
  }
  .recently-viewed-body {
    padding: 0.7rem 0.75rem 0.85rem;
  }
  .recently-viewed-title {
    font-size: 0.88rem;
  }
}

/* ==========================================================================
   Milestone 4 / R2: "Complete the Ritual" Smart Cross-Sells
   ========================================================================== */
.pdp-ritual-section {
  margin-top: 3.5rem;
  padding-top: 2.5rem;
  border-top: 1px solid var(--hide);
}

.pdp-ritual-header {
  margin-bottom: 1.25rem;
}

.pdp-ritual-header .eyebrow {
  color: var(--whiskey);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-weight: 700;
  display: inline-block;
  margin-bottom: 0.25rem;
}

.pdp-ritual-title {
  font-family: var(--font-heading, serif);
  font-size: 1.55rem;
  margin: 0.25rem 0 0.4rem 0;
  color: var(--paper);
  line-height: 1.25;
}

.pdp-ritual-sub {
  color: var(--paper-dim);
  margin: 0;
  font-size: 0.92rem;
  line-height: 1.4;
}

.pdp-ritual-card {
  background: var(--ink-2);
  border: 1px solid oklch(from var(--whiskey) l c h / 0.3);
  border-radius: var(--radius-lg, 12px);
  padding: 1.5rem;
  box-shadow: var(--shadow);
}

.pdp-ritual-items-grid {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 1.5rem;
}

.pdp-ritual-plus {
  font-size: 1.4rem;
  font-weight: 400;
  color: var(--whiskey);
  padding: 0 4px;
  user-select: none;
}

.pdp-ritual-item {
  display: flex;
  align-items: center;
  gap: 12px;
  background: var(--ink-3, rgba(255, 255, 255, 0.04));
  border: 1px solid var(--border-color, var(--hide));
  border-radius: var(--radius-md, 8px);
  padding: 10px 14px;
  cursor: pointer;
  flex: 1 1 200px;
  min-width: 180px;
  min-height: 48px;
  transition:
    border-color 0.2s ease,
    background-color 0.2s ease,
    opacity 0.2s ease;
  user-select: none;
}

.pdp-ritual-item:hover {
  border-color: var(--whiskey);
}

.pdp-ritual-item.is-checked {
  border-color: oklch(from var(--whiskey) l c h / 0.6);
  background: var(--ink-2);
}

.pdp-ritual-checkbox {
  accent-color: var(--whiskey);
  width: 24px;
  height: 24px;
  min-width: 24px;
  min-height: 24px;
  cursor: pointer;
}

.pdp-ritual-item-thumb {
  flex-shrink: 0;
}

/* The ritual and sticky-bar thumbnails are <picture> elements now (they used
   to be bare <img> tags pointing at the full-size product JPEG -- live audit
   2026-09-02, H-2). `display: contents` keeps the <img> itself as the box the
   rules below and the flex parent see, so nothing about the layout moved. */
.pdp-ritual-item-thumb picture,
.pdp-sticky-inner picture {
  display: contents;
}

.pdp-ritual-item-thumb img {
  width: 54px;
  height: 54px;
  object-fit: cover;
  border-radius: var(--radius-sm, 6px);
  border: 1px solid var(--hide);
  display: block;
}

.pdp-ritual-item-details {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.pdp-ritual-item-tag {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--whiskey);
  font-weight: 700;
  margin-bottom: 2px;
}

.pdp-ritual-item-name {
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--paper);
  line-height: 1.25;
  text-decoration: none;
}

a.pdp-ritual-item-name:hover,
a.pdp-ritual-item-name:focus-visible {
  color: var(--whiskey);
  text-decoration: underline;
}

.pdp-ritual-item-price {
  font-size: 0.88rem;
  font-weight: 700;
  color: var(--paper-dim);
  margin-top: 2px;
}

.pdp-ritual-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 16px;
  padding-top: 1.25rem;
  border-top: 1px solid var(--hide);
}

.pdp-ritual-total-wrap {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
}

.pdp-ritual-total-label {
  font-size: 0.95rem;
  color: var(--paper-dim);
  font-weight: 600;
}

.pdp-ritual-total-price {
  font-size: 1.4rem;
  font-weight: 700;
  color: var(--whiskey);
}

/* main.js toggles the `hidden` attribute; the display rule below would
   otherwise beat it and the "Unlocks Free Tracked Shipping!" badge stayed
   on screen for ritual totals under the threshold. */
/* A product card's Add to Cart is a primary touch target on a phone. */
@media (max-width: 768px) {
  .card .yl-add-item {
    min-height: 44px;
  }
}
/* Landing on shop.html#<product-id> (every generated product page
   redirects there) scrolls the card into view and marks it for a moment. */
.card.is-deep-linked {
  outline: 2px solid var(--whiskey);
  outline-offset: 4px;
  transition: outline-color 0.6s ease;
}
.pdp-ritual-shipping-badge[hidden] {
  display: none !important;
}
.pdp-ritual-shipping-badge {
  font-size: 0.82rem;
  color: #4ade80;
  font-weight: 600;
  background: rgba(74, 222, 128, 0.12);
  border: 1px solid rgba(74, 222, 128, 0.25);
  padding: 3px 8px;
  border-radius: var(--radius-sm, 6px);
  display: inline-flex;
  align-items: center;
}

:root[data-theme="light"] .pdp-ritual-shipping-badge {
  color: #14532d;
  background: rgba(20, 83, 45, 0.08);
  border-color: rgba(20, 83, 45, 0.25);
}

.pdp-ritual-add-btn {
  min-height: 48px;
  padding: 0 22px;
  font-size: 0.96rem;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  cursor: pointer;
}

.pdp-ritual-add-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Compact Modal Ritual Variant */
.lightbox-ritual-wrap {
  margin-top: 1.25rem;
  width: 100%;
  max-width: 600px;
}

.pdp-ritual-compact {
  margin-top: 0;
  padding-top: 0;
  border-top: none;
}

.pdp-ritual-compact .pdp-ritual-card {
  padding: 1rem;
}

.pdp-ritual-compact .pdp-ritual-title {
  font-size: 1.15rem;
}

.pdp-ritual-compact .pdp-ritual-item {
  padding: 8px 10px;
  min-width: 140px;
}

.pdp-ritual-compact .pdp-ritual-item-thumb img {
  width: 44px;
  height: 44px;
}

.pdp-ritual-compact .pdp-ritual-total-price {
  font-size: 1.15rem;
}

@media (max-width: 600px) {
  .pdp-ritual-items-grid {
    flex-direction: column;
    align-items: stretch;
  }
  .pdp-ritual-plus {
    text-align: center;
    padding: 2px 0;
  }
  .pdp-ritual-footer {
    flex-direction: column;
    align-items: stretch;
  }
  .pdp-ritual-add-btn {
    width: 100%;
  }
}

/* ==========================================================================
   R1: Mobile Sticky Add-to-Cart Bottom Bar on PDPs
   ========================================================================== */
.pdp-sticky-bar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  width: 100%;
  /* Page chrome, not an overlay -- see the Z-INDEX BANDS block at the top of
     this file. At 950 this bar painted OVER every overlay that is supposed to
     cover the page: the mobile nav drawer (99), the wishlist backdrop and
     drawer (198/199) and the skip link (200). On a phone -- the only width
     where this bar shows at all -- opening the nav or the wishlist left a
     full-width Add-to-Cart bar floating on top of the panel. 90 puts it below
     every one of them and still above all in-flow content. */
  z-index: 90;
  background: var(--ink-2, #181513);
  border-top: 1px solid var(--hide, #3a322d);
  box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.45);
  padding: 10px 14px max(10px, env(safe-area-inset-bottom, 10px));
  transform: translateY(100%);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition:
    transform 0.3s cubic-bezier(0.16, 1, 0.3, 1),
    opacity 0.25s ease,
    visibility 0.3s;
}

.pdp-sticky-bar.is-visible {
  transform: translateY(0);
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
}

@media (min-width: 768px) {
  .pdp-sticky-bar {
    display: none !important;
  }
}

.pdp-sticky-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  max-width: 600px;
  margin: 0 auto;
}

.pdp-sticky-thumb {
  width: 44px;
  height: 44px;
  min-width: 44px;
  border-radius: var(--radius-sm, 6px);
  object-fit: cover;
  border: 1px solid var(--hide, #3a322d);
  flex-shrink: 0;
}

.pdp-sticky-info {
  display: flex;
  flex-direction: column;
  min-width: 0;
  flex: 1 1 auto;
  overflow: hidden;
}

.pdp-sticky-title {
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--paper, #f5efe6);
  margin: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: 1.25;
}

.pdp-sticky-price {
  font-size: 0.88rem;
  font-weight: 700;
  color: var(--whiskey, #e08a3c);
  margin: 2px 0 0;
  line-height: 1.2;
}

:root[data-theme="light"] .pdp-sticky-price {
  color: var(--whiskey-dim, #b8651b);
}

.pdp-sticky-variant-wrap {
  flex-shrink: 0;
}

.pdp-sticky-variant-select {
  min-height: 44px;
  padding: 0 8px;
  font-size: 0.82rem;
  background: var(--ink-3, #24201c);
  color: var(--paper, #f5efe6);
  border: 1px solid var(--border-color, #4a4039);
  border-radius: var(--radius-sm, 6px);
  max-width: 110px;
  cursor: pointer;
}

.pdp-sticky-add-btn {
  min-height: 44px;
  min-width: 44px;
  padding: 0 14px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 0.88rem;
  white-space: nowrap;
  flex-shrink: 0;
  cursor: pointer;
}

@media (max-width: 767px) {
  body.pdp-page {
    padding-bottom: 72px;
  }
}

/* ==========================================================================
   Milestone 2: Announcement Accent Themes & Merchandising Badges
   ========================================================================== */
.announcement-accent-whiskey,
#yl-countdown-ticker.announcement-accent-whiskey {
  background-color: var(--whiskey, #e08a3c);
  color: var(--ink, #120f0d);
}
[data-theme="dark"] .announcement-accent-whiskey,
[data-theme="dark"] #yl-countdown-ticker.announcement-accent-whiskey {
  background-color: #d69b5c;
  color: #17130f;
}
.announcement-accent-moss,
#yl-countdown-ticker.announcement-accent-moss {
  background-color: #3e5a4a;
  color: #f3ead9;
}
.announcement-accent-lavender,
#yl-countdown-ticker.announcement-accent-lavender {
  background-color: #4a385c;
  color: #f3ead9;
}
.announcement-accent-rust,
#yl-countdown-ticker.announcement-accent-rust {
  background-color: #8a381e;
  color: #f3ead9;
}

.pdp-batch-date,
.badge-batch-date {
  display: inline-block;
  background: var(--ink-3, #24201c);
  color: var(--whiskey, #e08a3c);
  border: 1px solid var(--whiskey, #e08a3c);
  border-radius: var(--radius-sm, 6px);
  padding: 2px 8px;
  font-size: 0.75rem;
  font-weight: 600;
  margin-top: 4px;
}

/* ── Product detail pages (real pages since 2026-09-01) ─────────── */
.pdp-eyebrow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin: 0 0 8px;
}
.pdp-size-label {
  font-size: 0.78rem;
  color: var(--paper-dim);
  letter-spacing: 0.04em;
}
.pdp-rating-summary {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.9rem;
  color: var(--paper-dim);
  text-decoration: none;
  margin-bottom: 8px;
}
.pdp-rating-summary .stars,
.pdp-reviews-summary .stars,
.pdp-etsy-proof .stars {
  color: var(--whiskey);
  letter-spacing: 0.05em;
}
.pdp-rating-summary:hover {
  color: var(--paper);
  text-decoration: underline;
}
.pdp-gallery-main {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
  border-radius: var(--radius-lg, 16px);
  overflow: hidden;
}
.pdp-gallery-main:focus-visible {
  outline: 2px solid var(--whiskey);
  outline-offset: 4px;
}
.pdp-main-image {
  width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  display: block;
}
.pdp-thumbs {
  display: flex;
  gap: 10px;
  margin-top: 12px;
  overflow-x: auto;
  padding-bottom: 4px;
  scrollbar-width: thin;
}
.pdp-thumb {
  flex: 0 0 auto;
  width: 72px;
  height: 72px;
  padding: 0;
  border: 2px solid transparent;
  border-radius: 10px;
  overflow: hidden;
  background: var(--ink-2);
  cursor: pointer;
  transition: border-color 0.2s ease;
}
.pdp-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.pdp-thumb.is-active,
.pdp-thumb:hover {
  border-color: var(--whiskey);
}
.pdp-thumb:focus-visible {
  outline: 2px solid var(--whiskey);
  outline-offset: 2px;
}
.pdp-dispatch:empty {
  display: none;
}
.pdp-dispatch {
  margin: 4px 0 12px;
}
.pdp-variant-group {
  border: 0;
  padding: 0;
  margin: 16px 0 6px;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.pdp-variant-group legend {
  width: 100%;
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--paper-dim);
  margin-bottom: 8px;
  font-weight: 700;
}
.pdp-variant-current {
  text-transform: none;
  letter-spacing: 0;
  color: var(--paper);
  font-weight: 600;
}
.pdp-variant-option {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 16px;
  border: 1.5px solid var(--hide);
  border-radius: 999px;
  background: var(--ink-2);
  color: var(--paper);
  font-weight: 600;
  cursor: pointer;
  transition:
    border-color 0.2s ease,
    background 0.2s ease;
}
.pdp-variant-option small {
  margin-left: 6px;
  color: var(--paper-dim);
  font-weight: 500;
}
.pdp-variant-option input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
  pointer-events: none;
}
.pdp-variant-option:has(input:checked) {
  border-color: var(--whiskey);
  background: oklch(from var(--whiskey) l c h / 0.14);
}
.pdp-variant-option:has(input:focus-visible) {
  outline: 2px solid var(--whiskey);
  outline-offset: 2px;
}
.pdp-variant-option.is-sold-out {
  opacity: 0.55;
  cursor: not-allowed;
  text-decoration: line-through;
}
.pdp-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 12px;
  margin-top: 16px;
}
.pdp-actions .pdp-cta-btn {
  flex: 1 1 220px;
  justify-content: center;
}
.pdp-qty {
  display: inline-flex;
  align-items: stretch;
  border: 1.5px solid var(--hide);
  border-radius: 999px;
  overflow: hidden;
  background: var(--ink-2);
}
.pdp-qty-btn {
  width: 44px;
  min-height: 44px;
  border: 0;
  background: transparent;
  color: var(--paper);
  font-size: 1.2rem;
  cursor: pointer;
}
.pdp-qty-btn:hover {
  background: var(--ink-3);
}
.pdp-qty-btn:focus-visible {
  outline: 2px solid var(--whiskey);
  outline-offset: -2px;
}
.pdp-qty-input {
  width: 52px;
  text-align: center;
  border: 0;
  background: transparent;
  color: var(--paper);
  font-weight: 700;
  font-size: 1rem;
  -moz-appearance: textfield;
  appearance: textfield;
}
.pdp-qty-input::-webkit-outer-spin-button,
.pdp-qty-input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
.pdp-wish-btn {
  width: 48px;
  min-height: 48px;
  border: 1.5px solid var(--hide);
  border-radius: 999px;
  background: var(--ink-2);
  color: var(--paper);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition:
    color 0.2s ease,
    border-color 0.2s ease;
}
.pdp-wish-btn:hover,
.pdp-wish-btn.active {
  color: var(--crimson);
  border-color: var(--crimson);
}
.pdp-wish-btn.active svg {
  fill: currentColor;
}
.pdp-express {
  font-size: 0.82rem;
  margin: 10px 0 0;
}
.pdp-trust {
  list-style: none;
  padding: 14px 16px;
  margin: 18px 0 0;
  display: grid;
  gap: 10px;
  background: var(--ink-2);
  border: 1px solid var(--hide);
  border-radius: var(--radius, 10px);
  font-size: 0.86rem;
  color: var(--paper-dim);
}
.pdp-trust li {
  display: flex;
  gap: 10px;
  align-items: flex-start;
}
.pdp-trust .yl-icon {
  flex-shrink: 0;
  color: var(--whiskey);
  margin-top: 2px;
}
.pdp-policy-link {
  font-size: 0.82rem;
  margin: 8px 0 0;
}
.pdp-etsy-proof {
  font-size: 0.86rem;
  color: var(--paper-dim);
  margin: 14px 0 0;
}
.pdp-info {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  gap: 32px;
  margin: 40px 0;
  align-items: start;
}
@media (max-width: 820px) {
  .pdp-info {
    grid-template-columns: 1fr;
    gap: 24px;
  }
}
.pdp-facts {
  margin: 0;
  padding: 18px 20px;
  background: var(--ink-2);
  border: 1px solid var(--hide);
  border-radius: var(--radius, 10px);
  display: grid;
  gap: 12px;
}
.pdp-facts div {
  display: grid;
  gap: 2px;
}
.pdp-facts dt {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--paper-dim);
  font-weight: 700;
}
.pdp-facts dd {
  margin: 0;
  color: var(--paper);
}
.pdp-ingredients-lead {
  margin: -4px 0 8px;
}
.pdp-reviews {
  margin: 40px 0;
}
.pdp-reviews-summary {
  margin: 6px 0 0;
}
.pdp-reviews-disclosure {
  margin: 6px 0 0;
}
.pdp-reviews .review-text {
  margin: 8px 0;
  font-style: normal;
}
.pdp-reviews .review-meta {
  font-size: 0.82rem;
  color: var(--paper-dim);
}
.pdp-reviews .review-form-wrap {
  margin-top: 24px;
}
.pdp-related .related-grid {
  gap: 20px;
}
.grid-4 {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 20px;
}
@media (max-width: 1024px) {
  .grid-4 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 480px) {
  .grid-4 {
    grid-template-columns: 1fr;
  }
}
.related-card-link {
  display: block;
  color: inherit;
  text-decoration: none;
}
.related-card-link .card-media img {
  width: 100%;
  height: auto;
  aspect-ratio: 600 / 510;
  object-fit: cover;
  display: block;
}
.related-card-link:hover h3 {
  color: var(--whiskey);
}
.related-card-link:focus-visible {
  outline: 2px solid var(--whiskey);
  outline-offset: 4px;
  border-radius: var(--radius-lg, 16px);
}
.card-title-link {
  color: inherit;
  text-decoration: none;
}
.card-title-link:hover {
  color: var(--whiskey);
  text-decoration: underline;
}
/* A sticky bar must never cover a focused control (WCAG 2.4.11). */
@media (max-width: 767px) {
  body.pdp-page {
    scroll-padding-bottom: 96px;
  }
}
@media (prefers-reduced-motion: reduce) {
  .pdp-thumb,
  .pdp-variant-option,
  .pdp-wish-btn {
    transition: none;
  }
}
.pdp-safety {
  margin: 18px 0 0;
  padding: 16px 18px;
  border: 1px solid var(--hide);
  border-left: 3px solid var(--whiskey);
  border-radius: var(--radius, 10px);
  background: var(--ink-2);
}
.pdp-safety-title {
  margin: 0 0 8px;
  font-size: 0.95rem;
}
.pdp-safety-list {
  margin: 0;
  padding-left: 18px;
  display: grid;
  gap: 6px;
  font-size: 0.9rem;
  color: var(--paper-dim);
}
.pdp-safety-foot {
  margin: 10px 0 0;
}

/* =====================================================================
   LAYOUT-SHIFT RESERVATIONS (performance pass, 2026-09-02)
   ---------------------------------------------------------------------
   Every rule below reserves, before the deferred main.js runs, the exact
   space a JS-rendered block is about to occupy. Measured CLS before this
   block (mobile 393x851, Fast-4G, 4x CPU): shop.html 0.46, events.html
   0.62, about/faq/contact/policies/... 0.053. The dominant cost was never
   the product grid itself -- the grid starts below the fold on a phone and
   its growth pushes only off-screen content. What actually moved the
   viewport was (a) the announcement bar main.js inserts ABOVE the header on
   every page, and (b) the shop toolbar / events countdown banner growing
   from near-zero to several hundred pixels right at the fold.

   Every reservation is gated on the emptiness of the container main.js
   fills, so the reserved height disappears in the same frame the real
   content lands: no double-counting, and no permanent gap once a block
   renders. The pixel values come from a width sweep in 8px steps
   (scratchpad/perf/sweep.js) against the current products.json /
   events.json, re-run it if the catalogue's category or concern pills
   change enough to re-wrap the toolbar.
   ===================================================================== */

/* --- 1. Announcement bar (all pages) ---------------------------------
   assets/js/main.js announcementBar() inserts .announcement-bar directly
   before .site-header on every page that does not already ship one
   statically (index.html does, as #yl-countdown-ticker). That insertion
   moved the entire document down 38-61px depending on width, which on its
   own is ~0.05 CLS on every content page. Reserve it on the header while
   no bar exists yet; the :has() test flips off the instant one is inserted
   AND is already false on index.html, whose bar is in the static markup.
   If the shop owner ever turns the announcement off in /admin *and*
   clears shop.freeShippingThreshold, main.js inserts nothing and this
   leaves a blank strip -- both are set today (content.json
   site.announcement.enabled, products.json shop.freeShippingThreshold),
   and a browser without :has() support simply keeps the old behaviour. */
body:not(:has(.announcement-bar)) .site-header {
  margin-top: 61px;
}
@media (min-width: 376px) {
  body:not(:has(.announcement-bar)) .site-header {
    margin-top: 46px;
  }
}
@media (min-width: 712px) {
  body:not(:has(.announcement-bar)) .site-header {
    margin-top: 38px;
  }
}

/* --- 2. shop.html toolbar -------------------------------------------
   #filterRow, #concernFilterRow and #scentFieldWrap all ship empty and are
   filled by buildFilters() in main.js, taking .shop-toolbar from 169px to
   541px at 393px wide. That is the single largest shift on the page: it
   sits at the fold, so everything below it (the sort row, the policy note,
   the grid) is displaced by up to ~370px. The ladder tracks where the
   category/concern pills re-wrap. */
.shop-toolbar:has(#filterRow:empty) {
  min-height: 628px;
}
@media (min-width: 336px) {
  .shop-toolbar:has(#filterRow:empty) {
    min-height: 587px;
  }
}
@media (min-width: 368px) {
  .shop-toolbar:has(#filterRow:empty) {
    min-height: 544px;
  }
}
@media (min-width: 400px) {
  .shop-toolbar:has(#filterRow:empty) {
    min-height: 503px;
  }
}
@media (min-width: 408px) {
  .shop-toolbar:has(#filterRow:empty) {
    min-height: 460px;
  }
}
@media (min-width: 480px) {
  .shop-toolbar:has(#filterRow:empty) {
    min-height: 419px;
  }
}
@media (min-width: 496px) {
  .shop-toolbar:has(#filterRow:empty) {
    min-height: 370px;
  }
}
@media (min-width: 568px) {
  .shop-toolbar:has(#filterRow:empty) {
    min-height: 327px;
  }
}
@media (min-width: 608px) {
  .shop-toolbar:has(#filterRow:empty) {
    min-height: 322px;
  }
}
@media (min-width: 680px) {
  .shop-toolbar:has(#filterRow:empty) {
    min-height: 233px;
  }
}
@media (min-width: 904px) {
  .shop-toolbar:has(#filterRow:empty) {
    min-height: 253px;
  }
}
@media (min-width: 984px) {
  .shop-toolbar:has(#filterRow:empty) {
    min-height: 217px;
  }
}
@media (min-width: 1048px) {
  .shop-toolbar:has(#filterRow:empty) {
    min-height: 174px;
  }
}
@media (min-width: 1112px) {
  .shop-toolbar:has(#filterRow:empty) {
    min-height: 156px;
  }
}
@media (min-width: 1168px) {
  .shop-toolbar:has(#filterRow:empty) {
    min-height: 135px;
  }
}

/* --- 3. shop.html result count + product grid ------------------------
   #shopCount is one line of live-region text (22px at every width).
   #shopGrid holds 19 cards -- 15,900px tall on a phone, 6,000px at three
   columns -- so it only ever GROWS past the reservation and can never pull
   content back up. One row's worth is reserved, which is all the viewport
   can ever see, and a soft skeleton fills it so a slow connection shows a
   loading catalogue rather than a blank hole. */
#shopCount:empty {
  min-height: 22px;
}
#shopGrid:empty,
#featuredGrid:empty {
  min-height: 740px;
}
@media (min-width: 981px) {
  #shopGrid:empty,
  #featuredGrid:empty {
    min-height: 920px;
  }
}

/* --- 4. events.html countdown banner + upcoming grid -----------------
   #eventsCountdownBanner carried a hand-set inline min-height of 76px that
   was less than half the 162-191px it actually renders at. #upcomingEvents
   ships empty and renders one card per upcoming event in events.json.
   Both sit above the fold, so together they were displacing #pastEvents by
   ~480px. Unlike the shop grid these are SMALL blocks whose real height is
   close to the reservation, so the ladders below are sized to the measured
   render rather than rounded up -- over-reserving here would trade a
   downward shift for an equally expensive upward one. */
#eventsCountdownBanner:empty {
  min-height: 191px;
}
@media (min-width: 432px) {
  #eventsCountdownBanner:empty {
    min-height: 162px;
  }
}
@media (min-width: 712px) {
  #eventsCountdownBanner:empty {
    min-height: 167px;
  }
}
#upcomingEvents:empty {
  min-height: 391px;
}
@media (min-width: 336px) {
  #upcomingEvents:empty {
    min-height: 367px;
  }
}
@media (min-width: 464px) {
  #upcomingEvents:empty {
    min-height: 344px;
  }
}
@media (min-width: 608px) {
  #upcomingEvents:empty {
    min-height: 393px;
  }
}
@media (min-width: 696px) {
  #upcomingEvents:empty {
    min-height: 370px;
  }
}

/* --- 5. Skeleton shimmer for the reserved grid ------------------------
   Purely decorative: a pseudo-element, so it costs no markup, is invisible
   to the accessibility tree, and vanishes the moment the container stops
   being :empty. Respects prefers-reduced-motion. */
#shopGrid:empty::before,
#featuredGrid:empty::before,
#upcomingEvents:empty::before {
  content: "";
  display: block;
  grid-column: 1 / -1;
  min-height: inherit;
  border: 1px solid var(--hide);
  border-radius: var(--radius-lg, 14px);
  background: linear-gradient(
    100deg,
    var(--ink-2) 30%,
    color-mix(in srgb, var(--ink-2) 80%, var(--paper) 20%) 50%,
    var(--ink-2) 70%
  );
  background-size: 300% 100%;
  animation: yl-skeleton-sheen 1.6s ease-in-out infinite;
}
@keyframes yl-skeleton-sheen {
  from {
    background-position: 150% 0;
  }
  to {
    background-position: -50% 0;
  }
}
@media (prefers-reduced-motion: reduce) {
  #shopGrid:empty::before,
  #featuredGrid:empty::before,
  #upcomingEvents:empty::before {
    animation: none;
  }
}

/* ==========================================================
   Growth features: analytics/reviews/events/search additions.
   Appended, not merged into the sections above -- see file header
   convention (another agent appends here too).
   ========================================================== */

/* Visible review count next to the product card star row (main.js
   ratingHTML) -- now shown from 1 review instead of 3+. aria-hidden
   because the adjacent .sr-only span already announces the same count
   in full sentence form; this is the sighted-only echo of it. */
.card-rating-count {
  font-size: 0.78rem;
  color: var(--paper-dim);
  margin-left: 4px;
}

/* Star-distribution summary above the review grid (main.js
   reviewDistributionHTML), reviews.html and shop.html's #reviews section. */
.review-distribution {
  display: grid;
  gap: 6px;
  max-width: 420px;
  margin: 0 0 28px;
}
.review-dist-row {
  display: grid;
  grid-template-columns: 34px 1fr 28px;
  align-items: center;
  gap: 10px;
  font-size: 0.85rem;
  color: var(--paper-dim);
}
.review-dist-label {
  text-align: right;
}
.review-dist-track {
  height: 8px;
  border-radius: 999px;
  background: var(--ink-3);
  overflow: hidden;
}
.review-dist-fill {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--success);
}
.review-dist-count {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Owner reply under a review (main.js renderReviewCardHtml's ownerReply,
   admin/config.yml's reviews.ownerReply -- optional, CMS-authored). */
.review-owner-reply {
  margin-top: 12px;
  padding: 10px 14px;
  border-left: 3px solid var(--whiskey);
  background: var(--ink-3);
  border-radius: 0 var(--radius-md, 8px) var(--radius-md, 8px) 0;
  font-size: 0.9rem;
}
.review-owner-reply-label {
  margin: 0 0 4px;
  font-weight: 700;
  font-size: 0.78rem;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--whiskey);
}
.review-owner-reply p:last-child {
  margin: 0;
  color: var(--paper-dim);
}

/* Global search "no results" suggestion row (main.js renderNoResultsHtml) --
   sits under the popular-search chips, links to the full shop and contact. */
.search-empty-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px 20px;
  margin-top: 16px;
}
.search-empty-link {
  font-size: 0.88rem;
  color: var(--whiskey);
  text-decoration: underline;
}
.search-empty-link:hover,
.search-empty-link:focus-visible {
  color: var(--paper);
}

/* "Invite us to your market" line + the event-specific "email me the next
   market date" capture, rendered under the upcoming events list by main.js
   (eventInviteOrganizerHTML / eventEmailCaptureHTML). .events-market-alert-
   form's honeypot div reuses the shared .form-hp rule defined above. */
.events-followup-panel {
  margin-top: 32px;
  padding-top: 24px;
  border-top: 1px solid var(--hide);
  text-align: center;
}
.events-invite-organizer {
  color: var(--paper-dim);
  margin: 0 0 16px;
}
.events-invite-organizer a {
  color: var(--whiskey);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.events-market-alert-form {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 10px;
  max-width: 420px;
  margin: 0 auto;
}
.events-market-alert-form input[type="email"] {
  flex: 1 1 220px;
  padding: 10px 14px;
  background: var(--ink-2);
  border: 1px solid var(--hide);
  border-radius: var(--radius-md, 8px);
  color: var(--paper);
  font-size: 0.9rem;
}
.events-market-alert-form input[type="email"]:focus {
  border-color: var(--whiskey);
  outline: 2px solid var(--whiskey);
  outline-offset: 1px;
}

/* =====================================================================
   SELF-HOSTED WEBFONTS  (performance pass, 2026-09-02)
   ---------------------------------------------------------------------
   Gloock and DM Sans now ship from assets/fonts/ (69KB of WOFF2 in total,
   downloaded by scripts/self-host-fonts.js) instead of fonts.gstatic.com.
   That removes two cross-origin DNS+TLS handshakes -- fonts.googleapis.com
   for the CSS and fonts.gstatic.com for the files -- from the critical path.

   These rules live in styles.css, which EVERY page loads, and styles.css is
   linked after the Google Fonts stylesheet on the pages that still carry
   one. Later @font-face rules win for the same family/weight/style, so the
   self-hosted files are the ones actually used site-wide, and gstatic is
   never asked for a file even on a page whose <head> still references it.
   The 19 generated products/*.html pages plus welcome.html and
   thank-you.html still carry the old <head> block: their heads are emitted
   by scripts/build-site-data.js:4824-4831 (regenerating them needs a
   build-data run) or owned elsewhere. Until those are converted the CSP
   keeps https://fonts.googleapis.com in style-src and
   https://fonts.gstatic.com in font-src -- see the performance-pass note in
   docs/AUDIT-2026-09-01.md.

   Metric-matched fallbacks: the size-adjust / ascent-override /
   descent-override numbers below are measured, not guessed. At 100px,
   "Handgloves Wq 0123" advances 958.60px in DM Sans against 956.15px in
   Arial (=> 100.26%) and 919.90px in Gloock against 940.19px in Georgia
   (=> 97.84%); fontBoundingBoxAscent/Descent give 99%/31% for DM Sans and
   98%/23% for Gloock. Re-derive with scratchpad/perf/font-metrics.js if the
   families ever change. local() means the fallback face simply drops out on
   a machine without Arial/Georgia -- the stack behind it still applies.
   ===================================================================== */
@font-face {
  font-family: "Gloock";
  src: url("../fonts/gloock-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "DM Sans";
  src: url("../fonts/dm-sans-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "DM Sans";
  src: url("../fonts/dm-sans-500.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "DM Sans";
  src: url("../fonts/dm-sans-700.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "DM Sans Fallback";
  src:
    local("Arial"),
    local("Helvetica Neue"),
    local("Liberation Sans");
  size-adjust: 100.26%;
  ascent-override: 99%;
  descent-override: 31%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Gloock Fallback";
  src:
    local("Georgia"),
    local("Times New Roman"),
    local("Liberation Serif");
  size-adjust: 97.84%;
  ascent-override: 98%;
  descent-override: 23%;
  line-gap-override: 0%;
}

/* Re-declared here rather than edited in place at :root above -- this file is
   append-only for this pass. Same values as before with the metric-matched
   fallback slotted in front of the generic families, so the swap from
   fallback to real font no longer re-flows the paragraph it happens in.
   "CleanAmpersand" stays first: it is scoped to unicode-range U+0026 and
   exists only to borrow the system font's ampersand. */
:root {
  --font-display: "CleanAmpersand", "Gloock", "Gloock Fallback", "Georgia", serif;
  --font-body:
    "CleanAmpersand", "DM Sans", "DM Sans Fallback", -apple-system, BlinkMacSystemFont,
    "Segoe UI", sans-serif;
}

/* =====================================================================
   REPORT A REACTION (safety.html)
   ---------------------------------------------------------------------
   The MoCRA adverse-event form. The shared .field rules above already
   cover the inputs, textareas and selects on this page, so what follows
   is only what the shared rules do not have: fieldset grouping, the
   checkbox/radio lists, the hint and error lines, and the two result
   panels. Appended at the end of the file rather than edited in place --
   this file is append-only for this pass.

   Contrast note: every colour here is a plain token used at full
   opacity, never `oklch(from var(--x) ... / <alpha>)` over a light
   surface. That translucent-tint pattern is what produced the 23
   colour-contrast failures the 2026-09-01 audit had to fix at the token
   level; there is no reason to reintroduce it for a page whose whole job
   is being readable by someone having a bad day.
   ===================================================================== */

.safety-prose,
.safety-form-wrap {
  max-width: 760px;
}

.safety-prose h2,
.safety-form-wrap h2 {
  margin-bottom: 16px;
}

.safety-form-desc {
  color: var(--paper-dim);
  margin-bottom: 32px;
}

/* Numbered first-aid steps. The marker is the browser's own <ol> number,
   kept rather than replaced so the list still reads as a sequence with
   images off and in a screen reader's list announcement. */
.safety-steps {
  list-style: decimal;
  padding-left: 1.4em;
  margin: 0;
}

.safety-steps > li {
  margin-bottom: 26px;
}

/* Step 3 and the "Tell us what happened" form were separated by the last
   step's own margin, an 88px section pad-bottom, a 48px-margin rule and an
   88px section pad-top -- roughly 235px of nothing, which on a phone read as
   a broken page (live audit L11). */
.safety-steps > li:last-child {
  margin-bottom: 0;
}

section.safety-steps-section {
  padding-bottom: 24px;
}

hr.rule.safety-rule-tight {
  margin: 24px 0;
}

hr.rule.safety-rule-tight + #reaction-report {
  padding-top: 32px;
}

.safety-steps h3 {
  font-family: var(--font-body);
  font-size: 1.05rem;
  font-weight: 700;
  margin: 0 0 0.35em;
}

.safety-steps p {
  margin: 0;
}

.safety-next {
  list-style: disc;
  padding-left: 1.3em;
  margin: 0 0 24px;
}

.safety-next > li {
  margin-bottom: 12px;
}

.safety-note {
  color: var(--paper-dim);
  font-size: 0.95rem;
}

/* --- the form ------------------------------------------------------- */

.safety-fieldset {
  border: 1px solid var(--hide);
  border-radius: var(--radius);
  padding: 24px 20px 6px;
  margin: 0 0 28px;
}

.safety-fieldset > legend {
  font-family: var(--font-display);
  font-size: 1.15rem;
  padding: 0 8px;
  color: var(--paper);
}

/* Two fields side by side where they are a natural pair (the two dates,
   age + sex). Collapses to one column on a phone. */
.safety-field-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 0 18px;
}

.safety-optional {
  text-transform: none;
  letter-spacing: 0;
  font-weight: 400;
  color: var(--paper-dim);
}

.safety-hint {
  font-size: 0.85rem;
  color: var(--paper-dim);
  margin: -10px 0 0;
}

.safety-error {
  font-size: 0.85rem;
  color: var(--error);
  font-weight: 600;
  margin: 6px 0 0;
}

/* A control the validator has flagged. Not colour alone: the message
   below it says what is wrong, and aria-invalid carries it to a screen
   reader -- the border is the third signal, not the only one. */
.safety-form [aria-invalid="true"] {
  border-color: var(--error);
}

/* Checkbox and radio groups. A nested fieldset, so the question is the
   group's accessible name rather than a paragraph that happens to sit
   above it. */
.safety-checkgroup {
  border: 0;
  padding: 0;
  margin: 0 0 22px;
}

.safety-checkgroup > legend {
  display: block;
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--paper-dim);
  margin-bottom: 8px;
  font-weight: 600;
  padding: 0;
}

.safety-checks {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.safety-checks-inline {
  flex-direction: row;
  gap: 22px;
}

/* The whole row is the label, so the hit area clears the WCAG 2.2
   target-size minimum without a hand-set width -- the padding does it. */
.safety-check {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 7px 4px;
  border-radius: var(--radius);
  cursor: pointer;
  font-size: 0.95rem;
  line-height: 1.45;
  color: var(--paper);
}

.safety-check:hover {
  background: var(--ink-3);
}

.safety-check input {
  width: 18px;
  height: 18px;
  min-width: 18px;
  margin: 2px 0 0;
  accent-color: var(--whiskey);
  flex: none;
}

.safety-check input:focus-visible {
  outline: 2px solid var(--whiskey);
  outline-offset: 2px;
}

.safety-consent {
  margin-top: 8px;
}

.safety-privacy-note {
  margin-top: 16px;
}

/* --- result panels --------------------------------------------------- */

.safety-result {
  border: 1px solid var(--hide);
  border-left-width: 4px;
  border-radius: var(--radius);
  padding: 20px 22px;
  margin-bottom: 28px;
}

/* `hidden` has to win over the block-level rule above it. This is the
   same defect the thank-you page shipped: a display value on the class
   beat the attribute and the panel showed on every load. */
.safety-result[hidden] {
  display: none;
}

.safety-result h3 {
  margin: 0 0 10px;
  font-family: var(--font-body);
  font-size: 1.1rem;
  font-weight: 700;
}

.safety-result p {
  margin: 0 0 10px;
}

.safety-result p:last-child {
  margin-bottom: 0;
}

.safety-result-success {
  border-left-color: var(--success);
}

.safety-result-error {
  border-left-color: var(--error);
}

.safety-reference {
  font-family: var(--font-display);
  letter-spacing: 0.12em;
  font-size: 1.15rem;
  white-space: nowrap;
}

@media (max-width: 600px) {
  .safety-fieldset {
    padding: 20px 14px 4px;
  }

  .safety-checks-inline {
    gap: 14px;
  }
}

/* Search results: a product that is not on sale yet (coming soon) gets an
   amber badge and a "Notify me" link in place of the add button. */
.stock-badge.coming-soon {
  background: rgba(214, 155, 92, 0.16);
  color: var(--whiskey);
  border: 1px solid rgba(214, 155, 92, 0.45);
}
.search-notify-link {
  text-decoration: none;
  white-space: nowrap;
}

/* Events page: the market-date signup gets its own heading so it is not
   read as the "invite us" form above it (verify-A M4). */
.events-market-alert-title {
  flex: 1 1 100%;
  margin: 0 0 4px;
  font-size: 0.92rem;
  color: var(--paper);
  text-align: center;
}
/* Search modal: the clear-query control must not look like the close
   control beside it (verify-A L7) -- a small filled circle, not a bare X. */
.global-search-clear-btn {
  border-radius: 999px;
  background: color-mix(in srgb, var(--paper-dim) 22%, transparent);
  width: 26px;
  height: 26px;
  font-size: 0.8rem;
  line-height: 1;
}
.global-search-clear-btn {
  padding: 4px;
}
.global-search-clear-btn svg {
  width: 15px;
  height: 15px;
}

/* thank-you.html: the receipt card and badge ship [hidden] but keep their
   box until thank-you.js decides (a real redirect reveals them, a session-
   less visit adds .is-gone), so the common path paints without a shift on
   desktop too (verify-D M-6). */
.thank-you-card[hidden]:not(.is-gone),
.thank-you-badge-wrap[hidden]:not(.is-gone) {
  display: block !important;
  visibility: hidden;
}
.thank-you-card.is-pending .receipt-status-badge {
  opacity: 0.75;
}
/* The reference is the one string a shopper may have to read aloud: never
   cut it with an ellipsis (verify-D M-7). */
.session-code {
  max-width: none;
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
  overflow-wrap: anywhere;
  word-break: break-all;
}
/* safety.html with JavaScript off: the Worker's 303 lands on #safetySuccess
   so the confirmation shows even though nothing can fill the reference in. */
#safetySuccess:target {
  display: block !important;
}

/* Same trick for the "this did not go through, email us" panel, so a no-JS
   reporter caught by the honeypot is told the truth rather than being sent
   back to a silent form (live audit M11). */
#safetyEmailUs:target {
  display: block !important;
}

/* PDP sticky bar on narrow phones (verify-C H-7): the variant select must not
   crush the name and price to nothing. */
.pdp-sticky-info {
  min-width: 0;
  flex: 1 1 auto;
}
.pdp-sticky-variant-wrap {
  flex: 0 1 38%;
  min-width: 0;
}
.pdp-sticky-variant-select {
  max-width: 100%;
}
@media (max-width: 360px) {
  .pdp-sticky-bar {
    flex-wrap: wrap;
  }
  .pdp-sticky-variant-wrap {
    flex: 1 1 100%;
  }
}

/* Phone header controls meet the 44px target size (verify-B M-8) without
   changing the desktop header. */
@media (max-width: 768px) {
  #wishToggle,
  #globalSearchTrigger,
  .cart-toggle,
  .lang-toggle,
  .nav-toggle {
    min-width: 44px;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
  #themeToggle {
    min-height: 44px;
    padding-top: 10px;
    padding-bottom: 10px;
    box-sizing: border-box;
  }
  .nav-cta {
    gap: 2px;
  }
}
