/* ============================================================
   Betty Beauty — Animations
   Loaded on every page via /website/js/site.js
   All effects respect prefers-reduced-motion: reduce

   FAIL-SAFE RULE (2026-07-10, permanent):
   Initial-hidden states (opacity:0 / blur / translate) are gated behind
   html.bb-anim-ready. That class is set SYNCHRONOUSLY by bb-animations.js
   at IIFE start. If the JS never runs (network fail, SW stale, syntax
   error, ad-blocker) — the gate never activates and all animated content
   stays visible from the first paint. Never trap content behind an
   observer that might not fire.
   ============================================================ */

/* ═══ #1 Blur Text — per-word blur-in on viewport entry ═══ */
.bb-blur { display: inline; }
.bb-blur .w {
  display: inline-block;
  transition:
    opacity .6s cubic-bezier(.22,.61,.36,1),
    filter .6s cubic-bezier(.22,.61,.36,1),
    transform .6s cubic-bezier(.22,.61,.36,1);
  white-space: pre;
}
html.bb-anim-ready .bb-blur .w {
  opacity: 0;
  filter: blur(12px);
  transform: translateY(-8px);
}
/* Specificity MUST equal or exceed the gate above (html.bb-anim-ready ...)
   — otherwise the gate wins on cascade and content stays hidden after
   IntersectionObserver adds .is-in. Scope both under html for parity. */
html.bb-anim-ready .bb-blur.is-in .w { opacity: 1; filter: blur(0); transform: translateY(0); }
html.bb-anim-ready .bb-blur.is-in .w { transition-delay: calc(var(--i, 0) * 180ms); }

/* ═══ #1b Blur El — whole-element blur-in (i18n-safe: no inner splitting) ═══ */
.bb-blur-el {
  transition:
    opacity .8s cubic-bezier(.22,.61,.36,1),
    filter .8s cubic-bezier(.22,.61,.36,1),
    transform .8s cubic-bezier(.22,.61,.36,1);
}
html.bb-anim-ready .bb-blur-el {
  opacity: 0;
  filter: blur(10px);
  transform: translateY(-8px);
}
html.bb-anim-ready .bb-blur-el.is-in { opacity: 1; filter: blur(0); transform: translateY(0); }
.bb-anim-group .bb-blur-el { transition-delay: calc(var(--i, 0) * 120ms); }

/* ═══ Hero visual — floating diamonds + optional image/video slot ═══
   Sits between .hero-pattern and .hero-content in the layer stack. */
.hero-visual {
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow: hidden;
  pointer-events: none;
}

/* Media slot — right 65% of the hero on desktop, vignetted to fade into black */
.hero-visual-media {
  position: absolute;
  top: 0;
  bottom: 0;
  right: 0;
  width: 65%;
  /* Vignette: fully hidden 0-10%, gentle fade-in 10-40%, fully visible 40-100% */
  -webkit-mask-image: linear-gradient(
    90deg,
    transparent 0%,
    transparent 10%,
    rgba(0,0,0,0.4) 25%,
    #000 45%,
    #000 100%);
          mask-image: linear-gradient(
    90deg,
    transparent 0%,
    transparent 10%,
    rgba(0,0,0,0.4) 25%,
    #000 45%,
    #000 100%);
}
.hero-visual-media img,
.hero-visual-media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: brightness(0.75) contrast(1.05) saturate(1.05);
  transform-origin: 60% 50%;
  will-change: transform;
  /* Always visible — no opacity gate. Old fade-on-load logic could leave the
     element permanently invisible if the load event raced or was preempted
     by the browser cache path. Ken Burns still provides the animation touch. */
}
/* Ken Burns — slow zoom + subtle pan. Only for still images (video has its
   own motion). Alternates so it never snaps back. */
.hero-visual-media img {
  animation: bb-kenburns 26s ease-in-out infinite alternate;
}
@keyframes bb-kenburns {
  0%   { transform: scale(1.00) translate(0, 0); }
  100% { transform: scale(1.10) translate(-1.5%, -0.8%); }
}
/* No media configured → hide slot, diamonds carry the space */
.hero-visual:not(.has-media) .hero-visual-media { display: none; }
/* Media present → diamonds pull back so image can breathe */
.hero-visual.has-media .hero-diamond { opacity: 0.35; }
.hero-visual.has-media .hero-diamond:nth-child(n+5) { display: none; }

/* Diamonds */
.hero-diamonds { position: absolute; inset: 0; }
.hero-diamond {
  position: absolute;
  width: 18px;
  height: 18px;
  background: linear-gradient(135deg, #F0C84A 0%, #C9961E 60%, #7a5410 100%);
  transform: rotate(45deg);
  opacity: 0.55;
  border-radius: 2px;
  filter: drop-shadow(0 0 14px rgba(240,200,74,0.30));
  animation: bb-diamond-float 18s ease-in-out infinite;
  will-change: transform;
}
.hero-diamond:nth-child(1) { top: 14%; left:  8%; width: 14px; height: 14px; animation-duration: 14s; animation-delay:  -2s; opacity: 0.50; }
.hero-diamond:nth-child(2) { top: 66%; left: 20%; width: 22px; height: 22px; animation-duration: 22s; animation-delay:  -4s; opacity: 0.55; }
.hero-diamond:nth-child(3) { top: 26%; left: 44%; width: 10px; height: 10px; animation-duration: 12s; animation-delay:  -6s; opacity: 0.35; }
.hero-diamond:nth-child(4) { top: 52%; left: 76%; width: 24px; height: 24px; animation-duration: 20s; animation-delay:  -9s; opacity: 0.60; }
.hero-diamond:nth-child(5) { top: 18%; left: 84%; width: 12px; height: 12px; animation-duration: 16s; animation-delay: -12s; opacity: 0.45; }
.hero-diamond:nth-child(6) { top: 76%; left: 58%; width: 16px; height: 16px; animation-duration: 24s; animation-delay:  -5s; opacity: 0.45; }
.hero-diamond:nth-child(7) { top: 10%; left: 62%; width:  8px; height:  8px; animation-duration: 10s; animation-delay: -14s; opacity: 0.55; }
.hero-diamond:nth-child(8) { top: 42%; left: 14%; width: 12px; height: 12px; animation-duration: 18s; animation-delay:  -7s; opacity: 0.35; }

@keyframes bb-diamond-float {
  0%, 100% { transform: rotate(45deg) translate(0, 0); }
  25%      { transform: rotate(45deg) translate( 6px, -14px); }
  50%      { transform: rotate(45deg) translate(-8px,  10px); }
  75%      { transform: rotate(45deg) translate( 4px,  12px); }
}

/* Mobile — image adds nothing at portrait scale (competes with text for space
   and forces long scroll). Hide media slot entirely; diamonds carry the hero
   alone. Boost their opacity a bit and bring back the ones desktop dims when
   has-media is set. */
@media (max-width: 768px) {
  .hero-visual .hero-visual-media { display: none !important; }
  .hero-visual.has-media .hero-diamond { opacity: 0.55; }
  .hero-visual.has-media .hero-diamond:nth-child(n+5) { display: block; }
  /* Trim diamond count further so they don't crowd the small viewport. */
  .hero-diamond:nth-child(n+6) { display: none; }
  /* Force hero content visible on mobile — the IntersectionObserver-based
     reveal was leaving headline/sub/desc stuck at opacity 0 in portrait,
     probably because font swap shifted layout after IO's initial pass.
     Skip the reveal on mobile; the gradient text already provides visual life. */
  .hero .bb-blur-el {
    opacity: 1 !important;
    filter: none !important;
    transform: none !important;
  }
}

@media (prefers-reduced-motion: reduce) {
  .hero-diamond { animation: none !important; }
  .hero-visual-media img { animation: none !important; transform: none !important; }
  .hero-visual-media video { display: none !important; }
}

/* ═══ Hero gradient text — Betty Beauty brand palette, vivid infinite loop ═══
   Palette: white → bright gold → deep gold → wheat → cream → gold → bright gold → white
   Continuous linear loop (no alternate) via 400% background repeating. */
.bb-gradient-hero {
  background: linear-gradient(
    100deg,
    #FFFFFF 0%,
    #F0C84A 12%,
    #C9961E 22%,
    #C4A46A 33%,
    #F4ECD8 45%,
    #FFFFFF 55%,
    #F0C84A 67%,
    #C9961E 78%,
    #F4ECD8 90%,
    #FFFFFF 100%);
  background-size: 400% auto;
  background-position: 0% center;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  animation: bb-gradient-flow 6s linear infinite;
}
.bb-gradient-hero em,
.bb-gradient-hero span,
.bb-gradient-hero strong {
  /* inherit the gradient — override any local color rule */
  color: inherit !important;
  -webkit-text-fill-color: transparent !important;
  background: inherit;
  -webkit-background-clip: text;
  background-clip: text;
}
@keyframes bb-gradient-flow {
  0%   { background-position:   0% center; }
  100% { background-position: 400% center; }
}

/* ═══ #2 Shiny Text — continuous gold sweep ═══ */
.bb-shiny {
  background: linear-gradient(
    120deg,
    var(--gold, #C9961E) 0%,
    var(--gold, #C9961E) 35%,
    var(--gold2, #F0C84A) 50%,
    var(--gold, #C9961E) 65%,
    var(--gold, #C9961E) 100%);
  background-size: 200% auto;
  background-position: 150% center;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: bb-shiny-sweep 4s linear infinite;
  display: inline-block;
}
@keyframes bb-shiny-sweep {
  0%   { background-position: 150% center; }
  100% { background-position: -50% center; }
}

/* ═══ #3 Count-Up — no visual class needed; JS updates textContent
       Use .bb-count with data-target="N" and optional data-suffix="+"       ═══ */

/* ═══ #4 Scroll Reveal — words rotate+blur → clear as they enter ═══ */
.bb-reveal .w {
  display: inline-block;
  transition:
    opacity .5s ease,
    filter .5s ease,
    transform .5s ease;
  white-space: pre;
  transition-delay: calc(var(--i, 0) * 35ms);
}
html.bb-anim-ready .bb-reveal .w {
  opacity: 0.15;
  filter: blur(3px);
  transform: rotate(1deg);
}
html.bb-anim-ready .bb-reveal.is-in .w {
  opacity: 1;
  filter: blur(0);
  transform: rotate(0);
}

/* ═══ #5 Split Text — chars stagger fade+up ═══ */
.bb-split .c {
  display: inline-block;
  transition:
    opacity .55s cubic-bezier(.22,.61,.36,1),
    transform .55s cubic-bezier(.22,.61,.36,1);
  transition-delay: calc(var(--i, 0) * 30ms);
}
html.bb-anim-ready .bb-split .c {
  opacity: 0;
  transform: translateY(36px);
}
html.bb-anim-ready .bb-split.is-in .c { opacity: 1; transform: translateY(0); }

/* ═══ #6 Glare Hover — light streak crosses on hover ═══ */
.bb-glare {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}
.bb-glare::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    115deg,
    transparent 20%,
    rgba(255,255,255,0.28) 45%,
    rgba(240,200,74,0.42) 50%,
    rgba(255,255,255,0.28) 55%,
    transparent 80%);
  transform: translateX(-120%);
  transition: transform .9s cubic-bezier(.22,.61,.36,1);
  pointer-events: none;
  mix-blend-mode: overlay;
  z-index: 2;
}
.bb-glare:hover::after,
.bb-glare:focus-visible::after { transform: translateX(120%); }

/* ═══ #7 Animated Content — universal fade+slide on scroll ═══ */
.bb-anim {
  transition:
    opacity .6s cubic-bezier(.22,.61,.36,1),
    transform .6s cubic-bezier(.22,.61,.36,1);
}
html.bb-anim-ready .bb-anim {
  opacity: 0;
  transform: translateY(24px);
}
html.bb-anim-ready .bb-anim.is-in { opacity: 1; transform: translateY(0); }
/* Group stagger — when a parent has .bb-anim-group children are staggered */
.bb-anim-group .bb-anim { transition-delay: calc(var(--i, 0) * 90ms); }

/* ═══ #8 Grainient Overlay — DOES NOT replace existing background.
       Adds gold radial gradients + noise as ::before layer on top of whatever
       the container already renders. Content stays interactive via z-index. ═══ */
.bb-grainient {
  position: relative;
  isolation: isolate;
}
.bb-grainient::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(ellipse 60% 60% at 20% 30%, rgba(240,200,74,0.16), transparent 62%),
    radial-gradient(ellipse 55% 55% at 80% 70%, rgba(196,164,106,0.12), transparent 62%),
    radial-gradient(ellipse 100% 80% at 50% 50%, rgba(201,150,30,0.08), transparent 72%),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.79 0 0 0 0 0.59 0 0 0 0 0.12 0 0 0 0.30 0'/></filter><rect width='240' height='240' filter='url(%23n)' opacity='0.28'/></svg>");
  mix-blend-mode: overlay;
  opacity: 0.9;
}
.bb-grainient > * { position: relative; z-index: 1; }

/* ═══ Betty Diamonds perks — idle icon float + hover reward
   Applied to .loyalty-perk rows already in the DOM. Zero JS, pure CSS. */
.loyalty-perk {
  padding: 10px 14px;
  border-radius: 10px;
  border: 1px solid transparent;
  margin: 0 -14px; /* pull back so hover state doesn't shift layout */
  transition:
    background .35s cubic-bezier(.22,.61,.36,1),
    border-color .35s cubic-bezier(.22,.61,.36,1),
    transform .35s cubic-bezier(.22,.61,.36,1);
}
.loyalty-perk .loyalty-perk-icon {
  transition:
    transform .45s cubic-bezier(.22,.61,.36,1),
    border-color .35s ease,
    background .35s ease,
    box-shadow .35s ease,
    color .35s ease;
  animation: bb-perk-float 5s ease-in-out infinite;
  will-change: transform;
}
/* Stagger the idle float so the three icons breathe out of sync */
.loyalty-perk:nth-child(1) .loyalty-perk-icon { animation-delay: 0s; }
.loyalty-perk:nth-child(2) .loyalty-perk-icon { animation-delay: -1.7s; }
.loyalty-perk:nth-child(3) .loyalty-perk-icon { animation-delay: -3.4s; }

@keyframes bb-perk-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-5px); }
}

/* Hover reward — row nudges right + icon gets a gold ring + title glows */
.loyalty-perk:hover {
  background: linear-gradient(90deg, rgba(240,200,74,.06), rgba(240,200,74,.02) 60%, transparent);
  border-color: rgba(240,200,74,.18);
  transform: translateX(6px);
}
.loyalty-perk:hover .loyalty-perk-icon {
  background: rgba(240,200,74,.16);
  border-color: rgba(240,200,74,.75);
  color: #F0C84A;
  box-shadow:
    0 0 0 4px rgba(240,200,74,.10),
    0 0 28px -4px rgba(240,200,74,.55);
  transform: scale(1.15) rotate(-6deg) translateY(-6px);
}
.loyalty-perk:hover .loyalty-perk-title {
  text-shadow: 0 0 14px rgba(240,200,74,.4);
}
.loyalty-perk:hover .loyalty-perk-desc {
  color: rgba(216,195,165,.92);
}
/* BD number values inside perk descriptions pop slightly harder on hover */
.loyalty-perk:hover .loyalty-perk-desc [data-bd-key] {
  color: #F0C84A;
  font-weight: 600;
}

@media (prefers-reduced-motion: reduce) {
  .loyalty-perk .loyalty-perk-icon { animation: none !important; }
  .loyalty-perk,
  .loyalty-perk:hover,
  .loyalty-perk:hover .loyalty-perk-icon {
    transition: none !important;
    transform: none !important;
  }
}

/* ═══ Navbar polish — link underline reveal + logo shine + Book Now shine
   Applied via classes already in main.css (no HTML changes for underlines).
   All effects are pure CSS; nothing here breaks existing hover states. */

/* Nav link hover — hairline gold underline draws in from the left */
.nav-links a {
  position: relative;
  padding-bottom: 3px;
}
.nav-links a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -2px;
  height: 1.5px;
  background: linear-gradient(90deg,
    transparent 0%,
    var(--gold, #C9961E) 15%,
    #F0C84A 50%,
    var(--gold, #C9961E) 85%,
    transparent 100%);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .35s cubic-bezier(.22,.61,.36,1);
}
.nav-links a:hover::after,
.nav-links a:focus-visible::after,
.nav-links a.active::after {
  transform: scaleX(1);
}
/* Active link — pin the underline so it always shows without the animate-in */
.nav-links a.active::after {
  transition-duration: 0s;
}

/* Logo — subtle shine sweep every 10s. Uses ::before overlay on a wrapper
   applied via .bb-logo-shine class on the anchor. Doesn't touch img. */
.nav-logo {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}
.nav-logo::after {
  content: "";
  position: absolute;
  top: -20%;
  bottom: -20%;
  left: -50%;
  width: 60%;
  background: linear-gradient(
    115deg,
    transparent 0%,
    rgba(240,200,74,0.30) 45%,
    rgba(255,255,255,0.50) 50%,
    rgba(240,200,74,0.30) 55%,
    transparent 100%);
  transform: translateX(-120%) skewX(-18deg);
  pointer-events: none;
  mix-blend-mode: overlay;
  animation: bb-logo-shine 10s ease-in-out infinite;
  animation-delay: 3s;
}
@keyframes bb-logo-shine {
  0%, 8%  { transform: translateX(-120%) skewX(-18deg); opacity: 0; }
  14%     { opacity: 1; }
  32%     { transform: translateX(280%) skewX(-18deg); opacity: 1; }
  38%, 100% { transform: translateX(280%) skewX(-18deg); opacity: 0; }
}

/* BOOK NOW — occasional shine sweep on the nav CTA button.
   Applied by wrapping in .bb-nav-cta or by targeting .nav-actions .btn-primary. */
.nav-actions .btn-primary {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}
.nav-actions .btn-primary::before {
  content: "";
  position: absolute;
  top: 0; bottom: 0;
  left: 0;
  width: 45%;
  background: linear-gradient(
    115deg,
    transparent 0%,
    rgba(255,255,255,0.55) 45%,
    rgba(255,255,255,0.95) 50%,
    rgba(255,255,255,0.55) 55%,
    transparent 100%);
  transform: translateX(-120%) skewX(-18deg);
  pointer-events: none;
  mix-blend-mode: overlay;
  animation: bb-nav-cta-shine 7s ease-in-out infinite;
  animation-delay: 1.5s;
}
@keyframes bb-nav-cta-shine {
  0%, 10%  { transform: translateX(-120%) skewX(-18deg); opacity: 0; }
  15%      { opacity: 1; }
  30%      { transform: translateX(320%) skewX(-18deg); opacity: 1; }
  35%, 100% { transform: translateX(320%) skewX(-18deg); opacity: 0; }
}

/* Language toggle — subtle color pulse when it's "changed" (add .lang-flash class
   in JS after switching). Kept off by default. */
.nav-lang-btn.lang-flash {
  animation: bb-lang-flash .9s ease-out;
}
@keyframes bb-lang-flash {
  0%   { color: rgba(255,255,255,.6); transform: scale(1); }
  30%  { color: #F0C84A; transform: scale(1.1); }
  100% { color: rgba(255,255,255,.6); transform: scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  .nav-links a::after,
  .nav-logo::after,
  .nav-actions .btn-primary::before,
  .nav-lang-btn.lang-flash {
    animation: none !important;
    transition: none !important;
  }
  .nav-logo::after,
  .nav-actions .btn-primary::before { display: none; }
}

/* ═══ Living CTA — 4 layers on the "Join Betty Diamonds" button
   1. Breathing idle    → wrapper translates Y ±4px in 4s loop
   2. Magnetic pull     → handled by .bb-magnet on same wrapper (existing)
   3. Shine sweep       → ::before sweeps across button every 5s
   4. Pulse ring        → wrapper's ::after expands like a heartbeat 3s

   Layers 1 & 4 live on the WRAPPER (.bb-cta-living), so the magnet's
   translate on the child button doesn't drag the ring with it — the
   ring stays anchored to the block's calm rest position while the
   button gently pulls toward the cursor. */
.bb-cta-living {
  display: inline-block;
  position: relative;
  animation: bb-cta-breath 4s ease-in-out infinite;
  will-change: transform;
}
@keyframes bb-cta-breath {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-4px); }
}

/* Pulse ring — heartbeat every 3s, offset so it appears BEHIND the button */
.bb-cta-living::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 999px;
  border: 2px solid rgba(240,200,74,.6);
  pointer-events: none;
  opacity: 0;
  animation: bb-cta-pulse 3s ease-out infinite;
  z-index: -1;
}
@keyframes bb-cta-pulse {
  0%   { transform: scale(0.92); opacity: 0; }
  18%  { opacity: 0.7; }
  100% { transform: scale(1.55); opacity: 0; }
}

/* Shine sweep across the button surface every 5s */
.bb-cta-alive {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}
.bb-cta-alive::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 40%;
  background: linear-gradient(
    115deg,
    transparent 0%,
    rgba(255,255,255,0.55) 45%,
    rgba(255,255,255,0.95) 50%,
    rgba(255,255,255,0.55) 55%,
    transparent 100%);
  transform: translateX(-120%) skewX(-18deg);
  pointer-events: none;
  mix-blend-mode: overlay;
  animation: bb-cta-shine 5s ease-in-out infinite;
}
@keyframes bb-cta-shine {
  0%, 12%   { transform: translateX(-120%) skewX(-18deg); opacity: 0; }
  18%       { opacity: 1; }
  42%       { transform: translateX(320%) skewX(-18deg); opacity: 1; }
  48%, 100% { transform: translateX(320%) skewX(-18deg); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .bb-cta-living,
  .bb-cta-living::after,
  .bb-cta-alive::before {
    animation: none !important;
    transform: none !important;
  }
  .bb-cta-living::after,
  .bb-cta-alive::before { display: none; }
}

/* ═══ Betty Diamonds heading gradient — champagne + diamond flow
   Palette combines warm champagne-gold with subtle diamond-blue and
   rose highlights. Slower loop than the hero so the two headings feel
   different but part of the same brand family. */
.bb-gradient-bd {
  background: linear-gradient(
    100deg,
    #F4ECD8  0%,   /* cream */
    #F0C84A 12%,   /* bright gold */
    #E8C4B8 22%,   /* rose champagne */
    #C9961E 35%,   /* deep gold */
    #FFFFFF 48%,   /* white peak */
    #F0C84A 58%,   /* bright gold */
    #A8D9FF 70%,   /* diamond blue accent */
    #F4ECD8 82%,   /* cream */
    #F0C84A 92%,   /* bright gold */
    #F4ECD8 100%); /* cream */
  background-size: 350% auto;
  background-position: 0% center;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  animation: bb-gradient-bd-flow 10s linear infinite;
  display: inline-block; /* so background-clip:text sizes correctly */
}
.bb-gradient-bd em,
.bb-gradient-bd span,
.bb-gradient-bd strong {
  color: inherit !important;
  -webkit-text-fill-color: transparent !important;
  background: inherit;
  -webkit-background-clip: text;
  background-clip: text;
}
@keyframes bb-gradient-bd-flow {
  0%   { background-position:   0% center; }
  100% { background-position: 350% center; }
}
@media (prefers-reduced-motion: reduce) {
  .bb-gradient-bd {
    animation: none !important;
    -webkit-text-fill-color: var(--gold, #C9961E) !important;
    background: none !important;
  }
}

/* ═══ Betty Diamonds tier spotlight — follows cursor, coloured per metal/gem
   Applied to .loyalty-tier rows via .bb-tier-glow class (added by JS on init).
   Each tier picks up its own colour from a CSS variable. */
.loyalty-tier {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  transition: transform .4s cubic-bezier(.22,.61,.36,1),
              box-shadow .4s cubic-bezier(.22,.61,.36,1);
}
.loyalty-tier > * { position: relative; z-index: 1; }
.loyalty-tier::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(
    260px circle at var(--mx, 50%) var(--my, 50%),
    var(--tier-glow, rgba(255,255,255,0.18)),
    transparent 65%);
  opacity: 0;
  transition: opacity .35s ease;
  pointer-events: none;
  z-index: 0;
}
.loyalty-tier:hover::before,
.loyalty-tier:focus-within::before { opacity: 1; }
.loyalty-tier:hover {
  transform: translateY(-1px);
  box-shadow: 0 0 44px -10px var(--tier-glow, rgba(255,255,255,0.18));
}

/* Palette per tier — chosen to match the metal / gem the tier represents. */
.loyalty-tier.tier-standard { --tier-glow: rgba(230, 230, 230, 0.22); } /* neutral silver-white */
.loyalty-tier.tier-bronze   { --tier-glow: rgba(210, 130,  55, 0.55); } /* warm bronze */
.loyalty-tier.tier-silver   { --tier-glow: rgba(215, 220, 235, 0.55); } /* cool silver */
.loyalty-tier.tier-gold     { --tier-glow: rgba(240, 200,  74, 0.60); } /* Betty gold */
.loyalty-tier.tier-diamond  { --tier-glow: rgba( 96, 200, 255, 0.65); } /* premium diamond blue */

/* Touch devices — no cursor, so pin the glow to the right side as a subtle
   ambient breathing highlight. Never fully off. */
@media (hover: none) {
  .loyalty-tier::before {
    background: radial-gradient(
      70% 120% at 100% 50%,
      var(--tier-glow, rgba(255,255,255,0.15)),
      transparent 70%);
    opacity: 0.7;
  }
}

@media (prefers-reduced-motion: reduce) {
  .loyalty-tier { transition: none !important; }
  .loyalty-tier:hover { transform: none !important; }
  .loyalty-tier::before { transition: none !important; }
}

/* ═══ #9 Magnet CTA — no visual class; JS toggles transform.
       Add class .bb-magnet to a wrapper; the JS acts on its first button/link. ═══ */
.bb-magnet { display: inline-block; }
.bb-magnet > * { will-change: transform; transition: transform .3s cubic-bezier(.22,.61,.36,1); }

/* ═══ Reduced motion — disable everything ═══ */
@media (prefers-reduced-motion: reduce) {
  .bb-shiny, .bb-gradient-hero {
    animation: none !important;
    -webkit-text-fill-color: var(--gold, #C9961E) !important;
    background: none !important;
  }
  .bb-blur .w, .bb-reveal .w, .bb-split .c, .bb-anim,
  .bb-magnet > * {
    opacity: 1 !important;
    filter: none !important;
    transform: none !important;
    transition: none !important;
  }
  .bb-glare::after { display: none !important; }
}
