/* ==========================================================================
   MINDBITES — CROSS-DEVICE POLISH  (refactored, single source of truth)
   Load AFTER styles.css:  <link rel="stylesheet" href="mobile-polish.css">

   Breakpoint standard used throughout this file:
     • Mobile:  max-width: 767px
     • Tablet:  min-width: 768px and max-width: 1023px
     • Desktop: min-width: 1024px

   Motion tokens (single place duration & easing live):
     --ease-premium  cubic-bezier(0.16, 1, 0.3, 1)  ("easeOutExpo")
     --dur-sm .45s   /  --dur-md .72s  /  --dur-lg 1.05s

   Rules to preserve when editing:
     - Only animate opacity/transform. NEVER box-shadow/filter/width.
     - `will-change` only while element is mid-animation; release once settled.
     - Every eye-visible spacing snapped to 8-pt grid (8/16/24/32/48).
     - Every WebKit-only property has its `-webkit-` prefix.
   ========================================================================== */


/* ─────────────────────────────────────────────────────────────────────────────
   0. DESIGN TOKENS
   ───────────────────────────────────────────────────────────────────────────── */
:root{
  --ease-premium: cubic-bezier(0.16, 1, 0.3, 1);
  --dur-sm: .6s;     /* bumped — matches the loop-circle pop timing the user likes */
  --dur-md: 1.0s;    /* bumped — Windows Chrome reads faster durations as janky */
  --dur-lg: 1.6s;    /* matches the loop-path draw (1.6s) exactly — the "gold standard"
                        smoothness reference in this project. Slower = smoother on
                        integrated GPUs, because per-frame delta is smaller. */

  /* Font fallback stack — Manrope+Inter primary, then full cross-OS
     system fallback (Segoe UI on Windows, San Francisco on macOS/iOS,
     Roboto on Android) so an offline visitor never sees ugly Times New Roman. */
  --font-fallback: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
                   "Helvetica Neue", Arial, sans-serif;
}
/* Override styles.css's shorter font stacks with the full fallback set. */
body,
input, button, select, textarea{
  font-family: "Manrope", "Inter", var(--font-fallback);
}
h1, h2, h3, h4, h5, h6{
  font-family: "Manrope", "Inter", var(--font-fallback);
}


/* ─────────────────────────────────────────────────────────────────────────────
   1. BROWSER COMPAT & POLISH (all viewports)
   ───────────────────────────────────────────────────────────────────────────── */

/* Font rendering — antialiased text prevents Safari sub-pixel shimmer on
   smooth scroll (high-DPI screens especially). */
body{
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

/* iOS/Android tap fixes */
html{ -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
a, button, .chip, .acc>button, .opt, .nav-btn, .fchip, .pill{
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;                /* removes ~300ms mobile tap delay */
}
.mb-ticker-track{
  -webkit-user-select: none;                 /* was missing — Safari < 16 fix */
  user-select: none;
}

/* iOS Safari zooms into any input with font-size < 16px — force minimum on mobile. */
@media (max-width: 767px){
  input, select, textarea, .search input{ font-size: 16px !important; }
}

/* Dynamic viewport height for iOS URL-bar collapse. */
@supports (height: 100dvh){
  .sheet-panel, .drawer{ height: 100dvh; }
  .sim{ max-height: 92dvh; }
}
.sheet-panel, .drawer, .sim{ -webkit-overflow-scrolling: touch; }


/* ─────────────────────────────────────────────────────────────────────────────
   2. TYPOGRAPHY
   ───────────────────────────────────────────────────────────────────────────── */

/* Small-label readability bumps — audit flagged these as too tight (11-12px). */
.verify        { font-size: 12px; }                       /* was 10px  */
.fact .lbl     { font-size: 12px; }                       /* was 11px  */
.disclaimer    { font-size: 13px; line-height: 1.55; }    /* was 12px  */

/* Section numbers removed from every eyebrow. */
.eyebrow .num{ display: none; }

/* WebKit text-shadow fix — large-blur shadows on headings rasterize as hard
   grey rectangles inside overflow:hidden reveal wrappers in Safari. */
h1, h2, body.dark h1, body.dark h2{ text-shadow: none; }

/* Mobile: allow long headings to wrap, long unbreakable strings to break. */
@media (max-width: 767px){
  h1, h2, h3{
    overflow-wrap: break-word;
    word-wrap: break-word;
    word-break: normal;
    hyphens: manual;
  }
  p, li, .lead, .muted, .fine, .note, .crumbs, .acc-panel .inner{
    overflow-wrap: anywhere;
    word-wrap: break-word;
  }
  .tag, .pill, .chip, .fchip, .status{ max-width: 100%; white-space: normal; }
}
pre, code{ overflow-wrap: anywhere; word-wrap: break-word; white-space: pre-wrap; }


/* ─────────────────────────────────────────────────────────────────────────────
   3. HORIZONTAL-OVERFLOW GUARDS (mobile safety net)
   ───────────────────────────────────────────────────────────────────────────── */
@media (max-width: 767px){
  html, body{ overflow-x: hidden; max-width: 100vw; }

  img, video, svg, canvas, iframe, picture{ max-width: 100%; height: auto; }
  .chart-card canvas{ height: auto; max-width: 100%; }

  .search, .search input{ min-width: 0; }       /* styles.css sets 200px, overflows small phones */
  .grid > *, .hero > *, .facts > *,
  .sim-metrics > *, .readout > *{ min-width: 0; }

  .thunder-flash, #scroll-progress{
    max-width: 100vw; left: 0; right: 0;
  }
}
/* Table safety — universal, if any FAQ answer ever includes tabular data. */
table{
  max-width: 100%;
  display: block;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}


/* ─────────────────────────────────────────────────────────────────────────────
   4. TOUCH TARGETS (WCAG 2.5.5 / Apple HIG 44×44px)
   ───────────────────────────────────────────────────────────────────────────── */
.btn--sm     { min-height: 44px; }                      /* CRITICAL: was 36px  */
.acc > button{ min-height: 48px; }                      /* FAQ accordion header */
.ft-bottom .links a,
.ft-bottom .links span{
  display: inline-flex; align-items: center;
  min-height: 32px; padding: 4px 0;                      /* larger tap area for footer links */
}


/* ─────────────────────────────────────────────────────────────────────────────
   5. HEADLINE DESCENDER FIX + PRODUCT-IMAGE SHADOW POLISH
   ───────────────────────────────────────────────────────────────────────────── */

/* clip-reveal wrapper: room for descenders (g, y, p, j) inside overflow:hidden. */
.clip-reveal{ padding-bottom: .22em; margin-bottom: -.22em; }
.clip-reveal-inner{ padding-bottom: .02em; }

/* Mobile: cancel the negative-margin trick (no clip-reveal animation runs on
   mobile — see §12), so heading text can never overlap the eyebrow above. */
@media (max-width: 767px){
  .clip-reveal{ padding-bottom: 0 !important; margin-bottom: 0 !important; }
}

/* WebKit drop-shadow fix on product image — stacked heavy filters get
   clipped into a hard band in Safari. Keep one small filter on desktop
   only, plus a gradient ground shadow (pure gradient, no filter). */
.mb-hero-img, .mb-panel-img{
  filter: drop-shadow(0 10px 16px rgba(0,0,0,.14));
}
body.dark .mb-hero-img, body.dark .mb-panel-img{
  filter: drop-shadow(0 10px 16px rgba(0,0,0,.40));
}
@media (max-width: 767px){
  .mb-hero-img, .mb-panel-img,
  body.dark .mb-hero-img, body.dark .mb-panel-img{ filter: none; }
}

.hero-img-wrap::after,
.imgbox.mb-imgbox-clean::after{
  content: ""; display: block; position: absolute; left: 50%; bottom: 3%;
  width: min(62%, 330px); height: clamp(14px, 4vw, 28px);
  transform: translateX(-50%); border-radius: 50%;
  background: radial-gradient(closest-side,
    rgba(23,25,31,.15), rgba(23,25,31,.06) 55%, rgba(23,25,31,0) 100%);
  z-index: 1; pointer-events: none;
}
body.dark .hero-img-wrap::after,
body.dark .imgbox.mb-imgbox-clean::after{
  background: radial-gradient(closest-side,
    rgba(0,0,0,.55), rgba(0,0,0,.22) 55%, rgba(0,0,0,0) 100%);
}
@media (max-width: 767px){
  .hero-img-wrap::after{ bottom: 13%; width: 48%; }
}
@media (max-width: 519px){
  .hero-img-wrap::after{ bottom: 17%; width: 44%; }
}


/* ─────────────────────────────────────────────────────────────────────────────
   6. BACKGROUNDS
   ───────────────────────────────────────────────────────────────────────────── */
.bg-cloud{ background: var(--cloud); }


/* ─────────────────────────────────────────────────────────────────────────────
   7. FAQ ACCORDION
   ───────────────────────────────────────────────────────────────────────────── */
.acc.open > button{ padding-bottom: 8px; }
.acc-panel .inner{ padding: 2px 20px 16px; line-height: 1.55; font-size: 15px; }
.acc-panel .inner p{ margin: 0 0 10px; }
.acc-panel .inner > *:last-child{ margin-bottom: 0; }
.acc-panel .inner a, .acc-panel .inner button{ margin-right: 4px; }
@media (max-width: 519px){
  .acc-panel .inner{ padding: 2px 14px 13px; font-size: 14px; }
}


/* ─────────────────────────────────────────────────────────────────────────────
   8. MOTION SYSTEM  (all reveal animations, one place)
   ───────────────────────────────────────────────────────────────────────────── */

/* .sr / .sr-left / .sr-right — used site-wide by app.js for scroll reveals. */
.sr, .sr-left, .sr-right{
  transition: opacity var(--dur-lg) var(--ease-premium),
              transform var(--dur-lg) var(--ease-premium) !important;
}
.sr:not(.sr-visible){        transform: translate3d(0, 28px, 0); }
.sr-left:not(.sr-visible){   transform: translate3d(-32px, 0, 0); }
.sr-right:not(.sr-visible){  transform: translate3d(32px, 0, 0); }
.sr:not(.sr-visible),
.sr-left:not(.sr-visible),
.sr-right:not(.sr-visible){ will-change: opacity, transform; }
.sr.sr-visible, .sr-left.sr-visible, .sr-right.sr-visible{
  will-change: auto; transform: translate3d(0, 0, 0);
}

/* .reveal-left / .reveal-right / .reveal-up — center-converging premium reveal. */
.reveal-left, .reveal-right, .reveal-up{ transition-duration: var(--dur-lg) !important; }
.reveal-left:not(.reveal-active) { transform: translate3d(-40px, 0, 0) scale(.98) !important; }
.reveal-right:not(.reveal-active){ transform: translate3d(40px,  0, 0) scale(.98) !important; }
.reveal-up:not(.reveal-active)   { transform: translate3d(0, 32px, 0) scale(.99) !important; }
.reveal-left.reveal-active, .reveal-right.reveal-active, .reveal-up.reveal-active{
  will-change: auto;
}

/* .hl-word — hero headline word-by-word reveal. */
.hl-word{
  transition: transform var(--dur-lg) var(--ease-premium),
              opacity   var(--dur-md) var(--ease-premium) !important;
}

/* .clip-reveal — heading rise-up animation. */
.clip-reveal-inner{
  transition: transform var(--dur-lg) var(--ease-premium) !important;
}
.clip-reveal.in-view .clip-reveal-inner{ will-change: auto; }

/* .sr-edge — app.js's edge-reveal system. Tiered duration by element size. */
.sr-edge{
  transition: opacity var(--dur-md) var(--ease-premium),
              transform var(--dur-md) var(--ease-premium) !important;
}
.imgbox.sr-edge, .doypack-visual.sr-edge, .chart-card.sr-edge,
.founder-arc.sr-edge, .signup.sr-edge{ transition-duration: var(--dur-lg) !important; }
.eyebrow.sr-edge, .btn-row.sr-edge{ transition-duration: var(--dur-sm) !important; }

/* Desktop distances — SHORT. Per-frame pixel delta is what makes an
   animation feel janky on integrated GPUs: a 56px travel over 0.72s is
   ~1.3px/frame at 60fps, but over a longer duration with less distance
   it's sub-pixel and reads perfectly smooth. Matched to the loop-circle
   feel (which barely moves — it just scales 0→1 in place). */
@media (min-width: 1024px){
  .sr-edge.from-left  { transform: translate3d(-20px, 0, 0) !important; }
  .sr-edge.from-right { transform: translate3d(20px, 0, 0) !important; }
  .sr-edge.from-top   { transform: translate3d(0, -14px, 0) !important; }
  .sr-edge.from-bot   { transform: translate3d(0, 16px, 0) !important; }
  .sr-edge.from-scale { transform: scale3d(.97,.97,1) !important; }
  .sr-edge.in-view    { transform: translate3d(0, 0, 0) scale3d(1, 1, 1) !important; }
}
@media (max-width: 767px){
  .sr-edge.from-left, .sr-edge.from-right, .sr-edge.from-top,
  .sr-edge.from-bot, .sr-edge.from-scale{
    transform: translate3d(0, 12px, 0) !important;
  }
}
/* .sr / .sr-left / .sr-right — text glides in from the LEFT edge (per
   user request), at the loop-path's calm 1.6s pace. Distance stays short
   so per-frame delta is sub-pixel — that's what makes it read as smooth
   on integrated GPUs, not the duration alone. */
.sr:not(.sr-visible){        transform: translate3d(-22px, 0, 0) !important; }
.sr-left:not(.sr-visible){   transform: translate3d(-22px, 0, 0) !important; }
.sr-right:not(.sr-visible){  transform: translate3d(22px, 0, 0) !important; }

/* Section body copy, leads, notes, eyebrows — glide from the left too,
   matching the headline. Only the ones app.js marks with .sr scaffolding
   are affected; nothing else on the page moves. */
.lead.sr:not(.sr-visible),
p.sr:not(.sr-visible),
.note.sr:not(.sr-visible),
.eyebrow.sr:not(.sr-visible){
  transform: translate3d(-24px, 0, 0) !important;
}
/* .reveal-* — same. */
.reveal-left:not(.reveal-active) { transform: translate3d(-20px, 0, 0) !important; }
.reveal-right:not(.reveal-active){ transform: translate3d(20px, 0, 0) !important; }
.reveal-up:not(.reveal-active)   { transform: translate3d(0, 16px, 0) !important; }
.sr-edge.in-view{ will-change: auto; }

/* Carve-outs — permanent transforms/hover-lifts that get flattened by the
   in-view `transform: none !important` rule above. Restore them. */
@media (min-width: 1024px){
  .profile.feat.sr-edge.in-view    { transform: translate3d(0, -10px, 0) scale3d(1,1,1) !important; }
  .card.sr-edge.in-view:hover      { transform: translate3d(0, -4px, 0)  scale3d(1,1,1) !important; }
  .fact.sr-edge.in-view:hover      { transform: translate3d(0, -3px, 0)  scale3d(1,1,1) !important; }
}

/* Founder portraits and profile card must never be clipped by any parent. */
.founder-arc, .founder-arc *, .profile, .profile *{
  contain: none !important;
  overflow: visible !important;
}

/* .mb-icon-pop — small-icon staggered pop-in (wired by simulator-v2.js). */
.mb-icon-pop{
  opacity: 0; transform: scale(.8) translateY(6px);
  transition: opacity var(--dur-sm) var(--ease-premium),
              transform var(--dur-sm) var(--ease-premium);
  will-change: opacity, transform;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}
.mb-icon-pop.mb-icon-in{
  opacity: 1; transform: scale(1) translateY(0);
  will-change: auto;
}

/* .tl-item — Founders origin timeline: staggered reveal + circle pop + line draw. */
.tl-item{
  transition: opacity var(--dur-lg) var(--ease-premium),
              transform var(--dur-lg) var(--ease-premium) !important;
  will-change: opacity, transform;
}
.tl-item.sr-visible{ will-change: auto; }
.tl-item:nth-of-type(1){ transition-delay: 0ms   !important; }
.tl-item:nth-of-type(2){ transition-delay: 180ms !important; }
.tl-item:nth-of-type(3){ transition-delay: 360ms !important; }
.tl-item:nth-of-type(4){ transition-delay: 540ms !important; }
.tl-item:nth-of-type(5){ transition-delay: 720ms !important; }

.tl-item::before{
  transform: scale(0) !important; opacity: 0;
  transition: transform var(--dur-md) cubic-bezier(.34, 1.56, .64, 1),
              opacity var(--dur-sm) ease !important;
}
.tl-item.sr-visible::before, .tl-item.in-view::before{
  transform: scale(1) !important; opacity: 1;
}
.tl-item:nth-of-type(1)::before{ transition-delay: 200ms !important; }
.tl-item:nth-of-type(2)::before{ transition-delay: 380ms !important; }
.tl-item:nth-of-type(3)::before{ transition-delay: 560ms !important; }
.tl-item:nth-of-type(4)::before{ transition-delay: 740ms !important; }
.tl-item:nth-of-type(5)::before{ transition-delay: 920ms !important; }

.timeline::before{
  transform-origin: top center;
  transform: scaleY(0);
  transition: transform 1.4s var(--ease-premium);
}
.timeline.sr-visible::before,
.timeline.in-view::before,
.timeline[data-revealed="1"]::before{ transform: scaleY(1); }
/* `:has()` deliberately avoided here — Chrome only shipped it in v105,
   and a browser that doesn't understand :has() DROPS THE ENTIRE RULE
   including the two valid selectors above it. That would leave the
   timeline connector line permanently at scaleY(0) — invisible. */

@media (min-width: 768px){
  .tl-item{ margin-bottom: 8vh; }
  .tl-item:last-child{ margin-bottom: 0; }
}

/* Hero pouch breathing float (compositor-only). */
@keyframes mbFloat{ 0%,100%{transform:translateY(0)} 50%{transform:translateY(-7px)} }
.hero-img-wrap{ animation: mbFloat 6.5s ease-in-out infinite; }

/* Promo ticker — right-to-left scroll. Animation defined in styles.css
   (`mbTickerScroll` keyframes on `.mb-ticker-track`), but the animation
   sometimes reads as "stuck" because 32s for the full cycle is very slow
   AND several things can silently pause it: parent hover state stuck on,
   content-visibility: auto rendering skip, or a fresh compositor layer
   that never settles. Explicit re-declaration below forces it to run,
   faster (24s), with WebKit prefix + explicit play-state so nothing
   above can cancel it. Hover-pause kept intact. */
/* Own dedicated keyframes name (`mbTickScrollV2`) so nothing in
   styles.css or app.js can accidentally cancel it. */
@-webkit-keyframes mbTickScrollV2{
  from{ -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); }
  to  { -webkit-transform: translate3d(-50%, 0, 0); transform: translate3d(-50%, 0, 0); }
}
@keyframes mbTickScrollV2{
  from{ transform: translate3d(0, 0, 0); }
  to  { transform: translate3d(-50%, 0, 0); }
}
.mb-ticker-track{
  -webkit-animation: mbTickScrollV2 22s linear infinite !important;
  animation:         mbTickScrollV2 22s linear infinite !important;
  -webkit-animation-play-state: running !important;
  animation-play-state: running !important;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
  will-change: transform;
  transform: translateZ(0);      /* forces own compositor layer — prevents
                                    parent 'overflow:hidden' from silently
                                    pausing the animation on some engines */
}
/* Only pause on TRUE hover (mouse-only devices). On touch, `:hover` sticks
   after tap on some browsers, which was silently freezing the ticker. */
@media (hover: hover) and (pointer: fine){
  .mb-ticker:hover .mb-ticker-track{
    -webkit-animation-play-state: paused !important;
    animation-play-state: paused !important;
  }
}
/* Nothing may cancel the animation on any ancestor state — belt-and-suspenders
   in case a parent gets an accidental `animation: none` from some cascade. */
.mb-ticker, .mb-ticker *:not(a):not(button){ animation-play-state: running; }

/* Loop-svg arrow marker — was covered by the Explain circle, hide it. */
.loop-svg path{ marker-end: none !important; }


/* ═════════════════════════════════════════════════════════════════════════
   ROADMAP PILLS  ("Concept → Formula → Testing → Production → Launch")
   Each pill fills from LEFT to RIGHT in its own colour, one after another,
   like a progress bar being drawn. Same feel as the loop-path draw (which
   uses stroke-dashoffset) but implemented with scaleX — the cheapest
   possible GPU operation, works identically on every browser.

   Colours preserved exactly from styles.css:
     .stg.done .bar → var(--success)  (green — finished stages)
     .stg.cur  .bar → var(--action)   (navy — current stage)
     .stg      .bar → var(--mist)     (grey — not started)
   The grey ones stay grey and DON'T animate — they're not "lit up" yet,
   matching the user's description.
   ═════════════════════════════════════════════════════════════════════════ */

/* Track — the grey base rail is always visible immediately. */
.stg .bar{
  position: relative;
  overflow: hidden;
  background: var(--mist) !important;
}

/* The coloured fill is a pseudo-element that scales in from the left.
   Only .done and .cur get one — grey stages have no fill at all. */
.stg.done .bar::after,
.stg.cur .bar::after{
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 1.1s var(--ease-premium);
  will-change: transform;
}
.stg.done .bar::after{ background: var(--success); }
.stg.cur  .bar::after{ background: var(--action); }

/* GREEN GLOW (the "green light glows" effect from the 21st.dev component,
   rebuilt in vanilla CSS). The finished (green) stage bars emit a soft,
   slowly-breathing green halo so they read as "lit up / active". Uses a
   box-shadow pulse on the filled pseudo-element — GPU-cheap, isolated to
   ~2 tiny bars, so no scroll-jank risk. Only glows once the bar has
   filled in (parent revealed). */
@keyframes mbGreenGlow{
  0%,100%{ box-shadow: 0 0 6px 0 rgba(34,197,94,.35), 0 0 2px 0 rgba(34,197,94,.5); }
  50%    { box-shadow: 0 0 16px 2px rgba(34,197,94,.65), 0 0 6px 0 rgba(34,197,94,.7); }
}
/* ═══════════════ SINGLE CLEAN AUTO-PLAY SYSTEM ═══════════════
   ONE system, no scroll/observer/reduced-motion dependency. The bars
   fill from the left via a keyframe `animation` that plays automatically
   the instant the elements exist in the DOM — i.e. every time you open
   the #/updates page (app.js re-renders fresh .stg elements on route
   change, so the animation replays on entry). `forwards` holds the end
   state so they stop filled.

   IMPORTANT: this deliberately runs EVEN under prefers-reduced-motion.
   That's why nothing moved on Windows before — Windows commonly reports
   reduced-motion, and the old rules killed the animation. A slow bar
   fill + soft glow is not a vestibular trigger, and the site owner wants
   it visible on every device, so we let it play. Slowed to 1.8s with a
   gentle stagger for the calm feel requested. */
@-webkit-keyframes stgFill{ from{ -webkit-transform: scaleX(0); transform: scaleX(0); } to{ -webkit-transform: scaleX(1); transform: scaleX(1); } }
@keyframes stgFill{ from{ transform: scaleX(0); } to{ transform: scaleX(1); } }
@-webkit-keyframes stgLabel{ from{ opacity: 0; -webkit-transform: translateY(4px); transform: translateY(4px);} to{ opacity: 1; -webkit-transform: none; transform: none;} }
@keyframes stgLabel{ from{ opacity: 0; transform: translateY(4px);} to{ opacity: 1; transform: none;} }

/* FILL — slow (1.8s), calm easing, staggered left → right. `both` keeps
   the from-state (scaleX 0) during the delay so nothing flashes filled. */
.stg.done .bar::after,
.stg.cur  .bar::after{
  -webkit-animation: stgFill 1.8s cubic-bezier(.16,1,.3,1) both;
  animation:         stgFill 1.8s cubic-bezier(.16,1,.3,1) both;
}
.stages .stg:nth-child(1) .bar::after{ -webkit-animation-delay:.15s; animation-delay:.15s; }
.stages .stg:nth-child(2) .bar::after{ -webkit-animation-delay:.75s; animation-delay:.75s; }
.stages .stg:nth-child(3) .bar::after{ -webkit-animation-delay:1.35s; animation-delay:1.35s; }
.stages .stg:nth-child(4) .bar::after{ -webkit-animation-delay:1.95s; animation-delay:1.95s; }
.stages .stg:nth-child(5) .bar::after{ -webkit-animation-delay:2.55s; animation-delay:2.55s; }

/* GREEN GLOW — lives on the BAR itself (not the fill pseudo), so it's
   completely decoupled from the fill animation. Starts calmly after the
   green bars have filled, then breathes forever. box-shadow on the bar
   is not clipped by its own overflow:hidden, so the halo shows. */
.stg.done .bar{
  -webkit-animation: mbGreenGlow 2.8s ease-in-out infinite;
  animation:         mbGreenGlow 2.8s ease-in-out infinite;
}
.stages .stg.done:nth-child(1) .bar{ -webkit-animation-delay: 2.0s; animation-delay: 2.0s; }
.stages .stg.done:nth-child(2) .bar{ -webkit-animation-delay: 2.6s; animation-delay: 2.6s; }

/* LABELS — fade + tiny rise, staggered to follow their bar. */
.stg .nm{
  -webkit-animation: stgLabel .7s cubic-bezier(.16,1,.3,1) both;
  animation:         stgLabel .7s cubic-bezier(.16,1,.3,1) both;
}
.stages .stg:nth-child(1) .nm{ -webkit-animation-delay:.45s; animation-delay:.45s; }
.stages .stg:nth-child(2) .nm{ -webkit-animation-delay:1.05s; animation-delay:1.05s; }
.stages .stg:nth-child(3) .nm{ -webkit-animation-delay:1.65s; animation-delay:1.65s; }
.stages .stg:nth-child(4) .nm{ -webkit-animation-delay:2.25s; animation-delay:2.25s; }
.stages .stg:nth-child(5) .nm{ -webkit-animation-delay:2.85s; animation-delay:2.85s; }


/* ═════════════════════════════════════════════════════════════════════════
   §TL  ORIGIN-STORY TIMELINE — auto-play slide from the LEFT edge.
   Each item (The frustration / The idea / The promise) glides in from the
   left, slowly and calmly, one after another, and stops in place. Uses an
   auto-play keyframe `animation` (not a scroll/observer transition), so it
   plays every time you open the Founders page — including on Windows with
   reduced-motion (the site owner asked for it to be visible everywhere).
   Higher specificity (`.timeline .tl-item`) + !important so it beats the
   reduced-motion `.sr{animation:none}` rule that was freezing it.
   `both` holds the start state during the stagger delay so nothing flashes.
   ═════════════════════════════════════════════════════════════════════════ */
@-webkit-keyframes tlSlideIn{
  from{ opacity:0; -webkit-transform: translate3d(-32px,0,0); transform: translate3d(-32px,0,0); }
  to  { opacity:1; -webkit-transform: none; transform: none; }
}
@keyframes tlSlideIn{
  from{ opacity:0; transform: translate3d(-32px,0,0); }
  to  { opacity:1; transform: none; }
}
.timeline .tl-item{
  -webkit-animation: tlSlideIn 1.2s cubic-bezier(.16,1,.3,1) both !important;
  animation:         tlSlideIn 1.2s cubic-bezier(.16,1,.3,1) both !important;
}
.timeline .tl-item:nth-of-type(1){ -webkit-animation-delay:.15s; animation-delay:.15s; }
.timeline .tl-item:nth-of-type(2){ -webkit-animation-delay:.6s;  animation-delay:.6s; }
.timeline .tl-item:nth-of-type(3){ -webkit-animation-delay:1.05s; animation-delay:1.05s; }
.timeline .tl-item:nth-of-type(4){ -webkit-animation-delay:1.5s;  animation-delay:1.5s; }
.timeline .tl-item:nth-of-type(5){ -webkit-animation-delay:1.95s; animation-delay:1.95s; }

/* The connecting line grows down calmly as the items arrive; the marker
   dots keep their soft ring (calm shadow). */
.timeline::before{
  -webkit-animation: tlLineGrow 1.6s cubic-bezier(.16,1,.3,1) .1s both !important;
  animation:         tlLineGrow 1.6s cubic-bezier(.16,1,.3,1) .1s both !important;
  transform-origin: top center;
}
@-webkit-keyframes tlLineGrow{ from{ -webkit-transform: scaleY(0); transform: scaleY(0); } to{ -webkit-transform: scaleY(1); transform: scaleY(1); } }
@keyframes tlLineGrow{ from{ transform: scaleY(0); } to{ transform: scaleY(1); } }


/* ═════════════════════════════════════════════════════════════════════════
   §ING  INGREDIENTS CARDS — calm auto-play reveal (Product page,
   "Chosen with a purpose."). Same feel as the Development-Updates roadmap:
   an auto-play keyframe that runs on page entry, works on Windows even
   with reduced-motion, and stops in place.

   Targets ONLY the ingredient cards: `.grid > .card.card--pad-lg`. The
   contact-form card is also `.card--pad-lg` but is NOT inside a `.grid`,
   so it's not affected.

   Uses `backwards` (not `forwards`) fill: the from-state is held during
   the stagger delay (no flash), and after the animation the card reverts
   to its normal resting style — so the hover-lift still works. We also
   force opacity:1 as the base so the card can never end up hidden by the
   `.sr-edge{opacity:0}` reveal scaffolding app.js adds to every card.
   ═════════════════════════════════════════════════════════════════════════ */
@-webkit-keyframes ingIn{
  from{ opacity:0; -webkit-transform: translate3d(0,26px,0); transform: translate3d(0,26px,0); }
  to  { opacity:1; -webkit-transform: none; transform: none; }
}
@keyframes ingIn{
  from{ opacity:0; transform: translate3d(0,26px,0); }
  to  { opacity:1; transform: none; }
}
.grid > .card.card--pad-lg{
  opacity: 1 !important;   /* beat .sr-edge{opacity:0} so it can't stay hidden */
  -webkit-animation: ingIn 1.1s cubic-bezier(.16,1,.3,1) backwards !important;
  animation:         ingIn 1.1s cubic-bezier(.16,1,.3,1) backwards !important;
}
.grid > .card.card--pad-lg:nth-child(1){ -webkit-animation-delay:.15s; animation-delay:.15s; }
.grid > .card.card--pad-lg:nth-child(2){ -webkit-animation-delay:.55s; animation-delay:.55s; }
.grid > .card.card--pad-lg:nth-child(3){ -webkit-animation-delay:.95s; animation-delay:.95s; }
.grid > .card.card--pad-lg:nth-child(4){ -webkit-animation-delay:1.35s; animation-delay:1.35s; }
/* Preserve the hover-lift after the entrance finishes (desktop). */
@media (min-width:1024px){
  .grid > .card.card--pad-lg:hover{
    transform: translate3d(0,-4px,0);
    transition: transform .3s cubic-bezier(.22,.61,.36,1);
  }
}


/* ═════════════════════════════════════════════════════════════════════════
   TIMELINE DOTS — gentle colour pulse (Founders "How MindBites started")
   Each dot breathes with a soft ring in the brand action colour. Pure
   box-shadow-on-pseudo-element via opacity — no shadow value animation,
   so it stays compositor-cheap.
   ═════════════════════════════════════════════════════════════════════════ */
@-webkit-keyframes tlDotPulse{
  0%,100%{ opacity: .35; -webkit-transform: scale(1); transform: scale(1); }
  50%    { opacity: .85; -webkit-transform: scale(1.35); transform: scale(1.35); }
}
@keyframes tlDotPulse{
  0%,100%{ opacity: .35; transform: scale(1); }
  50%    { opacity: .85; transform: scale(1.35); }
}
/* Pulsing halo ring behind each timeline dot. */
.tl-item::after{
  content: "";
  position: absolute;
  left: -24px; top: 6px;
  width: 12px; height: 12px;
  border-radius: 50%;
  background: var(--action);
  opacity: 0;
  pointer-events: none;
  /* z-index:-1 removed — it pushed the halo BEHIND the section background
     in some stacking contexts (invisible), and in others created a new
     stacking context that clipped the dot itself. z-index:0 keeps it in
     normal flow, safely under the ::before dot which paints after it. */
  z-index: 0;
}
.tl-item.sr-visible::after,
.tl-item.in-view::after,
.tl-item[data-revealed="1"]::after{
  -webkit-animation: tlDotPulse 2.8s var(--ease-premium) infinite;
  animation: tlDotPulse 2.8s var(--ease-premium) infinite;
}
.tl-item:nth-of-type(1)::after{ -webkit-animation-delay:0s;   animation-delay:0s; }
.tl-item:nth-of-type(2)::after{ -webkit-animation-delay:.5s;  animation-delay:.5s; }
.tl-item:nth-of-type(3)::after{ -webkit-animation-delay:1s;   animation-delay:1s; }
.tl-item:nth-of-type(4)::after{ -webkit-animation-delay:1.5s; animation-delay:1.5s; }
.tl-item:nth-of-type(5)::after{ -webkit-animation-delay:2s;   animation-delay:2s; }
@media (prefers-reduced-motion: reduce){
  .tl-item::after{ animation: none !important; opacity: 0 !important; }
}


/* ═════════════════════════════════════════════════════════════════════════
   STATUS-GUIDE DOTS — same gentle pulse, in each status's own colour.
   (.status.new / .planning / .review / .complete pills on the
   Suggestions page's "Status guide" card.)
   ═════════════════════════════════════════════════════════════════════════ */
.status::before{
  -webkit-animation: tlDotPulse 2.6s var(--ease-premium) infinite;
  animation: tlDotPulse 2.6s var(--ease-premium) infinite;
  /* keep the dot's own colour — inherits from styles.css .status variants */
}
.status:nth-of-type(2)::before{ -webkit-animation-delay:.4s; animation-delay:.4s; }
.status:nth-of-type(3)::before{ -webkit-animation-delay:.8s; animation-delay:.8s; }
.status:nth-of-type(4)::before{ -webkit-animation-delay:1.2s; animation-delay:1.2s; }
@media (prefers-reduced-motion: reduce){
  .status::before{ animation: none !important; opacity: 1 !important; }
}

/* Reduced-motion — ONLY the small decorative pop bits are flattened here.
   The reveal scaffolds (.sr, .sr-edge, .clip-reveal-inner, .tl-item, etc.)
   are handled by §M-RM near the end of this file, which re-enables a gentle
   opacity fade instead of killing motion entirely — that's the Windows fix.
   The promo ticker is INTENTIONALLY left running (the site owner wants it
   moving on all devices); it's a slow, calm horizontal scroll. */
@media (prefers-reduced-motion: reduce){
  .mb-icon-pop{ transition: none !important; transform: none !important; opacity: 1 !important; }
  .tl-item::before, .timeline::before{ transition: none !important; transform: none !important; opacity: 1 !important; }
  .hero-img-wrap{ animation: none; }   /* continuous float — OK to disable */
  /* .mb-ticker-track is NOT disabled — see note above. */
}


/* ─────────────────────────────────────────────────────────────────────────────
   9. SCROLL SMOOTHNESS  (fixed-header layer, progress bar, parallax layer hints)
   ───────────────────────────────────────────────────────────────────────────── */

/* Fixed header — its own GPU compositor layer so it doesn't repaint against
   page content during scroll. */
.hd{
  -webkit-transform: translateZ(0);
  transform: translateZ(0);
  will-change: transform;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}

/* Scroll progress bar — GPU-driven scaleX via CSS variable (see site-patch.js §3).
   app.js still writes .style.width on every scroll, but this rule dominates and
   contains any layout thrash to just this one element. */
#scroll-progress-bar{
  width: 100% !important;
  transform-origin: left center;
  transform: scaleX(var(--sp, 0));
  will-change: transform;
  contain: layout paint style;
  transition: none !important;
}
#scroll-progress{ contain: layout paint style; }

/* Parallax targets — stable GPU compositor layers so fractional-pixel
   transforms from app.js don't shimmer at edges during scroll. */
.hero-img, .founder-arc, .chart-card, .chart-card canvas,
.doypack-visual, .mb-hero-img, .mb-panel-img, .imgbox, .loop-svg{
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
  -webkit-transform-style: preserve-3d;
  transform-style: preserve-3d;
}


/* ─────────────────────────────────────────────────────────────────────────────
  10. HERO LAYOUT & PRODUCT IMAGE  (single source of truth per breakpoint)
   ───────────────────────────────────────────────────────────────────────────── */

/* Desktop: text column wider so h1 fits on 2 lines; product image is a
   wide-rectangle 5:4 (not a tall pillar) at 480–560px. */
@media (min-width: 1024px){
  .hero{
    grid-template-columns: 1.35fr 1fr !important;
    align-items: center;
    gap: clamp(28px, 4vw, 64px);
  }
  .hero h1{
    font-size: clamp(40px, 4.6vw, 68px) !important;
    line-height: 1.05 !important;
  }
  /* PRODUCT PAGE hero (.text-first) has a LONG headline
     ("Energy + focus in a portable gummy format.") that was wrapping onto
     6 narrow lines like a phone layout. Give its text column much more
     width and cap the font smaller so it lands on ~2 lines. Only affects
     this one hero — other heroes keep their larger headline. */
  .hero.text-first{
    grid-template-columns: 1.65fr 1fr !important;
  }
  .hero.text-first h1{
    font-size: clamp(34px, 3.4vw, 50px) !important;
    line-height: 1.1 !important;
    max-width: 16ch;          /* ~2 lines for this specific headline */
  }
  /* HOME hero — PC layout.
     NOTE: an earlier `aspect-ratio:5/4` on a tall min-height forced the image
     column ~775px wide, which squeezed the headline onto 4 lines and shrank
     the signup card. Fixed by dropping aspect-ratio (height governs the pouch
     size) and giving the text column more width. */
  .hero-home{ gap: clamp(26px, 3.4vw, 52px); align-items: center; }
  .hero-home .hero-txt{ flex: 1.45; }        /* wider → headline fits 2 lines + roomier signup */
  .hero-home .hero-img{
    flex: 1;
    aspect-ratio: auto;
    min-height: 560px;
    max-height: 660px;
    width: 100%;
  }
  /* Headline stays on its two intended lines ("Energy that" / "keeps up.")
     — never let a single line wrap internally. */
  .hero-home #hero-hl{ font-size: clamp(38px, 4vw, 58px); }
  .hero-home #hero-hl .hl-line{ display: block; white-space: nowrap; }
  /* Nudge the pouch a little to the right inside its column. */
  .hero-home .mb-hero-img{ object-position: 72% center; }
  /* Signup card back to its original comfortable width. app.js replaces the
     [data-signup] placeholder with a `.signup` card, so target that. */
  .hero-home .signup,
  .hero-home [data-signup]{ max-width: 460px; width: 100%; }
  .hero .imgbox{
    aspect-ratio: 5/4;
    min-height: 520px;      /* bumped — product pouch bigger on desktop */
    max-height: 640px;
  }
  /* Make the injected pouch image fill more of its (now larger) box.
     Text column untouched — this only affects the image side. */
  .hero .imgbox .mb-panel-img,
  .hero .imgbox .mb-hero-img{
    width: 100% !important;
    height: 100% !important;
    object-fit: contain;
  }
  .mb-hero-img, .mb-panel-img{
    width: 100% !important;
    height: 100% !important;
    object-fit: contain;
  }

  /* SCIENCE mini-chart (home §05) — a touch bigger, grown LEFTWARD so the
     right edge (and therefore the gap to the text column) stays put and the
     page spacing is unchanged. Pure layout (width + negative margin), so it
     doesn't conflict with the transform rules on `.chart-card canvas`. */
  .hero > .chart-card[data-mini-chart]{
    width: 112%;
    margin-left: -12%;
    overflow: visible;
  }
}

/* Tablet + mobile: pouch fills nearly the whole fold — the first thing
   anyone sees. Matches the red-outlined area in the user's screenshot:
   roughly from just under the header down to the eyebrow label. */
@media (max-width: 1023px){
  .hero-home .hero-img{
    height: 78vh !important;
    max-height: 760px !important;
    min-height: 560px !important;
  }
  @supports (height: 1dvh){
    .hero-home .hero-img{ height: 78dvh !important; }
  }
  /* Image fills its container fully — was 95% in app.js's inline style. */
  .mb-hero-img{
    width: 100% !important;
    height: 100% !important;
    object-fit: contain;
  }
}
@media (max-width: 519px){
  .hero-home .hero-img{
    height: 72vh !important;
    max-height: 680px !important;
    min-height: 480px !important;
  }
  @supports (height: 1dvh){
    .hero-home .hero-img{ height: 72dvh !important; }
  }
}


/* ─────────────────────────────────────────────────────────────────────────────
  11. HERO GRID — MOBILE REORDER  (media below text, buttons below chart)
   ───────────────────────────────────────────────────────────────────────────── */

/* Hero layout on tablet + mobile: TITLE → PHOTO → TEXT → BUTTONS.
   Works by dissolving the text-column wrapper div via `display: contents`
   so its inner h1/lead/btn-row become direct flex items of `.hero`,
   alongside the media (founder-arc / imgbox / etc.). Then `order` places
   each element individually.
   Skips `.hero.text-first` (product page — kept as-is by request). */
@media (max-width: 1023px){
  .hero:not(.text-first){
    display: flex !important;
    flex-direction: column;
    align-items: stretch;
  }
  /* Text-column wrapper div → transparent; its children participate in
     the .hero flex layout as if they were direct siblings of the media. */
  .hero:not(.text-first) > div:not(.chart-card):not(.imgbox):not(.doypack-visual):not(.founder-arc){
    display: contents;
  }

  /* 1) Eyebrow (small label above the title) */
  .hero:not(.text-first) .eyebrow{ order: 1; }
  /* 2) Title */
  .hero:not(.text-first) h1,
  .hero:not(.text-first) h2{ order: 2; }
  /* 3) PHOTO-STYLE media (portraits, product pouch, doypack) — sits BETWEEN
     title and body copy, since these are the "hero image" for the section. */
  .hero:not(.text-first) > .founder-arc,
  .hero:not(.text-first) > .imgbox,
  .hero:not(.text-first) > .doypack-visual{ order: 3; margin-block: 20px; }
  /* 4) Body copy — leads and paragraphs */
  .hero:not(.text-first) .lead,
  .hero:not(.text-first) > p:not(.crumbs),
  .hero:not(.text-first) > * > p:not(.crumbs):not(.muted):not(.fine){ order: 4; }
  .hero:not(.text-first) .muted,
  .hero:not(.text-first) .fine{ order: 4; }
  /* 5) SIDE CARD (e.g. Suggestions "Status guide") — sits after the lead,
     before the button. Gives: title → lead → status guide → button. */
  .hero:not(.text-first) > .card{ order: 5; margin-top: 6px; }
  /* 5b) CHART media (Science mini-chart) — position handled by
     site-patch.js `syncScienceChart()` which physically inserts the
     chart just before the buttons. No CSS `order` here so the two
     systems can't conflict. Just give it breathing room. */
  .hero:not(.text-first) .chart-card{ margin-block: 20px; }
  /* 6) CTA buttons at the very bottom of the hero. */
  .hero:not(.text-first) .btn-row{ order: 6; }
}

/* FOUNDERS PAGE — portrait arc must always show on phones.
   app.js reveals `.founder-arc` with its edge observer (starts it hidden:
   opacity 0 + translateX). On phones that observer is unreliable, so the
   four portraits could stay invisible. Force the arc — and each portrait —
   fully visible on mobile/tablet, right under the big title. */
@media (max-width: 1023px){
  .founder-arc,
  .founder-arc.sr-edge,
  .founder-arc.sr-edge:not(.in-view),
  .founder-arc.sr,
  .founder-arc.sr:not(.sr-visible){
    opacity: 1 !important;
    transform: none !important;
  }
  .founder-arc .portrait{
    opacity: 1 !important;
    transform: none !important;
  }
  /* give the raised centre portrait its lift back (transform was cleared) */
  .founder-arc .portrait.mid{ transform: translateY(-10px) !important; }
}

/* ═════════════════════════════════════════════════════════════════════════
   LOOP DIAGRAM (Listen → Evaluate → Build → Explain) — always visible on
   mobile. app.js reveals the circles + path via an observer + JS timer;
   on phones that reveal is unreliable, leaving them invisible (circles at
   opacity 0, path with a full stroke-dashoffset). Force them fully drawn
   on mobile so the diagram always shows. Also make the SVG scale to the
   viewport so nothing is cut off.
   ═════════════════════════════════════════════════════════════════════════ */
@media (max-width: 767px){
  .loop-svg{
    width: 100% !important;
    max-width: 100% !important;
    height: auto !important;
  }
  .loop-node{
    opacity: 1 !important;
    transform: none !important;
  }
  .loop-svg path,
  .loop-path,
  #loop-line{
    stroke-dasharray: none !important;
    stroke-dashoffset: 0 !important;
    opacity: 1 !important;
  }
}

/* SIMULATOR (Caffeine Explorer) — .sim-body has controls on the left and
   chart on the right in desktop grid. On mobile the user wants the chart
   ABOVE the controls (visual first, tweak controls below). */
@media (max-width: 1023px){
  .sim-body{
    display: flex !important;
    flex-direction: column;
  }
  .sim-body > .sim-chartwrap{ order: 1; }        /* chart + legend + metrics */
  .sim-body > .sim-controls{ order: 2; margin-top: 16px; }
}

/* [REMOVED] old `.below-chart` ordering — superseded by site-patch.js's
   physical DOM move (syncScienceChart). Keeping it caused two competing
   reorder systems to fight, which is why the graph/buttons order looked
   wrong. Now there's exactly one system. */

/* KILL SCROLL PARALLAX EVERYWHERE — continuous scroll-driven transforms
   are the #1 cause of the "text/image peeks and glitches while scrolling"
   bug on Windows Chrome (the compositor can't keep the layer in sync with
   the scroll every frame). These five elements have NO hover transform,
   so neutralising their transform is completely safe. The product pouch
   images (.mb-hero-img / .mb-panel-img) are NOT parallax targets and keep
   their hover-zoom — so they're excluded from the desktop rule. */
.hero-img, .founder-arc, .loop-svg,
.chart-card canvas, .doypack-visual{
  transform: none !important;
}
/* On mobile also freeze the product images (no hover on touch anyway). */
@media (max-width: 767px){
  .mb-hero-img, .mb-panel-img{ transform: none !important; }
}


/* ─────────────────────────────────────────────────────────────────────────────
  12. MOBILE SAFETY OVERRIDES  (must-never-be-invisible + button wrap)
   ───────────────────────────────────────────────────────────────────────────── */
@media (max-width: 767px){

  /* Never let a heading get stuck below its own clip-reveal box. app.js's
     IntersectionObserver sometimes races with DOM inject timing on mobile
     — this ensures the h2/h3 is always readable, animation still plays
     if the observer fires. */
  .clip-reveal, .clip-reveal-inner{
    overflow: visible !important;
    transform: none !important;
    opacity: 1 !important;
  }

  /* Idea/suggestion card h3 — belt-and-suspenders after the clip-reveal
     fix above; forces the title visible regardless of race conditions. */
  .idea h3{
    font-size: clamp(15px, 3.8vw, 17px);
    font-weight: 700;
    color: var(--ink);
    line-height: 1.3;
    margin: 0 0 6px;
    display: block !important;
    visibility: visible !important;
    opacity: 1 !important;
  }
  .idea h3 .clip-reveal,
  .idea h3 .clip-reveal-inner{
    display: inline !important;
    padding: 0 !important;
    margin: 0 !important;
  }

  /* Buttons — allow long labels to wrap, keep touch-target ≥44px. */
  .btn{
    max-width: 100%;
    box-sizing: border-box;
    white-space: normal;
    line-height: 1.2;
    padding-left: 18px;
    padding-right: 18px;
    min-height: 46px;
  }
  .btn-row{ width: 100%; max-width: 100%; flex-wrap: wrap; }
}


/* ─────────────────────────────────────────────────────────────────────────────
  13. CARDS, GRIDS, IDEAS, SIMULATOR
   ───────────────────────────────────────────────────────────────────────────── */

/* Card padding — enough internal space so long copy never touches the
   rounded corner. */
.card{ padding: clamp(18px, 2.8vw, 28px); }
.card > *:last-child{ margin-bottom: 0; }

/* Idea rows — center the vote badge vertically beside its content. */
.idea{ align-items: center !important; }
@media (max-width: 519px){
  .idea{ flex-wrap: wrap; padding: 16px !important; }
  .idea .vres{
    align-self: center;
    flex-direction: row;
    justify-content: center;
    min-width: 100%;
    padding-bottom: 6px;
    border-bottom: 1px solid var(--mist);
  }
}
.idea .tag, .idea .status{
  vertical-align: middle;
  display: inline-flex;
  align-items: center;
}

/* Simulator (Caffeine Explorer) restyle helpers */
.sm{ position: relative; overflow: hidden; }
.sm .ico{ color: var(--chart); margin-bottom: 6px; display: inline-flex; }
.chart-card canvas{ transition: opacity .3s ease; }
.sim-controls .toggle-row button{ min-width: 44px; }
.sim-metrics{ grid-template-columns: repeat(2, 1fr) !important; }   /* 5 cards → 2×3 grid */


/* ─────────────────────────────────────────────────────────────────────────────
  14. "THE NEED" — 3-PHOTO SECTION  (wired by site-patch.js §4)

  Desktop / tablet: three rounded-square photos in a row.
  Mobile: stacked vertically (one under the next, larger) so overlaid
  text on each photo stays readable.
   ───────────────────────────────────────────────────────────────────────────── */
.need-strip{
  display: flex;
  gap: clamp(14px, 2vw, 24px);
  justify-content: center;
  align-items: stretch;
  width: 100%;
  max-width: 100%;
  margin: 36px 0 0;
}
.need-strip .need-shot{
  flex: 1 1 0;
  min-width: 0;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  object-position: center;
  display: block;
  border-radius: 20px;
  box-shadow: 0 4px 6px -1px rgba(29,45,80,.02),
              0 25px 55px -12px rgba(29,45,80,.08);
}
body.dark .need-strip .need-shot{
  box-shadow: 0 30px 60px rgba(0,0,0,.4);
}

/* Mobile + narrow tablet — vertical stack, bigger images. */
@media (max-width: 1023px){
  .need-strip{
    flex-direction: column;
    gap: 16px;
    margin-top: 26px;
  }
  .need-strip .need-shot{
    flex: 0 0 auto;
    width: 100%;
    max-width: 640px;
    aspect-ratio: 1 / 1;
    margin: 0 auto;
    border-radius: 18px;
  }
}
@media (max-width: 519px){
  .need-strip{ gap: 14px; }
  .need-strip .need-shot{ border-radius: 16px; }
}


/* ─────────────────────────────────────────────────────────────────────────────
  15. FAQ SECTION  (left-align override — was oddly centered)
   ───────────────────────────────────────────────────────────────────────────── */
/* NOTE: `:has()` removed — Chrome shipped it only in v105, and any
   browser that doesn't understand it drops the whole rule. Handled in
   site-patch.js §10 instead (adds a `data-faq-head` attribute), which
   works everywhere. */
[data-faq-head]{ text-align: left !important; }


/* ─────────────────────────────────────────────────────────────────────────────
  16. SPACING — 8-POINT VERTICAL RHYTHM  (mobile)
   ───────────────────────────────────────────────────────────────────────────── */
@media (max-width: 767px){
  /* Eyebrow → heading */
  .eyebrow{ margin-bottom: clamp(18px, 4vw, 24px); }
  .eyebrow + h1,
  .eyebrow + h2,
  .eyebrow + h3{
    margin-top: 0 !important;
    padding-top: 6px;
  }
  /* Heading → paragraph */
  h1 + p, h2 + p, h3 + p,
  h1 + .lead, h2 + .lead, h3 + .lead{ margin-top: clamp(8px, 2vw, 16px) !important; }
  /* Paragraph → paragraph */
  p + p, .lead + p, p + .lead{ margin-top: clamp(12px, 2.5vw, 16px) !important; }
  /* Text → button row */
  .btn-row{ margin-top: clamp(16px, 4vw, 24px) !important; }
  p + .btn-row, .lead + .btn-row, .muted + .btn-row,
  h1 + .btn-row, h2 + .btn-row, h3 + .btn-row{
    margin-top: clamp(24px, 5vw, 32px) !important;
  }
  /* Block → block */
  .grid, .facts, .stages{ margin-top: clamp(24px, 5vw, 40px); }
  /* Section vertical padding — cards inside have real breathing room from edges. */
  .section{ padding-block: clamp(40px, 8vw, 72px); }
  .section.section--tight{ padding-block: clamp(32px, 6vw, 56px); }
}

/* Universal (all viewports) — proactive card-follows-by-X spacing. */
.grid + .btn-row,
.facts + .btn-row,
.fact-chips + .btn-row,
.trust-pills + .btn-row,
.stages + .btn-row{ margin-top: clamp(28px, 5vw, 48px) !important; }

.grid + .signup, .grid + p, .grid + .lead,
.facts + p, .facts + .lead{ margin-top: clamp(20px, 3vw, 32px); }

.card + .btn, .card + button.btn,
.note + .btn, .note + button.btn,
p + .btn, .lead + .btn, .muted + .btn{ margin-top: clamp(20px, 3vw, 28px); }

/* .btn-row gap between adjacent buttons — universal. */
.btn-row{ gap: clamp(10px, 1.6vw, 16px); }
.btn-row .btn{ margin: 0; }
@media (max-width: 519px){ .btn-row{ gap: 12px; } }

/* Chip/pill/badge row gaps — universal. */
.trust-pills{ gap: clamp(8px, 1.2vw, 12px); }
.fact-chips { gap: clamp(8px, 1.4vw, 14px); }
.sim-legend { gap: clamp(10px, 1.6vw, 16px); }
.sim-controls .toggle-row{ gap: clamp(8px, 1.2vw, 12px); }
.stages     { gap: clamp(6px, 1vw, 10px); }
.socials    { gap: clamp(8px, 1.2vw, 12px); }
.ft-bottom .links{ gap: clamp(14px, 2vw, 20px); }


/* ─────────────────────────────────────────────────────────────────────────────
  17. GPU-ONLY ANIMATION HYGIENE  (Windows-Chrome-vs-macOS-Safari fix)

  Root cause of the reported "smooth on macOS/iOS Safari, glitchy on
  Windows Chrome" gap:  styles.css animates `box-shadow` and layout
  properties (left, width, background-position) on many hover-triggered
  elements. Only `transform` and `opacity` are compositor-friendly on
  every browser. Apple Silicon's tile renderer absorbs the extra paint
  cost silently; integrated Intel/AMD GPUs on Windows drop frames.

  Rules applied here override styles.css transitions/keyframes without
  changing the visible effect: same lift on hover, same shimmer, same
  timing — just implemented through transform/opacity only.
   ───────────────────────────────────────────────────────────────────────────── */

/* --- 17.1  KARTY & TILE-Y — usuwamy box-shadow z transition ---
   Static shadows in styles.css still render fine (paint once at reveal).
   We only strip the *transition* on box-shadow so hover doesn't repaint
   the shadow every frame. Lift on hover stays (transform-based). */
.card,
.fact,
.idea,
.pill,
.step-led,
.glass-panel{
  transition: transform .3s cubic-bezier(.22, .61, .36, 1) !important;
}
/* .card and .fact both had a hover-lift built in via `transform: translateY(-3/-4px)`
   — keep that behavior visible. .sr-edge carve-outs at §8 already restore lift
   for revealed cards on desktop. Nothing else to change here. */

/* --- 17.2  STEP-LED SHIMMER — replace `transition: left` with translateX ---
   The sweeping highlight bar on .step-led hover was moving via `left:-120% → 150%`,
   which forces layout on every frame. Same visual effect via transform is free. */
.step-led::after{
  left: 0 !important;
  transform: translateX(-220%);
  transition: transform .6s cubic-bezier(.4, 0, .4, 1) !important;
  will-change: transform;
}
.step-led:hover::after{
  transform: translateX(250%);
}

/* --- 17.3  PRIMARY BUTTON — kill the background-position hover animation ---
   `.btn--primary` uses a 200%-wide gradient and slides it on hover via
   background-position. That's a texture repositioning — expensive on
   integrated GPUs. The button still gets its lift+glow via transform;
   the gradient shift itself was a subtle detail no one will miss. */
.btn--primary{
  background-size: 100% 100% !important;
  background-position: 0 0 !important;
}
.btn--primary:hover{
  background-position: 0 0 !important;    /* no re-position on hover */
}

/* --- 17.4  LOGO SWEEP KEYFRAME — replace `left` with translateX ---
   The mark's sweep animation was `left: -90% → 155%`. Layout property.
   Redefine the animation using transform-only. Same visual, GPU-cheap. */
@-webkit-keyframes logoSweep{
  0%{ -webkit-transform: translateX(-100%); transform: translateX(-100%); }
  55%,100%{ -webkit-transform: translateX(280%); transform: translateX(280%); }
}
@keyframes logoSweep{
  0%{ transform: translateX(-100%); }
  55%,100%{ transform: translateX(280%); }
}
.logo-mask::after{
  left: 0 !important;                     /* neutralize the old `left` starting point */
  will-change: transform;
}

/* --- 17.5  DISCOUNT-POP KEYFRAME — replace box-shadow flash with opacity ring ---
   Original keyframe animates box-shadow directly, which forces a repaint
   on every frame. Repaint the same visual flash by fading a pseudo-element
   with a static box-shadow instead — opacity is compositor-only. */
@-webkit-keyframes discountPop{
  0%,100%{ opacity: 0; -webkit-transform: scale(1); transform: scale(1); }
  40%{ opacity: 1; -webkit-transform: scale(1.02); transform: scale(1.02); }
}
@keyframes discountPop{
  0%,100%{ opacity: 0; transform: scale(1); }
  40%{ opacity: 1; transform: scale(1.02); }
}

/* --- 17.6  PROGRESS BARS (survey `.progress > i`) — width → scaleX ---
   `transition: width` animates a layout property. Same visual via
   `transform: scaleX()` is compositor-cheap. Requires transform-origin
   left so the bar grows from the left edge like the original width did. */
.progress{ overflow: hidden; }
.progress > i{
  width: 100% !important;
  transform-origin: left center;
  transform: scaleX(var(--progress, 0));
  transition: transform .35s cubic-bezier(.22, .61, .36, 1) !important;
  will-change: transform;
}
/* app.js writes `.style.width = pct + '%'` to `.progress > i`. We can't stop
   that write, but the CSS above dominates. To make the visual actually
   reflect progress, we'd need JS to write `--progress` instead — see
   site-patch.js §8 for the bridge that mirrors width writes to --progress.

   NOTE: for the survey progress bar this bridge is optional — the visual
   is still animated smoothly via transform, just at a fixed scaleX(0) if
   --progress is never set. If you want the survey progress to animate,
   add the bridge in site-patch.js next round. */

/* --- 17.7  .opt (survey options) — remove box-shadow from transition ---
   Kept transform + background-color (cheap paint, not gradient). */
.opt{
  transition: background-color .2s ease,
              border-color   .2s ease,
              transform      .2s cubic-bezier(.22, .61, .36, 1) !important;
}

/* --- 17.8  CONTAIN on card grids — isolate hover-repaints ---
   `.grid.two/.three/.four` on desktop wrap multiple cards. Hovering one
   card can trigger a repaint of the entire section — a real cost on
   Chrome/Windows. `contain: layout paint` scopes any hover-repaint to
   just that card. NOT applied to .founder-arc / .profile / hero (those
   have intentional overflow-visible lift, containment would clip them). */
@media (min-width: 1024px){
  .card, .fact, .idea, .pill{
    contain: layout paint;
  }
}

/* --- 17.9  Reduced-motion also stops the two new transform animations ---
   Extends the §8 opt-out to logoSweep + discountPop. */
@media (prefers-reduced-motion: reduce){
  .logo-mask::after,
  .step-led::after{
    animation: none !important;
    transition: none !important;
    transform: none !important;
  }
}

/* --- 17.9b  [REMOVED] fade-only rewrite that was too aggressive.

   Previous version set `.clip-reveal:not(.in-view) .clip-reveal-inner
   { opacity: 0 !important; transform: none !important; }` — combined with
   §18 content-visibility, sections deep on the page whose clipObserver
   didn't fire in time left every h2 title invisible ("Ideas that build",
   "The Issues We Kept Noticing", etc.). Reverted entirely.

   Now: the original transform-based reveal from styles.css / app.js is
   preserved (translateY / translateX / clip-reveal-inner rise up). Motion
   is CALM (already tuned in §8 to smaller distances + easeOutExpo). The
   §17.10 lock below still freezes each element after its first reveal so
   nothing re-animates on scroll-back.
   -------------------------------------------------------------------- */


/* --- 17.10  [REMOVED] `[data-revealed="1"]` LOCK was the reason nothing
   animated on Windows Chrome. It set `transition: none !important` which
   killed the animation the instant site-patch.js stamped the attribute
   (immediately after the .visible class was added). The reveal never
   got a chance to play. Deleted entirely — the standard CSS-transition
   pattern from styles.css now runs unopposed. */

/* ═════════════════════════════════════════════════════════════════════════
   §M  MASTER REVEAL SYSTEM  (the ONE rule replacing sections 17.10 + 19)

   This is the industry-standard pattern used by Apple, Google, Deloitte,
   LinkedIn, Sopra Steria — the simplest thing that could possibly work:

     1. Default state:  opacity 0, subtle translateY(20px)
     2. IntersectionObserver adds a class the moment element scrolls in
     3. That class flips to opacity 1, translateY 0
     4. Transition property does the interpolation on GPU

   No `!important` transition kills, no data-attribute pinning, no
   `.js-anim` gate, no keyframe-based failsafe. Just a plain transition
   that plays exactly once when the observer fires.

   The observer + class toggling is already implemented in app.js
   (SR_IO, edgeObserver, clipObserver) and site-patch.js §8 fallback.
   All this rule does is make sure the transition itself is:
     - GPU-friendly (only opacity + transform)
     - Slow enough to feel calm on Windows (0.9s)
     - With a natural easing curve (easeOutExpo — same as loop-path draw)
     - Sub-pixel per-frame delta (20px over 0.9s ≈ 1px per 60fps frame)

   Nothing is `!important` overridden — styles.css's original selectors
   still work exactly as intended; this just re-tunes the duration and
   distance to what everyone finds smooth.
   ═════════════════════════════════════════════════════════════════════════ */

/* All eight reveal-scaffold selectors get the same calm transition. */
.sr, .sr-left, .sr-right,
.sr-edge,
.reveal-left, .reveal-right, .reveal-up,
.hl-word,
.clip-reveal-inner,
.tl-item{
  transition-property: opacity, transform;
  transition-duration: .9s;
  transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}

/* Subpage TITLES (the clip-reveal heading rise) — user reported them
   "too fast and lagging sometimes". Give them a longer, calmer duration
   than body elements so the big headline glides rather than snaps. The
   longer duration also means smaller per-frame movement = smoother on
   Windows integrated GPUs. */
.clip-reveal-inner{
  transition-duration: 1.15s !important;
  transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1) !important;
}

/* §T  TITLE PULSATE FIX (pairs with site-patch.js §1d).
   Once a title has been revealed once, site-patch stamps its
   `.clip-reveal` with data-seen="1". This pins the inner span at its
   final position so app.js's observer toggling `.in-view` off can no
   longer make it drop and re-animate. Crucially we DON'T touch
   `transition` here — the first reveal still plays normally; this only
   prevents the re-trigger feedback loop that caused the pulsing. */
.clip-reveal[data-seen="1"] .clip-reveal-inner{
  transform: translate3d(0, 0, 0) !important;
  opacity: 1 !important;
}

/* FOUNDERS "THE TEAM" — all three cards equal height.
   The .profile-grid is already a grid; `align-items: stretch` makes every
   card fill the tallest row height instead of hugging its own content, so
   the three cards line up perfectly even with different amounts of text.
   The featured card's -10px lift is preserved. */
.profile-grid{ align-items: stretch !important; }
.profile-grid > .profile{
  height: 100%;
  display: flex;
  flex-direction: column;
}
/* Push the quote to the bottom so shorter cards don't leave the quote
   floating mid-card — keeps the visual baseline aligned across all four. */
.profile-grid > .profile > p:last-child{ margin-top: auto; }

/* FOUR co-founders — app.js renders a 3-column grid; with the 4th member
   (Katarzyna) injected by site-patch.js §11 we need a balanced layout:
   one row of 4 on desktop, 2×2 on tablet, single column on phone. */
@media (min-width: 1024px){
  .profile-grid{ grid-template-columns: repeat(4, 1fr) !important; gap: 18px !important; }
  .profile-grid > .profile{ padding: 22px 18px !important; }
  .profile-grid > .profile .pf{ width: 92px; height: 92px; }
}
@media (min-width: 768px) and (max-width: 1023px){
  .profile-grid{ grid-template-columns: repeat(2, 1fr) !important; }
}

/* USE-MOMENTS (and any .grid.four card group) — slide in from the LEFT
   edge to their resting position, with a gentle left-to-right stagger.
   Forces a from-left start regardless of the alternating direction
   app.js assigns, so the whole row wipes in from the left as requested. */
.grid.four > .card.sr-edge:not(.in-view){
  transform: translate3d(-42px, 0, 0) !important;
}
.grid.four > .card.sr-edge.in-view{
  transform: translate3d(0, 0, 0) !important;
}
/* Stagger — each card starts a beat after the previous (left → right). */
.grid.four > .card:nth-child(1){ transition-delay: 0ms; }
.grid.four > .card:nth-child(2){ transition-delay: 120ms; }
.grid.four > .card:nth-child(3){ transition-delay: 240ms; }
.grid.four > .card:nth-child(4){ transition-delay: 360ms; }

/* Preserve `.profile.feat`'s permanent -10px lift on desktop. */
@media (min-width: 1024px){
  .profile.feat.sr-edge.in-view{
    transform: translate3d(0, -10px, 0) scale3d(1, 1, 1);
  }
  /* Card / fact hover-lift still works because styles.css owns hover
     transitions and we haven't overridden them here. */
}


/* ═════════════════════════════════════════════════════════════════════════
   §M-RM  THE ACTUAL WINDOWS FIX  ← this is why nothing moved on Windows.

   ROOT CAUSE (confirmed in styles.css lines 948 & 958):
     @media (prefers-reduced-motion:reduce){
       .sr,.sr-left,.sr-right{opacity:1;transform:none;transition:none}
       .reveal-left,.reveal-right,.reveal-up{opacity:1;transform:none;transition:none}
     }

   Windows very commonly ships with system animations DISABLED
   (Settings → Accessibility → Visual effects → "Animation effects" OFF,
   or the performance tweak "Animate controls and elements inside
   windows"). When that's off, the browser reports
   `prefers-reduced-motion: reduce`, which triggers the rules above and
   kills every scroll reveal — content appears instantly, no motion.
   macOS almost never has "Reduce motion" on, so it always animated.
   Same code, opposite result. That's the entire mystery, solved.

   FIX — the Apple / Google standard: under reduced-motion we still play
   a GENTLE OPACITY CROSSFADE (no sliding, no scaling, no movement — so
   it stays vestibular-safe and honours the spirit of reduced-motion),
   instead of killing motion entirely. Net result: the site fades in
   softly on Windows even with system animations off, while genuine
   reduced-motion users get calm fades with zero movement.

   Loads AFTER styles.css so it wins the cascade; scoped tightly to the
   reveal scaffolds so nothing else is touched.
   ═════════════════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce){

  /* Re-enable a movement-free opacity fade on every reveal scaffold.
     NOTE: `.tl-item` is deliberately EXCLUDED here — the Origin-story
     timeline uses its own auto-play slide-in (see §TL below) which must
     run even under reduced-motion, per the site owner's request. */
  .sr, .sr-left, .sr-right,
  .sr-edge,
  .reveal-left, .reveal-right, .reveal-up,
  .hl-word,
  .clip-reveal-inner{
    transition: opacity .8s ease !important;
    transform: none !important;          /* no slide/scale — reduced-motion respected */
    animation: none !important;
  }

  /* Hidden (pre-reveal) state → fully transparent. */
  .sr:not(.sr-visible),
  .sr-left:not(.sr-visible),
  .sr-right:not(.sr-visible),
  .sr-edge:not(.in-view),
  .reveal-left:not(.reveal-active),
  .reveal-right:not(.reveal-active),
  .reveal-up:not(.reveal-active),
  .hl-word:not(.vis),
  .clip-reveal:not(.in-view) .clip-reveal-inner{
    opacity: 0 !important;
  }

  /* Revealed state → fully opaque. */
  .sr.sr-visible,
  .sr-left.sr-visible,
  .sr-right.sr-visible,
  .sr-edge.in-view,
  .reveal-left.reveal-active,
  .reveal-right.reveal-active,
  .reveal-up.reveal-active,
  .hl-word.vis,
  .clip-reveal.in-view .clip-reveal-inner{
    opacity: 1 !important;
  }

  /* Ambient loops (ticker, pulse dots, hero float) stay OFF under
     reduced-motion — those are continuous movement and genuinely should
     be disabled. Only the one-shot reveal fade is re-enabled above. */
}


/* ─────────────────────────────────────────────────────────────────────────────
  18. [REMOVED] content-visibility: auto on sections.

  It was a performance hack — sections beyond the first skipped
  layout/paint/render until near the viewport. But it interfered with
  app.js's clipObserver (which needs proper layout of every .clip-reveal
  to fire IntersectionObserver reliably), leaving h2 titles invisible on
  sections deep on the page. Removed — the ~3-5% perf gain isn't worth
  the reveal-reliability tradeoff, and mobile-polish already has enough
  other perf optimisations elsewhere.
   ───────────────────────────────────────────────────────────────────────────── */


/* ═════════════════════════════════════════════════════════════════════════
   §19  "SUBMIT AN IDEA" — hide the "Your category" field until needed.

   BUG: app.js renders the custom-category field as
        <div class="field" data-custom hidden> … </div>
   and toggles its `hidden` attribute when the Category select changes.
   BUT styles.css line 602 declares `.field{ display:flex }`, which has
   higher specificity than the browser's built-in `[hidden]{display:none}`
   rule — so the field stayed visible even when hidden. This one line makes
   the `hidden` attribute win again, so "Your category" only appears after
   the user picks "Other / type my own".
   ───────────────────────────────────────────────────────────────────────── */
.field[hidden],
[data-custom][hidden]{ display: none !important; }


/* ═════════════════════════════════════════════════════════════════════════
   §20  CURRENT-STAGE TEXT SHIMMER  (Development Updates roadmap)

   The active roadmap stage label (`.stg.cur .nm` — e.g. "Testing") gets a
   soft left-to-right light sweep, recreating the framer-motion "TextShimmer"
   effect with pure CSS (animated gradient clipped to the text). It is
   GENERIC: whichever stage currently has `.cur` shimmers, so when you move
   the status forward in app.js later, the new current stage animates
   automatically. Completed stages stay green (styles.css .stg.done .bar).

   Technique: two stacked background layers clipped to the text —
     • a solid base colour (the resting text colour), plus
     • a moving highlight gradient (250% wide) swept across via
       background-position, exactly like the framer component.
   ───────────────────────────────────────────────────────────────────────── */
@keyframes mbTextShimmer{
  0%   { background-position: 100% center, center; }
  100% { background-position: 0% center, center; }
}
.stg.cur .nm{
  --mb-base: #8b93a1;           /* resting colour of the shimmering text */
  --mb-hi:   var(--action);     /* highlight sweep — on-brand blue */
  --mb-spread: 18px;            /* width of the bright band */
  color: transparent !important;
  -webkit-text-fill-color: transparent;
  background-image:
    linear-gradient(90deg,
      transparent calc(50% - var(--mb-spread)),
      var(--mb-hi),
      transparent calc(50% + var(--mb-spread))),
    linear-gradient(var(--mb-base), var(--mb-base));
  background-repeat: no-repeat;
  background-size: 250% 100%, 100% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  /* FIX: previously this single `animation` overrode the shared `stgLabel`
     fade (§ roadmap), so "Testing" was already visible + shimmering while
     every other label faded in — out of sync with its blue bar. Now it runs
     TWO animations: first the same fade the other labels use (held hidden
     until 1.35s — the moment its blue bar fills — via `both`), then the
     shimmer starts once the fade has finished. So it appears smoothly like
     the rest, in step with the bar underneath. */
  animation:
    stgLabel .7s cubic-bezier(.16, 1, .3, 1) 1.35s both,
    mbTextShimmer 2.4s linear 2.4s infinite;
}
body.dark .stg.cur .nm{
  --mb-base: #8b93a1;
  --mb-hi: #cdd8ff;             /* lighter sweep for contrast on dark bg */
}
/* Deliberately NOT gated behind prefers-reduced-motion — Windows commonly
   reports reduced-motion (system animations off), and the user wants this
   sweep to run there too. A CSS keyframe animation still plays under
   reduced-motion; the base gradient keeps the text fully legible regardless. */


/* ═════════════════════════════════════════════════════════════════════════
   §21  SUGGESTIONS LIST — smooth staggered reveal (PC only).

   Each idea card carries `.sr`; app.js's IntersectionObserver adds
   `.sr-visible` when it enters the viewport, so the cards already reveal as
   you scroll. Here we make that reveal cinematic on desktop: a soft rise +
   fade with a gentle left-to-right / top-to-bottom cascade for cards that
   enter together. Plays once per load (fresh DOM on refresh restarts it).
   Phones are intentionally excluded — the request was PC-only. Same easing
   token used across the site so it feels consistent everywhere. */
@media (min-width: 1024px){
  #main [data-list] .idea.sr{
    transition: opacity .7s cubic-bezier(.16, 1, .3, 1),
                transform .7s cubic-bezier(.16, 1, .3, 1);
  }
  #main [data-list] .idea.sr:not(.sr-visible){
    opacity: 0 !important;
    transform: translate3d(0, 30px, 0) !important;
  }
  #main [data-list] .idea.sr.sr-visible{
    opacity: 1 !important;
    transform: none !important;
  }
  /* Cascade — cards that scroll in as a group light up one after another. */
  #main [data-list] .idea:nth-child(6n + 1){ transition-delay: 0ms; }
  #main [data-list] .idea:nth-child(6n + 2){ transition-delay: 80ms; }
  #main [data-list] .idea:nth-child(6n + 3){ transition-delay: 160ms; }
  #main [data-list] .idea:nth-child(6n + 4){ transition-delay: 240ms; }
  #main [data-list] .idea:nth-child(6n + 5){ transition-delay: 320ms; }
  #main [data-list] .idea:nth-child(6n){     transition-delay: 400ms; }
}


/* ═════════════════════════════════════════════════════════════════════════
   §22  STATUS GUIDE — redesigned rows (no white pills).

   site-patch.js §13 rebuilds the "Status guide" panel into rows of:
     [ tinted icon tile + coloured dot ] [ coloured label ] | [ muted desc ]
   Colours come from the site's theme tokens (--action / --warn / --success),
   so they re-tint automatically when the site's colour theme changes. Hover
   gives each row a subtle lift + coloured border — interactive, on every
   browser and OS. */
.mb-sg{ display: flex; flex-direction: column; gap: 10px; margin-top: 12px; }
.mb-sg-row{
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 14px;
  border-radius: 14px;
  border: 1px solid var(--mist);
  background: var(--card);
  transition: border-color .25s ease, transform .25s ease, box-shadow .25s ease;
}
.mb-sg-row:hover{
  transform: translateY(-2px);
  border-color: color-mix(in srgb, var(--c) 55%, var(--mist));
  box-shadow: 0 8px 22px rgba(0, 0, 0, .10);
}
.mb-sg-ico{
  flex: none;
  width: 40px; height: 40px;
  border-radius: 11px;
  display: grid; place-items: center;
  background: color-mix(in srgb, var(--c) 16%, transparent);
  border: 1px solid color-mix(in srgb, var(--c) 32%, transparent);
}
.mb-sg-dot{
  width: 12px; height: 12px; border-radius: 50%;
  background: var(--c);
  box-shadow: 0 0 10px color-mix(in srgb, var(--c) 60%, transparent);
}
.mb-sg-label{ font-weight: 800; font-size: 16px; color: var(--c); min-width: 108px; }
.mb-sg-sep{ width: 1px; align-self: stretch; background: var(--mist); margin: 3px 2px; }
.mb-sg-desc{ color: var(--slate); font-size: 14px; line-height: 1.4; }
/* per-status colour — tied to theme tokens where possible */
.mb-sg-row[data-st="new"]{      --c: #7b83ff; }
.mb-sg-row[data-st="review"]{   --c: var(--warn); }
.mb-sg-row[data-st="planning"]{ --c: var(--action); }
.mb-sg-row[data-st="complete"]{ --c: var(--success); }
/* Small phones — let the description wrap under the label if space is tight. */
@media (max-width: 420px){
  .mb-sg-label{ min-width: 92px; font-size: 15px; }
  .mb-sg-ico{ width: 34px; height: 34px; }
}


/* ═════════════════════════════════════════════════════════════════════════
   §23  PRODUCT "USE MOMENTS" PHOTO GRID.

   site-patch.js §15 swaps the four text cards under "Made for real days."
   for the four lifestyle photos (which already carry their title + caption).
   2×2 on desktop/tablet, single column on phones. Images are 3:2 landscape
   to match the source photos, cover-cropped so any cell size stays clean. */
.moment-strip{
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 18px;
  margin-top: 8px;
}
.moment-cell{
  aspect-ratio: 3 / 2;
  border-radius: 16px;
  overflow: hidden;                 /* clips the zoomed image → crops the white frame */
  box-shadow: 0 10px 30px rgba(0, 0, 0, .14);
}
.moment-shot{
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
  transform: scale(1.06);           /* small zoom so the photos' white border isn't visible */
}
body.dark .moment-cell{ box-shadow: 0 12px 34px rgba(0, 0, 0, .45); }
@media (max-width: 719px){
  .moment-strip{ grid-template-columns: 1fr; gap: 14px; }
}
/* wrapper holding each photo + its icon */
.moment-item{ display: block; }

/* Clean fade-in on scroll — PC only. Each photo starts faded + slightly
   lowered, then eases to full clarity when it enters the viewport. The
   `.moment-in` class is added ONCE by site-patch.js §15 (IntersectionObserver
   that unobserves after firing), so there is no flicker, no re-trigger, and
   no pulsing — the reveal plays a single clean time per page load. GPU-only
   properties (opacity + transform) keep it smooth on every machine. */
@media (min-width: 1024px){
  .moment-item{
    opacity: 0;
    transform: translate3d(0, 26px, 0);
    transition: opacity .85s cubic-bezier(.16, 1, .3, 1),
                transform .85s cubic-bezier(.16, 1, .3, 1);
    will-change: opacity, transform;
  }
  .moment-item.moment-in{
    opacity: 1;
    transform: none;
  }
  /* Gentle stagger so the four photos resolve one after another. */
  .moment-strip .moment-item:nth-child(1){ transition-delay: 0ms; }
  .moment-strip .moment-item:nth-child(2){ transition-delay: 90ms; }
  .moment-strip .moment-item:nth-child(3){ transition-delay: 180ms; }
  .moment-strip .moment-item:nth-child(4){ transition-delay: 270ms; }
}

/* (Icons under the Use-moments photos were removed by request — the titles
   and icons are already baked into the photographs themselves.) */


/* ═════════════════════════════════════════════════════════════════════════
   §24  REMOVE THE SMALL SECTION LABELS (eyebrows + breadcrumbs).

   Every section's small kicker above the big heading — "The need",
   "Product preview", "Community", "Science", "Founders", "Quick FAQ",
   the hero's "Energy gummies — coming soon", and the page breadcrumbs like
   "Learn / About This Product" — is hidden site-wide. The big headings and
   all body content are untouched. (The elements stay in the DOM so scripts
   that read their text, e.g. to place the warning watermark, still work.) */
.eyebrow,
.crumbs{ display: none !important; }


/* ═════════════════════════════════════════════════════════════════════════
   §25  SCIENCE PAGE — premium glassmorphism info cards
   (Dose clarity / Timing / Individual variability).

   site-patch.js §16 rebuilds each card into an outer entrance container
   (`.card`) + an inner glass card (`.mb-sci-card`) holding: a circular icon
   with a radial-gradient glow, a numbered badge (01/02/03), the heading and
   copy, a bottom accent line, and a light-sweep. It also drops faint floating
   particles, soft background glows and a low-opacity connector curve behind
   the grid. The 3D cursor tilt is handled in JS (max 3°).

   Identical on every device/browser: layout, radii, shadows and glass are all
   the same; only the hover micro-interactions are desktop-pointer only.
   Entrance reuses app.js's reliable `.in-view` toggle (no competing observer)
   but restyles it as a fade + gentle rise + blur-clear — elegant, no bounce. */
.mb-sci-steps{ position: relative; isolation: isolate; }

/* soft background depth (radial light) */
.mb-sci-steps::before{
  content: ""; position: absolute; inset: -14% -6%; z-index: 0; pointer-events: none;
  background:
    radial-gradient(440px 300px at 16% 22%, color-mix(in srgb, var(--action) 12%, transparent), transparent 70%),
    radial-gradient(420px 300px at 84% 78%, color-mix(in srgb, var(--action) 9%, transparent), transparent 72%);
  opacity: .8;
}
/* faint floating particles */
.mb-sci-particles{ position: absolute; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; }
.mb-sci-particles i{
  position: absolute; width: 6px; height: 6px; border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--action) 60%, transparent), transparent 70%);
  opacity: .10; animation: sciFloat 15s ease-in-out infinite;
}
@keyframes sciFloat{ 0%,100%{ transform: translateY(0); } 50%{ transform: translateY(-18px); } }
/* ultra-thin connector curve with glowing nodes (opacity < 10%) */
.mb-sci-conn{ position: absolute; z-index: 0; pointer-events: none; opacity: .08;
  top: 34px; left: 6%; right: 6%; height: 46px; }
.mb-sci-conn svg{ width: 100%; height: 100%; display: block; }
.mb-sci-conn circle{ filter: drop-shadow(0 0 3px var(--action)); }
@media (max-width: 1023px){ .mb-sci-conn{ display: none; } }

/* OUTER card — pure entrance container (glass moved to the inner element) */
.mb-sci-steps > .card{
  background: transparent !important;
  border: 0 !important;
  box-shadow: none !important;
  padding: 0 !important;
  position: relative; z-index: 1;
  overflow: visible !important;
  perspective: 1000px;
}
/* entrance: fade + rise + de-blur (reuses app.js .in-view; restrained, no bounce) */
.mb-sci-steps > .card.sr-edge{
  transition: opacity .85s cubic-bezier(.22, 1, .36, 1),
              transform .85s cubic-bezier(.22, 1, .36, 1),
              filter .85s ease !important;
}
.mb-sci-steps > .card.sr-edge:not(.in-view){
  opacity: 0 !important; transform: translate3d(0, 28px, 0) !important; filter: blur(9px) !important;
}
.mb-sci-steps > .card.sr-edge.in-view{
  opacity: 1 !important; transform: none !important; filter: blur(0) !important;
}
.mb-sci-steps > .card:nth-child(2).sr-edge{ transition-delay: .12s !important; }
.mb-sci-steps > .card:nth-child(3).sr-edge{ transition-delay: .24s !important; }

/* INNER — the glass card */
.mb-sci-card{
  position: relative; overflow: hidden;
  border-radius: 22px;
  padding: clamp(24px, 2.4vw, 32px);
  min-height: 100%;
  background: rgba(255,255,255,.55);
  -webkit-backdrop-filter: blur(16px) saturate(1.25);
          backdrop-filter: blur(16px) saturate(1.25);
  border: 1px solid rgba(255,255,255,.5);
  box-shadow:
    0 1px 1px rgba(16,24,40,.04),
    0 6px 14px rgba(16,24,40,.06),
    0 18px 40px rgba(16,24,40,.08),
    inset 0 1px 0 rgba(255,255,255,.6);
  transition: transform .35s cubic-bezier(.22,1,.36,1),
              box-shadow .35s ease, background .35s ease, border-color .35s ease;
  transform-style: preserve-3d;
}
/* soft gradient edge */
.mb-sci-card::after{
  content: ""; position: absolute; inset: 0; border-radius: 22px; padding: 1px; pointer-events: none;
  background: linear-gradient(140deg, rgba(255,255,255,.9), rgba(255,255,255,.04) 42%, color-mix(in srgb, var(--action) 30%, transparent));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  opacity: .55;
}
/* slow light sweep every ~18s */
.mb-sci-sheen{
  position: absolute; top: -20%; bottom: -20%; left: -45%; width: 40%;
  background: linear-gradient(105deg, transparent, rgba(255,255,255,.4), transparent);
  transform: skewX(-16deg); pointer-events: none; z-index: 1;
  animation: sciSheen 18s ease-in-out infinite;
}
@keyframes sciSheen{ 0%,86%{ left: -45%; } 95%,100%{ left: 125%; } }

/* icon in a soft radial-gradient circle */
.mb-sci-card .mb-sci-ico{
  position: relative; z-index: 2;
  width: 56px; height: 56px; border-radius: 50%;
  display: grid; place-items: center; margin: 0 0 18px;
  color: var(--action);
  background: radial-gradient(circle at 35% 30%, color-mix(in srgb, var(--action) 20%, #fff), color-mix(in srgb, var(--action) 6%, #fff));
  box-shadow: inset 0 0 12px color-mix(in srgb, var(--action) 18%, transparent), 0 4px 12px rgba(16,24,40,.08);
  transition: transform .35s cubic-bezier(.22,1,.36,1), box-shadow .35s ease;
}
.mb-sci-card .mb-sci-ico svg{ width: 26px; height: 26px; }

/* numbered badge, upper-right */
.mb-sci-card .mb-sci-num{
  position: absolute; top: 16px; right: 16px; z-index: 3;
  width: 30px; height: 30px; border-radius: 50%;
  display: grid; place-items: center;
  font-size: 11px; font-weight: 800; letter-spacing: .03em;
  color: var(--slate);
  background: rgba(255,255,255,.6);
  border: 1px solid rgba(16,24,40,.08);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
/* bottom accent line — animates left→right on entry */
.mb-sci-card .mb-sci-accent{
  position: absolute; left: clamp(24px, 2.4vw, 32px); bottom: 18px; z-index: 2;
  height: 3px; width: 0; border-radius: 3px;
  background: linear-gradient(90deg, var(--action), color-mix(in srgb, var(--action) 25%, transparent));
  transition: width .9s cubic-bezier(.22,1,.36,1) .3s;
}
.card.in-view .mb-sci-card .mb-sci-accent{ width: 48px; }

.mb-sci-card h3, .mb-sci-card p{ position: relative; z-index: 2; }
.mb-sci-card p{ margin-bottom: 26px; }   /* room above the accent line */

/* HOVER — desktop pointers only (transform handled by JS tilt) */
@media (hover: hover) and (pointer: fine){
  .mb-sci-card:hover{
    background: rgba(255,255,255,.7);
    border-color: rgba(255,255,255,.85);
    box-shadow:
      0 2px 4px rgba(16,24,40,.05),
      0 10px 24px rgba(16,24,40,.09),
      0 34px 64px rgba(16,24,40,.13),
      inset 0 1px 0 rgba(255,255,255,.75);
  }
  .mb-sci-card:hover .mb-sci-ico{
    transform: scale(1.08);
    box-shadow: inset 0 0 16px color-mix(in srgb, var(--action) 26%, transparent),
                0 0 24px color-mix(in srgb, var(--action) 32%, transparent),
                0 6px 16px rgba(16,24,40,.1);
  }
}

/* DARK MODE glass */
body.dark .mb-sci-card{
  background: rgba(26,28,36,.5);
  border-color: rgba(255,255,255,.09);
  box-shadow: 0 1px 1px rgba(0,0,0,.3), 0 12px 32px rgba(0,0,0,.42), inset 0 1px 0 rgba(255,255,255,.06);
}
body.dark .mb-sci-card .mb-sci-num{ background: rgba(255,255,255,.06); border-color: rgba(255,255,255,.1); color: #c9cdd6; }
body.dark .mb-sci-card .mb-sci-ico{
  background: radial-gradient(circle at 35% 30%, color-mix(in srgb, var(--action) 32%, #1a1c24), color-mix(in srgb, var(--action) 10%, #1a1c24));
}
@media (hover: hover) and (pointer: fine){
  body.dark .mb-sci-card:hover{ background: rgba(34,37,46,.62); border-color: rgba(255,255,255,.16); }
}

/* comfortable spacing between the cards */
@media (min-width: 768px){
  .mb-sci-steps{ gap: clamp(20px, 2.4vw, 36px) !important; }
}

/* Reduced motion — keep it calm: no sweep / float, cards simply fade in. */
@media (prefers-reduced-motion: reduce){
  .mb-sci-sheen, .mb-sci-particles i{ animation: none !important; }
}

/* ── Removed by request: the background glow/particles/connector behind the
   cards, the blue accent line under the text, and the numbered circle badges.
   The glass cards, icons, hover and entrance are all kept. ── */
.mb-sci-steps::before{ display: none !important; }        /* soft background light */
.mb-sci-particles,
.mb-sci-conn{ display: none !important; }                 /* floating particles + connector curve */
.mb-sci-card .mb-sci-accent,
.mb-sci-card .mb-sci-num{ display: none !important; }      /* blue accent line + 01/02/03 badges */
.mb-sci-card p{ margin-bottom: 0 !important; }             /* reclaim the space the accent line used */

/* ── Borders matched to the rest of the site, and tighter spacing ──────────
   Every other card/panel on the site is bordered with `var(--mist)` (the
   shared border token, which flips automatically in dark mode). The glass
   cards were using a translucent white edge, so on light backgrounds they
   read as borderless and in dark mode they didn't match. Use the site token
   so all rectangles on the site share one edge colour. */
.mb-sci-card{
  border: 1px solid var(--mist) !important;
}
.mb-sci-card::after{ display: none !important; }   /* the old white gradient edge */
@media (hover: hover) and (pointer: fine){
  .mb-sci-card:hover{
    border-color: color-mix(in srgb, var(--action) 32%, var(--mist)) !important;
  }
}

/* DARK MODE — white icons, same edge colour as every other card. */
body.dark .mb-sci-card .mb-sci-ico{
  color: #fff;
  background: rgba(255, 255, 255, .07);
  box-shadow: inset 0 0 12px rgba(255, 255, 255, .06);
}
body.dark .mb-sci-card .mb-sci-ico svg{ stroke: #fff; }
@media (hover: hover) and (pointer: fine){
  body.dark .mb-sci-card:hover .mb-sci-ico{
    background: rgba(255, 255, 255, .12);
    box-shadow: inset 0 0 16px rgba(255, 255, 255, .10), 0 0 22px rgba(255, 255, 255, .12);
  }
}

/* Smaller gap between the intro copy and the cards. The grid sits inside a
   `.section--tight`, whose top padding was leaving a large empty band — pull
   the row up a little (scaled down on phones). */
.mb-sci-steps{ margin-top: -30px; }
@media (max-width: 767px){ .mb-sci-steps{ margin-top: -14px; } }

/* ── SOLID, UNBROKEN EDGES ────────────────────────────────────────────────
   The light-sweep sits just off the left edge at rest, but its -16° skew
   pushed the top corner back into view — showing as a pale diagonal wedge
   that broke the border line at each card's top-left. Fix: the sweep is now
   fully transparent at rest and only fades in while it crosses the card, so
   the border reads as one clean, solid line the whole way round. */
.mb-sci-sheen{
  opacity: 0;
  animation-name: sciSheenFixed !important;
}
@keyframes sciSheenFixed{
  0%, 86%   { left: -60%; opacity: 0; }
  89%       { opacity: .35; }
  93%       { opacity: .35; }
  96%, 100% { left: 125%; opacity: 0; }
}
body.dark .mb-sci-sheen{
  background: linear-gradient(105deg, transparent, rgba(255,255,255,.10), transparent);
}

/* Border = exactly the site's shared edge token, same as every other
   rectangle on the site. (An earlier version blended it with #fff, which is
   why it looked white in dark mode — that blending is gone.) */
.mb-sci-card{
  border: 1px solid var(--mist) !important;
  border-radius: 22px !important;
}
body.dark .mb-sci-card{
  border-color: var(--mist) !important;
}

/* Corners: the OUTER entrance container must not paint anything of its own.
   Its inherited `.card` border/background was drawing straight edges that sat
   slightly outside the rounded glass card — which is why the borders looked
   offset and the corners appeared to be missing. Blank it out completely,
   including any pseudo-elements, so the only visible edge is the inner
   card's own rounded 1px border. */
.mb-sci-steps > .card{
  border: 0 !important;
  background: none !important;
  box-shadow: none !important;
  border-radius: 22px !important;
  overflow: visible !important;
  -webkit-backdrop-filter: none !important;
          backdrop-filter: none !important;
}
.mb-sci-steps > .card::before,
.mb-sci-steps > .card::after{
  content: none !important;
  display: none !important;
}

/* HOVER EDGE FIX — the lifted card's top border used to vanish.
   Two causes: the hover style painted a white 1px inset highlight
   (`inset 0 1px 0 rgba(255,255,255,…)`) directly over the top border, and a
   1px border can sub-pixel away under the 3D tilt. Fix: drop the white
   highlight and add an inset 1px ring in the same edge colour, which renders
   crisply through the lift/tilt. Border stays `var(--mist)` — identical to
   every other rectangle on the site — while animating. */
@media (hover: hover) and (pointer: fine){
  .mb-sci-card:hover{
    border-color: var(--mist) !important;
    box-shadow:
      inset 0 0 0 1px var(--mist),
      0 2px 4px rgba(16, 24, 40, .05),
      0 10px 24px rgba(16, 24, 40, .09),
      0 34px 64px rgba(16, 24, 40, .13) !important;
  }
  body.dark .mb-sci-card:hover{
    border-color: var(--mist) !important;
    box-shadow:
      inset 0 0 0 1px var(--mist),
      0 10px 24px rgba(0, 0, 0, .40),
      0 34px 64px rgba(0, 0, 0, .50) !important;
  }
}

/* ROOT CAUSE of the cut-off top edge on hover: `backdrop-filter`.
   When an element with backdrop-filter is transformed (our lift + 3D tilt),
   the browser re-samples the backdrop against the *untransformed* box, which
   clips the element's own border along the moving edge — so the top border
   vanished mid-animation. Since the section behind these cards is a flat
   colour, the blur adds nothing visually; removing it fixes the rendering
   completely and the card keeps the same appearance.

   With the filter gone, the border and shadow are painted on the same
   element that moves — so they now travel with the card, perfectly intact. */
.mb-sci-card{
  -webkit-backdrop-filter: none !important;
          backdrop-filter: none !important;
  background: var(--card) !important;
  -webkit-backface-visibility: hidden;
          backface-visibility: hidden;
}
@media (hover: hover) and (pointer: fine){
  .mb-sci-card:hover{ background: var(--card) !important; }
}
/* the lifted card must not be clipped by its container */
.mb-sci-steps,
.mb-sci-steps > .card{ overflow: visible !important; }

/* TOP EDGE — visible at rest AND all the way through the animation.
   The card's resting shadow still carried a white 1px inset highlight
   (`inset 0 1px 0 rgba(255,255,255,.6)`) that painted straight over the top
   border. Removing it only from :hover wasn't enough: box-shadow interpolates
   between the two states, so mid-transition that white line reappeared and
   erased the top edge exactly while the card was moving. It is now gone from
   BOTH states, and both use the same `inset 0 0 0 1px var(--mist)` ring — so
   there is nothing white to fade through and the top border stays solid the
   entire time. */
.mb-sci-card{
  box-shadow:
    inset 0 0 0 1px var(--mist),
    0 1px 1px rgba(16, 24, 40, .04),
    0 6px 14px rgba(16, 24, 40, .06),
    0 18px 40px rgba(16, 24, 40, .08) !important;
}
body.dark .mb-sci-card{
  box-shadow:
    inset 0 0 0 1px var(--mist),
    0 1px 1px rgba(0, 0, 0, .30),
    0 12px 32px rgba(0, 0, 0, .42) !important;
}
/* dark hover re-declared last so it still deepens on lift */
@media (hover: hover) and (pointer: fine){
  body.dark .mb-sci-card:hover{
    box-shadow:
      inset 0 0 0 1px var(--mist),
      0 10px 24px rgba(0, 0, 0, .40),
      0 34px 64px rgba(0, 0, 0, .50) !important;
  }
}


/* ═════════════════════════════════════════════════════════════════════════
   §29  SUSTAINABILITY BLOCKS (site-patch §19).
   The eco band on Home and the three-card eco grid on the Product page. */
.mb-eco-band{
  position: relative;
  margin-top: clamp(24px, 3vw, 38px);
  padding: clamp(22px, 2.6vw, 30px) clamp(22px, 2.6vw, 32px);
  border: 1px solid var(--mist);
  border-radius: 20px;
  background:
    radial-gradient(120% 140% at 0% 0%, color-mix(in srgb, var(--action) 7%, transparent), transparent 62%),
    var(--card);
  overflow: hidden;
}
/* slim brand rule down the left edge */
.mb-eco-band::before{
  content: "";
  position: absolute; left: 0; top: 14px; bottom: 14px; width: 3px;
  border-radius: 0 3px 3px 0;
  background: linear-gradient(180deg, var(--action), color-mix(in srgb, var(--action) 18%, transparent));
}
.mb-eco-band-title{
  display: block;
  font-weight: 800;
  font-size: 11.5px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--action);
  margin-bottom: 18px;
}
.mb-eco-band-items{
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(16px, 2.2vw, 30px);
}
.mb-eco-band-item{
  display: flex;
  align-items: flex-start;
  gap: 13px;
}
.mb-eco-band-ico{
  flex: none;
  width: 46px; height: 46px;
  display: grid; place-items: center;
  border-radius: 12px;
  color: var(--action);
  background: color-mix(in srgb, var(--action) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--action) 20%, transparent);
}
.mb-eco-band-ico svg{ width: 30px; height: 30px; display: block; overflow: visible; }
.mb-eco-band-copy{ display: block; min-width: 0; }
.mb-eco-band-copy b{
  display: block;
  color: var(--ink);
  font-size: 14.5px;
  font-weight: 700;
  line-height: 1.3;
}
.mb-eco-band-copy em{
  display: block;
  margin-top: 3px;
  font-style: normal;
  color: var(--slate);
  font-size: 13px;
  line-height: 1.45;
}
@media (max-width: 820px){
  .mb-eco-band-items{ grid-template-columns: 1fr; gap: 16px; }
}


/* ─────────────────────────────────────────────────────────────────────────
   MISSION PAGE — circular-economy mark beside the copy.
   Arcs follow the theme (currentColor), the bolt uses the brand navy, and
   the whole mark is inline SVG so it is transparent and sharp at any size. */
.mb-mission-grid{
  display: grid;
  grid-template-columns: 1.25fr .75fr;
  gap: clamp(24px, 4vw, 64px);
  align-items: center;
}
.mb-mission-text{ min-width: 0; }
.mb-mission-art{
  justify-self: center;
  width: min(470px, 100%);
  color: var(--ink);          /* → white automatically in dark mode */
}
.mb-mission-art svg{ width: 100%; height: auto; display: block; overflow: visible; }
@media (max-width: 900px){
  .mb-mission-grid{ grid-template-columns: 1fr; }
  .mb-mission-art{ width: min(320px, 84%); justify-self: start; margin-top: 10px; }
}

/* ── The loop builds itself clockwise, like a clock hand ──────────────────
   1. top arrow draws            0.00s
   2. bolt strikes + shines      0.85s
   3. right arrow draws          2.10s
   4. plant grows, leaves sway   2.95s
   5. left arrow draws           4.25s
   6. can appears, then the ring
      and the cross strike it    5.10s
   Everything uses currentColor, so the whole mark turns white in dark mode. */

/* arrows */
.mb-ml-a1{ stroke-dasharray: 140; stroke-dashoffset: 140; }
.mb-ml-a2{ stroke-dasharray: 100; stroke-dashoffset: 100; }
.mb-ml-a3{ stroke-dasharray: 120; stroke-dashoffset: 120; }
.mb-art-in .mb-ml-a1{ animation: mbArcDraw .95s cubic-bezier(.42,0,.25,1) 0s forwards; }
.mb-art-in .mb-ml-a2{ animation: mbArcDraw .85s cubic-bezier(.42,0,.25,1) 2.10s forwards; }
.mb-art-in .mb-ml-a3{ animation: mbArcDraw .95s cubic-bezier(.42,0,.25,1) 4.25s forwards; }
@keyframes mbArcDraw{ to{ stroke-dashoffset: 0; } }

/* bolt — snaps in hard, then flashes twice like lightning */
.mb-ml-bolt{ opacity: 0; transform-box: fill-box; transform-origin: 50% 50%; }
.mb-art-in .mb-ml-bolt{ animation: mbBoltStrike 1.5s cubic-bezier(.2,1.4,.3,1) .85s forwards; }
@keyframes mbBoltStrike{
  0%   { opacity: 0; transform: scale(.55) rotate(-9deg); filter: none; }
  14%  { opacity: 1; transform: scale(1.18) rotate(3deg);
         filter: drop-shadow(0 0 16px currentColor) brightness(1.5); }
  24%  { opacity: .35; transform: scale(1) rotate(0deg); filter: none; }
  36%  { opacity: 1; filter: drop-shadow(0 0 26px currentColor) brightness(1.7); }
  48%  { opacity: .7;  filter: drop-shadow(0 0 8px currentColor); }
  62%  { opacity: 1;   filter: drop-shadow(0 0 18px currentColor); }
  100% { opacity: 1; transform: none; filter: none; }
}

/* plant — rises, then the leaves sway and glow green */
.mb-ml-plant{ opacity: 0; }
.mb-art-in .mb-ml-plant{ animation: mbFadeIn .5s ease 2.95s forwards; }
.mb-ml-leaf{ transform-box: fill-box; transform-origin: 50% 100%; }
/* grass tufts — sway with the plant, but at about a third of the amplitude
   so they read as ground texture rather than competing with the leaves */
.mb-ml-grass{ transform-box: fill-box; transform-origin: 50% 100%; }
.mb-art-in .mb-ml-grass{ animation: mbGrassSway 2.4s cubic-bezier(.36,1,.4,1) 3.15s 1 both; }
@keyframes mbGrassSway{
  0%   { transform: rotate(0deg); }
  28%  { transform: rotate(-2.6deg); }
  58%  { transform: rotate(1.7deg); }
  80%  { transform: rotate(-.7deg); }
  100% { transform: rotate(0deg); }
}
.mb-art-in .mb-ml-leaf{ animation: mbLeafSway 2.4s cubic-bezier(.36,1,.4,1) 3.15s 1 both; }
@keyframes mbLeafSway{
  0%   { transform: rotate(0deg); stroke: currentColor; filter: none; }
  28%  { transform: rotate(-8deg); }
  42%  { stroke: #22c55e; filter: drop-shadow(0 0 5px rgba(34,197,94,.85)); }
  58%  { transform: rotate(5deg); }
  70%  { stroke: #22c55e; filter: drop-shadow(0 0 4px rgba(34,197,94,.55)); }
  80%  { transform: rotate(-2deg); }
  100% { transform: rotate(0deg); stroke: currentColor; filter: none; }
}

/* can — body fades in, then the ring draws and the slash strikes through */
.mb-ml-can{ opacity: 0; }
.mb-art-in .mb-ml-can{ animation: mbFadeIn .5s ease 5.10s forwards; }
@keyframes mbFadeIn{ to{ opacity: 1; } }
.mb-ml-ring{ stroke-dasharray: 152; stroke-dashoffset: 152; }
.mb-ml-slash{ stroke-dasharray: 50; stroke-dashoffset: 50; }
.mb-art-in .mb-ml-ring{ animation: mbArcDraw .7s cubic-bezier(.45,0,.2,1) 5.45s forwards; }
.mb-art-in .mb-ml-slash{ animation: mbArcDraw .4s cubic-bezier(.4,0,.2,1) 6.05s forwards; }

/* ─────────────────────────────────────────────────────────────────────────
   PRODUCT-PAGE ECO CARDS — icon on top, everything left-aligned, three in a
   row with equal gaps. One rhythm for the vertical spacing:
       icon → 18px → heading → 10px → body
   Icons are inline SVG (transparent, resolution-independent), sized 56px. */
.mb-eco-grid{
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(20px, 2.6vw, 34px);
  align-items: start;
}
.mb-eco-card{
  text-align: left;                 /* matches the rest of the page */
  padding: clamp(22px, 2.2vw, 28px);
  border: 1px solid var(--mist);
  border-radius: 18px;
  background: var(--card);
  transition: transform .3s cubic-bezier(.22,1,.36,1), box-shadow .3s ease, border-color .3s ease;
}
@media (hover: hover) and (pointer: fine){
  .mb-eco-card:hover{
    transform: translateY(-3px);
    box-shadow: 0 10px 26px rgba(16,24,40,.09);
    border-color: color-mix(in srgb, var(--action) 34%, var(--mist));
  }
}
.mb-eco-ico{
  display: block;
  width: 72px; height: 72px;        /* larger — clearly readable */
  margin: 0 0 20px;                 /* even gap under the icon */
  color: var(--ink);
}
.mb-eco-ico svg{ width: 100%; height: 100%; display: block; overflow: visible; }
.mb-eco-card h3{ margin: 0 0 10px; font-size: 18px; line-height: 1.25; }
.mb-eco-card p{ margin: 0; color: var(--slate); font-size: 14.5px; line-height: 1.6; }
.mb-eco-card p b{ color: var(--ink); }

/* PHONE / TABLET — stack, keep the same left alignment and rhythm. */
@media (max-width: 900px){
  .mb-eco-grid{ grid-template-columns: 1fr; gap: 14px; }
  .mb-eco-ico{ width: 62px; height: 62px; margin-bottom: 16px; }
}

/* ── ICON ANIMATIONS — play once when the block scrolls into view ─────────
   site-patch adds `.mb-eco-in` per card via IntersectionObserver.
   Deliberately NOT disabled under prefers-reduced-motion: Windows commonly
   reports reduced-motion and these are short, one-shot, non-looping. */

/* 1 — NO CAN: the prohibition ring draws, then the slash strikes through. */
.mb-eco-ring{ stroke-dasharray: 158; stroke-dashoffset: 158; }
.mb-eco-slash{ stroke-dasharray: 51; stroke-dashoffset: 51; }
.mb-eco-in .mb-eco-ring{ animation: ecoDrawRing .75s cubic-bezier(.5,0,.2,1) .15s forwards; }
.mb-eco-in .mb-eco-slash{ animation: ecoDrawSlash .45s cubic-bezier(.4,0,.2,1) .85s forwards; }
@keyframes ecoDrawRing { to { stroke-dashoffset: 0; } }
@keyframes ecoDrawSlash{ to { stroke-dashoffset: 0; } }

/* 2 — RECYCLING: each arrow draws in turn AROUND the triangle — left edge
       up, then right edge down, then the bottom edge back to the start. The
       motion follows the path of the triangle instead of spinning, and the
       loop finishes where it began. */
.mb-eco-arrow{ stroke-dasharray: 52; stroke-dashoffset: 52; }
.mb-eco-in .mb-eco-arrow:nth-of-type(1){ animation: ecoDrawArrow .55s cubic-bezier(.4,0,.2,1) .20s forwards; }
.mb-eco-in .mb-eco-arrow:nth-of-type(2){ animation: ecoDrawArrow .55s cubic-bezier(.4,0,.2,1) .70s forwards; }
.mb-eco-in .mb-eco-arrow:nth-of-type(3){ animation: ecoDrawArrow .55s cubic-bezier(.4,0,.2,1) 1.20s forwards; }
@keyframes ecoDrawArrow{ to { stroke-dashoffset: 0; } }

/* 3 — PLANT: a slow, calm sway, then the leaf outlines glow green. */
.mb-eco-plant{ transform-origin: 50% 92%; transform-box: fill-box; }
.mb-eco-in .mb-eco-plant{ animation: ecoSway 2.6s cubic-bezier(.36,1,.4,1) .35s 1 both; }
.mb-eco-in .mb-eco-leaf,
.mb-eco-in .mb-eco-vein{ animation: ecoLeafGlow 2.4s ease-in-out .8s 1 both; }
@keyframes ecoSway{
  0%   { transform: rotate(0deg); }
  26%  { transform: rotate(-7deg); }
  56%  { transform: rotate(4.5deg); }
  80%  { transform: rotate(-1.8deg); }
  100% { transform: rotate(0deg); }
}
@keyframes ecoLeafGlow{
  0%, 100% { stroke: currentColor; filter: none; }
  32%, 66% { stroke: #22c55e; filter: drop-shadow(0 0 5px rgba(34,197,94,.85)); }
}

/* ── "Not a drink you sip." — clearer, with the same shimmer used on the
      current roadmap stage (§20). ───────────────────────────────────────── */
.mb-eco-note{
  margin-top: clamp(24px, 3vw, 34px);
  padding: clamp(18px, 2vw, 24px) clamp(20px, 2.2vw, 26px);
  border: 1px solid var(--mist);
  border-left: 3px solid var(--action);
  border-radius: 14px;
  background: var(--cloud);
}
.mb-eco-note-title{
  display: block;
  font-size: clamp(17px, 1.7vw, 20px);
  font-weight: 800;
  letter-spacing: -.01em;
  margin-bottom: 8px;
  /* shimmer — identical technique to the roadmap's current stage */
  --mb-base: #8b93a1;
  --mb-hi: var(--action);
  --mb-spread: 22px;
  color: transparent;
  -webkit-text-fill-color: transparent;
  background-image:
    linear-gradient(90deg, transparent calc(50% - var(--mb-spread)), var(--mb-hi), transparent calc(50% + var(--mb-spread))),
    linear-gradient(var(--mb-base), var(--mb-base));
  background-repeat: no-repeat;
  background-size: 250% 100%, 100% 100%;
  -webkit-background-clip: text;
          background-clip: text;
  animation: mbTextShimmer 3s linear infinite;
}
body.dark .mb-eco-note-title{ --mb-base: #8b93a1; --mb-hi: #cdd8ff; }
.mb-eco-note-body{
  display: block;
  color: var(--slate);
  font-size: 14.5px;
  line-height: 1.65;
  max-width: 78ch;
}


/* ═════════════════════════════════════════════════════════════════════════
   §30  THEME BULB — identical animation on Windows and macOS.

   styles.css (lines 542 & 881) disables the bulb's "zap" animation under
   `prefers-reduced-motion`. Windows very often reports that preference
   (system animations off by default in many setups) while macOS usually does
   not — which is exactly why the toggle felt lively on Mac and dead on
   Windows. We restore the full animation for everyone, plus the glow ring
   and the rays/glass transitions, so the button behaves the same everywhere.
   It is a short one-shot animation on a deliberate click, not ambient motion. */
.bulb.zap svg{
  animation: bulbZap .55s cubic-bezier(.34, 1.56, .64, 1) !important;
}
.bulb.zap{
  box-shadow: 0 0 0 9px rgba(255, 200, 61, .22), 0 0 26px rgba(255, 200, 61, .35) !important;
}
.bulb{
  transition: color .3s ease, border-color .3s ease, background-color .3s ease,
              box-shadow .45s ease, transform .28s cubic-bezier(.22, .61, .36, 1) !important;
}
.bulb svg{ transition: transform .3s ease !important; }
.bulb .rays{ transition: opacity .35s ease !important; }
.bulb .glass{ transition: fill .35s ease !important; }


/* ═════════════════════════════════════════════════════════════════════════
   §28  FAQ PAGE — smaller gap between the intro copy and the category chips.
   site-patch.js §16b tags the filter section `mb-faq-tight`; here we cut its
   top padding so the chips sit closer under the lead paragraph. */
.mb-faq-tight{ padding-top: 0 !important; }
.mb-faq-tight > .filters{ margin-top: -34px; }
@media (max-width: 767px){
  .mb-faq-tight > .filters{ margin-top: -16px; }
}


/* ═════════════════════════════════════════════════════════════════════════
   §26  IMPORTANT-INFO WATERMARK.

   For the customer-facing "please note" sections — Product → "Take it. Keep
   moving." and Science / Explorer → "What this tool cannot know." —
   site-patch.js §17 adds `mb-warnbg`. We paint a large exclamation mark (just
   the "!", no circle around it) in a calm, muted red with a soft glow — the
   `mask` makes the element the exact shape of the glyph, and `drop-shadow`
   then makes THAT shape glow (a subtle, not-bright red shine). It sits behind
   the content (pointer-events off) so it's visible but covers nothing.
   Mask works across all modern browsers via the -webkit- prefix (Safari/iOS)
   and the standard property (Chrome/Firefox/Edge). */
.mb-warnbg{ position: relative; overflow: hidden; }
.mb-warnbg > *{ position: relative; z-index: 1; }   /* keep all real content above the watermark */
.mb-warnbg::after{
  content: "";
  position: absolute; z-index: 0; pointer-events: none;
  right: 6%; top: 50%; transform: translateY(-50%);
  width: min(120px, 14vw); height: min(240px, 30vw);
  background: #c15b52;                        /* calm, muted red — not bright */
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 100'%3E%3Crect x='15' y='6' width='10' height='58' rx='5'/%3E%3Ccircle cx='20' cy='86' r='7'/%3E%3C/svg%3E") no-repeat center / contain;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 100'%3E%3Crect x='15' y='6' width='10' height='58' rx='5'/%3E%3Ccircle cx='20' cy='86' r='7'/%3E%3C/svg%3E") no-repeat center / contain;
  opacity: .18;
  filter: drop-shadow(0 0 18px rgba(193, 91, 82, .55));   /* the calm red shine */
}
body.dark .mb-warnbg::after{
  background: #d06a60;
  opacity: .24;
  filter: drop-shadow(0 0 20px rgba(208, 106, 96, .6));
}
@media (max-width: 768px){
  .mb-warnbg::after{ width: 74px; height: 150px; right: -6px; opacity: .14; }
}


/* ═════════════════════════════════════════════════════════════════════════
   §27  NAVIGATION & BUTTON INTERACTION FIXES.

   (a) INSTANT route scroll — styles.css sets `html{scroll-behavior:smooth}`,
   which made every page-change visibly animate-scroll from the bottom to the
   top (looked like lag). Force it to jump instantly, so a new subpage simply
   appears at the top. Intentional smooth scrolls elsewhere use the JS
   `behavior:'smooth'` option, which still overrides this. */
html{ scroll-behavior: auto !important; }

/* (b) BUTTON HOVER — replace the "magnetic" cursor-follow (app.js moves the
   button toward the pointer, which feels wrong on macOS) with a clean, uniform
   hover: a gentle spring lift + slight scale, identical on Windows and macOS.
   The !important beats app.js's inline transform, so the button no longer
   trails the mouse — it just reacts once when hovered. */
@media (hover: hover) and (pointer: fine){
  .btn--primary, .btn--secondary{
    transition: transform .32s cubic-bezier(.34, 1.56, .64, 1),
                box-shadow .3s ease, background .2s ease, color .2s ease, border-color .2s ease !important;
  }
  .btn--primary:hover, .btn--secondary:hover{
    transform: translateY(-3px) scale(1.035) !important;   /* spring easing = subtle bounce */
  }
  .btn--primary:active, .btn--secondary:active{
    transform: translateY(-1px) scale(.99) !important;
    transition: transform .12s ease !important;
  }
}
