/* ============================================================
   VCG QLD — PRIMITIVES
   Glass (UI layer) + Card (content) + shared helpers.
   Per VCG Design System v1 (§02 The Rule, §06 Primitive).
   ============================================================ */

/* ------------------------------------------------------------
   GLASS — the material lives on the real UI-layer components in
   liquid-glass.css (.nav, .hero-badge, .scroll-to-top, drawer…),
   which also own the accessibility/fallback modes at its tail.
   The standalone .glass/.glass--* class family was removed
   2026-06-12: zero usages — a parallel system nobody consumed.
   Four cues that always carry the material on those components:
   1. Shape (pill / high radius)
   2. Top highlight (inset 1px white)
   3. Elevation shadow (soft wide)
   4. Directional hairline edge
   ------------------------------------------------------------ */


/* ------------------------------------------------------------
   CARD — content layer. Solid, shares shape vocabulary.
   Same radius family, same shadow scale, just opaque.
   ------------------------------------------------------------ */
.card {
  background: var(--color-surface);
  border: 1px solid var(--card-border);
  border-radius: var(--r-card);
  box-shadow: var(--card-shadow);
  transition: transform var(--dur) var(--ease),
              box-shadow var(--dur) var(--ease),
              border-color var(--dur) var(--ease);
}

.card:hover {
  transform: translateY(-2px);
  box-shadow: var(--card-shadow-hover);
  border-color: var(--card-border-hover);
}

.card--flat { box-shadow: var(--shadow-1); }
.card--raised { box-shadow: var(--shadow-3); }
.card--sheet { border-radius: var(--r-sheet); }


/* ------------------------------------------------------------
   HORIZONTAL-SCROLL EDGE FADE — directional mask shared by every
   horizontal-scroll row:
     .hscroll-wrapper   — pinned scroll-jacked rows (home "Why Choose
                          Us", product-detail "Key Features"), driven
                          by VCG.horizontalScroll.
     .pd-related__grid  — the manually-scrolled "Explore other
                          options" row, driven by VCG.edgeFadeScroller.

   --fade-l / --fade-r are 0–1 multipliers the scroll handlers drive
   live (0 = that side flush, 1 = full fade); start state is left
   flush, right faded. The mask gradient is declared on the elements
   that own those vars so var(--fade-*) resolve correctly (a :root
   token would resolve them against :root instead).
   ------------------------------------------------------------ */
/* Manually-scrolled related row keeps the mask — it scrolls natively
   (not a pinned GSAP scrub), so the mask repaint cost is light and only
   occurs while the user is actively dragging that row. */
.pd-related__grid {
  --fade-l: 0;
  --fade-r: 1;
  -webkit-mask-image: linear-gradient(to right,
    transparent 0,
    #000 calc(var(--scroll-edge-fade) * var(--fade-l, 1)),
    #000 calc(100% - var(--scroll-edge-fade) * var(--fade-r, 1)),
    transparent 100%);
  mask-image: linear-gradient(to right,
    transparent 0,
    #000 calc(var(--scroll-edge-fade) * var(--fade-l, 1)),
    #000 calc(100% - var(--scroll-edge-fade) * var(--fade-r, 1)),
    transparent 100%);
}

/* Pinned scrub rows (home "Why Choose Us", product "Key Features",
   WCS-110 aromatherapy) clip the track and fade their edges. The fade
   is done with two opacity-animated gradient overlays rather than a
   mask-image on the wrapper: a mask forces the browser to re-rasterise
   the whole wrapper every frame because the track translates under it
   (the cause of the scroll chop, especially on mobile). Overlay opacity
   is GPU-composited, so the per-frame cost during the scrub is just the
   track's transform. --fade-l / --fade-r (0..1, set live by the scroll
   handler) drive the overlay opacities directly: 0 = edge flush, 1 =
   fully faded. --hscroll-fade-color must match the section background so
   the cards appear to dissolve into it (overridden per section). */
.hscroll-wrapper {
  --fade-l: 0;
  --fade-r: 1;
  --hscroll-fade-color: var(--color-bg);
  position: relative;
  overflow: hidden;
}
.hscroll-wrapper::before,
.hscroll-wrapper::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  width: var(--scroll-edge-fade);
  z-index: 3;
  pointer-events: none;
}
/* --edge-fade-max caps the veil so a fully-faded edge stays subtle (a soft
   dissolve, not a solid white band). The 0..1 --fade-l/r ramp scales within
   it. */
.hscroll-wrapper {
  --edge-fade-max: 0.6;
}
.hscroll-wrapper::before {
  left: 0;
  background: linear-gradient(to right, var(--hscroll-fade-color), transparent);
  opacity: calc(var(--fade-l, 0) * var(--edge-fade-max));
}
.hscroll-wrapper::after {
  right: 0;
  background: linear-gradient(to left, var(--hscroll-fade-color), transparent);
  opacity: calc(var(--fade-r, 1) * var(--edge-fade-max));
}


/* Apple-style sticky stage — built at runtime by VCG.horizontalScroll.
   The section becomes a tall scroll "runway" (height set inline by JS:
   one viewport + the horizontal scroll distance + two dwells) and
   .hscroll-stage — which receives ALL the section's original content —
   sticks to the viewport top while the runway scrolls past beneath it.
   position: sticky is resolved on the browser's compositor, so the
   frame never jumps or trails the way a JS pin (a position:fixed toggle
   driven by late-reported iOS scroll events) does. ScrollTrigger only
   scrubs the track's transform inside the held frame.

   section.class beats the per-section .why / .pd-features / .spa-scents
   rules, so this overrides their 100vh + flex centring + overflow. */
section.hscroll-runway {
  display: block;       /* the stage owns the flex centring now */
  min-height: 0;        /* JS sets the explicit runway height inline */
  height: auto;         /* (overridden inline; keeps cascade tidy) */
  padding: 0;           /* padding moved onto the stage by the JS */
  overflow: visible;    /* a clipping ancestor would break sticky */
}
.hscroll-stage {
  position: -webkit-sticky;
  position: sticky;
  top: 0;
  height: 100vh;        /* fallback; JS sets it to window.innerHeight */
  display: flex;
  flex-direction: column;
  justify-content: center;
  overflow: hidden;     /* clips the track at the frame edges */
}


/* ------------------------------------------------------------
   BUTTON PRIMITIVES — exactly THREE button styles (user decisions
   2026-07-06 + 2026-07-08):
   .btn-primary (solid brand blue)  = every ordinary action
   .btn-white   (solid white)       = actions that lead to the CONTACT form
   .btn-buy     (solid emerald)     = PURCHASE/checkout actions (Square links)
   Colour is SEMANTIC (destination), not surface-dependent. All share the
   same beveled-slab depth. Height ≥44px touch target, pill radius.
   ------------------------------------------------------------ */
.btn-primary,
.btn-white,
.btn-buy {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
  padding: 0.7rem 1.4rem;
  min-height: 44px;
  border-radius: var(--r-pill);
  font-family: var(--font-sans);
  font-size: var(--text-body-sm);
  font-weight: 600;
  letter-spacing: -0.005em;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--dur) var(--ease),
              color var(--dur) var(--ease),
              box-shadow var(--dur) var(--ease),
              border-color var(--dur) var(--ease),
              transform var(--dur) var(--ease);
}

/* Beveled slab: light-from-above gradient overlay on the solid fill +
   inset top highlight / bottom contour + atmospheric drop shadow.
   border:none — the inset edges ARE the border. */
.btn-primary {
  background: var(--btn-primary-bevel), var(--color-primary);
  color: var(--color-white);
  border: none;
  box-shadow: var(--shadow-primary-pill);
}
.btn-primary:hover {
  background: var(--btn-primary-bevel), var(--color-primary-deep);
  box-shadow: var(--shadow-primary-pill-hover);
}
.btn-primary:active { transform: translateY(1px); box-shadow: var(--shadow-primary-pill); }

/* White pill — the CONTACT button. Same beveled-slab depth language as
   .btn-primary (white-tuned bevel + pill shadow), so both styles read
   equally dimensional. */
.btn-white {
  background: var(--btn-white-bevel), var(--color-surface);
  color: var(--color-primary-deep);
  border: none;
  box-shadow: var(--shadow-white-pill);
}
.btn-white:hover { box-shadow: var(--shadow-white-pill-hover); }

/* Buy pill — the PURCHASE button (opens a Square-hosted checkout). Emerald
   so commerce CTAs read instantly distinct from the blue action / white
   contact pair; same beveled-slab depth language. */
.btn-buy {
  background: var(--btn-buy-bevel), var(--btn-buy-fill);
  color: var(--color-white);
  border: none;
  box-shadow: var(--shadow-buy-pill);
}
.btn-buy:hover {
  background: var(--btn-buy-bevel), var(--color-success-deep);
  box-shadow: var(--shadow-buy-pill-hover);
}
.btn-buy:active { transform: translateY(1px); box-shadow: var(--shadow-buy-pill); }


/* ------------------------------------------------------------
   BUY MODAL — package picker opened by [data-buy-modal] triggers
   (js/buy-modal.js). The buyer picks a package (+ scent when the
   package includes a vitamin filter) and continues to the matching
   Square-hosted checkout.
   ------------------------------------------------------------ */
/* iOS-proof scroll lock: overflow:hidden alone doesn't stop touch
   scrolling in iOS Safari — fixing the body freezes it at the JS-saved
   scroll offset (body.style.top, set by buy-modal.js) and restores on
   close. overscroll-behavior on the sheet stops scroll chaining from the
   option list to the page. */
body.buym-lock {
  position: fixed;
  left: 0;
  right: 0;
  width: 100%;
  overflow: hidden;
}
.buym-overlay {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal-scrim);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: var(--modal-scrim);
  -webkit-backdrop-filter: var(--glass-blur-sm);
          backdrop-filter: var(--glass-blur-sm);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur) var(--ease);
  /* Backdrop swallows all touch gestures (incl. pinch-zoom). */
  touch-action: none;
}
.buym-overlay--open { opacity: 1; pointer-events: auto; }
.buym-sheet {
  position: relative;
  z-index: var(--z-modal);
  width: min(var(--modal-sheet-w), 100%);
  max-height: var(--modal-sheet-max-h);
  overflow-y: auto;
  overscroll-behavior: contain;
  /* Vertical pan only inside the sheet — blocks pinch-zoom + double-tap
     zoom while keeping the option list scrollable. */
  touch-action: pan-y;
  background: var(--color-surface);
  border-radius: var(--r-sheet) var(--r-sheet) 0 0;
  box-shadow: var(--shadow-3);
  padding: var(--modal-pad) var(--modal-pad) calc(var(--modal-pad) + env(safe-area-inset-bottom, 0px));
  transform: translateY(var(--modal-rise));
  transition: transform var(--dur) var(--ease);
}
.buym-overlay--open .buym-sheet { transform: translateY(0); }
@media (min-width: 600px) {
  .buym-overlay { align-items: center; padding: var(--space-page-x); }
  .buym-sheet { border-radius: var(--r-sheet); padding-bottom: var(--modal-pad); }
}
.buym-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
}
.buym-title {
  font-size: var(--text-lg);
  font-weight: 700;
  color: var(--text-primary);
  letter-spacing: -0.01em;
}
.buym-close {
  -webkit-appearance: none;
  appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--modal-close-size);
  height: var(--modal-close-size);
  border: none;
  border-radius: var(--r-pill);
  background: var(--color-surface-subtle);
  color: var(--text-muted);
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.buym-close:hover { background: var(--color-surface-light); color: var(--text-primary); }
.buym-note {
  font-size: var(--text-xs);
  color: var(--text-muted);
  margin: var(--space-xs) 0 var(--modal-gap-lg);
}
.buym-list {
  display: flex;
  flex-direction: column;
  gap: var(--modal-gap);
}
.buym-group-label {
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
  margin: var(--modal-gap-sm) 0 0;
}
.buym-list .buym-group-label:first-child { margin-top: 0; }
.buym-option {
  /* appearance:none — iOS Safari keeps NATIVE button rounding until a
     style change (e.g. the selected background) knocks it off, so the
     selected row rendered squarer than its siblings. Strip it and declare
     the capsule radius explicitly so every state matches. */
  -webkit-appearance: none;
  appearance: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  width: 100%;
  padding: var(--modal-row-pad);
  background: var(--color-surface);
  border: var(--modal-border-w) solid var(--card-border);
  border-radius: var(--r-pill);
  font-family: var(--font-sans);
  text-align: left;
  cursor: pointer;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
/* Exclude selected rows: `:hover` (2 classes) out-specifies `--selected`
   (1 class), so a tapped/hovered selected row showed a BLUE border over its
   green fill (touch devices keep :hover after a tap). */
.buym-option:not(.buym-option--selected):hover { border-color: var(--color-primary-border-strong); }
.buym-option--selected {
  border-color: var(--color-success);
  background: var(--color-success-bg);
}
.buym-option__info {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--modal-gap-sm);
}
.buym-option__name {
  font-size: var(--text-body-sm);
  font-weight: 600;
  color: var(--text-primary);
}
.buym-option__hint {
  font-size: var(--text-xs);
  color: var(--text-muted);
}

.buym-option__save {
  padding: var(--modal-badge-pad);
  border-radius: var(--r-pill);
  font-size: var(--text-2xs);
  font-weight: 700;
  color: var(--color-success);
  background: var(--color-success-bg-solid);
}
.buym-option__price {
  font-size: var(--text-body-sm);
  font-weight: 700;
  color: var(--text-primary);
  white-space: nowrap;
}
.buym-cta {
  width: 100%;
  margin-top: var(--space-md);
}


/* ------------------------------------------------------------
   FORM INPUT PRIMITIVES — glass-light, 12px radius
   ------------------------------------------------------------ */
.form-input,
.form-textarea,
.form-select,
input[type="text"],
input[type="email"],
input[type="tel"],
input[type="url"],
input[type="search"],
input[type="number"],
input[type="password"],
textarea,
select {
  width: 100%;
  padding: 0.8rem 1rem;
  font-family: var(--font-sans);
  font-size: var(--text-body);
  color: var(--text-primary);
  background: var(--glass-strong);
  -webkit-backdrop-filter: var(--glass-blur-sm);
          backdrop-filter: var(--glass-blur-sm);
  border: 1px solid var(--border-medium);
  border-radius: var(--r-input);
  box-shadow: var(--input-shadow);
  transition: border-color var(--dur) var(--ease),
              box-shadow   var(--dur) var(--ease),
              background   var(--dur) var(--ease);
  outline: none;
}

.form-input:focus,
.form-textarea:focus,
.form-select:focus,
input:focus,
textarea:focus,
select:focus {
  border-color: var(--color-primary);
  box-shadow: var(--input-shadow-focus);
  background-color: var(--color-surface);
}

.form-select,
select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 2.5rem;
  background-image: url("data:image/svg+xml,%3Csvg width='12' height='8' viewBox='0 0 12 8' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='currentColor' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 1rem center;
  cursor: pointer;
}


/* ------------------------------------------------------------
   BADGE / CHIP / TAG — solid tinted pills (inline on content)
   Hero badges use .glass--hero elsewhere.
   ------------------------------------------------------------ */
.badge,
.chip,
.tag {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.35rem 0.75rem;
  font-family: var(--font-sans);
  font-size: var(--text-caption);
  font-weight: 500;
  border-radius: var(--r-pill);
  background: var(--color-primary-tint-bg);
  color: var(--color-primary-deep);
  white-space: nowrap;
}

.badge--success     { background: var(--color-success-bg);     color: var(--color-success); }
.badge--warning     { background: var(--color-warning-bg);     color: var(--color-warning-text); }
.badge--destructive { background: var(--color-destructive-bg); color: var(--color-destructive); }
.badge--new {
  background: var(--color-ink);
  color: var(--color-white);
  font-family: var(--font-mono);
  font-size: var(--text-micro);
  font-weight: 600;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  border-radius: var(--r-sm);
  padding: 0.3rem 0.7rem;
}


/* ------------------------------------------------------------
   SECTION LABEL (eyebrow) — JetBrains Mono, uppercase
   ------------------------------------------------------------ */
.section-label,
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-mono);
  font-size: var(--text-eyebrow);
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--color-primary);
}

/* Eyebrow on colored/dark backgrounds */
.section-label.on-dark,
.eyebrow.on-dark {
  color: var(--text-on-dark-muted);
}


/* ------------------------------------------------------------
   FOCUS RING — applied globally via :focus-visible
   ------------------------------------------------------------ */
:focus-visible {
  outline: var(--focus-outline);
  outline-offset: var(--focus-offset);
  /* NOTE: never set `border-radius: inherit` here — it makes the FOCUSED
     element take its PARENT's radius (a focused pill in a square container
     went rectangular — buy-modal bug 2026-07-08). Modern browsers already
     follow the element's own radius for outlines. */
}

/* Reset default focus on interactive elements, we handle via :focus-visible */
a:focus,
button:focus,
input:focus,
textarea:focus,
select:focus,
[tabindex]:focus {
  outline: none;
}


/* ------------------------------------------------------------
   SKIP LINK — visible on focus only
   ------------------------------------------------------------ */
.skip-link {
  position: absolute;
  top: -999px;
  left: 0;
  z-index: var(--z-skip);
  padding: 0.75rem 1.25rem;
  background: var(--color-primary);
  color: var(--color-white);
  font-weight: 600;
  font-size: var(--text-body-sm);
  border-radius: var(--r-pill);
  text-decoration: none;
}
.skip-link:focus {
  top: 14px;
  left: 14px;
  box-shadow: var(--shadow-2);
}


/* ------------------------------------------------------------
   REDUCED MOTION
   ------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}
