/*
 * Stamp Foundation - shared DESIGN SYSTEM (motion + surfaces).
 * ============================================================
 *
 * Sibling to styles/tokens.css. Where tokens.css owns the *colours*, this
 * file owns the *design language*: the motion system, the frosted nav, the
 * "boxes pop and breathe" card hover, the feathered section dividers, the
 * hero stage scaffold and the scroll-cue chevron. Pages <link> both files
 * and inherit one consistent, award-quality feel.
 *
 * Ported from the redesigned Inkwell landing page (products/inkwell/index.html)
 * and RECOLOURED to be driven entirely by the shared tokens (--green,
 * --green-soft, --green-dark, --gold, --bg, --card, --card-alt, --border,
 * --text, --text-sub, --text-mute, --shadow, --nav-bg). It carries NO
 * hardcoded hex and NO violet, so it themes green on the company/Stamp
 * surfaces here and could theme violet/neutral elsewhere purely by swapping
 * the tokens in tokens.css. The single site easing curve is
 * cubic-bezier(.2,.7,.2,1) throughout.
 *
 * The per-page IntersectionObserver reveal + nav.scrolled scripts stay inline
 * (CSP: self + inline only, no external JS). A minimal reference pattern lives
 * in the comment at the bottom of this file.
 *
 * Everything here is disabled wholesale under prefers-reduced-motion (see the
 * block at the very end): opacity:1, no transform, no animation, no transition.
 */

/* ── single source of truth for the "pop" recipe ─────────────────────────────
   Every emphasis card lifts by the same amount with the same green glow. The
   accent tokens default to green here; a page that wants a different accent
   could re-point --pop-accent / --pop-accent-soft without touching this file. */
:root {
  --site-ease:        cubic-bezier(.2,.7,.2,1);
  --pop-lift:         -5px;
  --pop-scale:        1.018;
  --pop-accent:       var(--green);
  --pop-accent-soft:  var(--green-soft);
  --pop-glow:         0 16px 36px -12px color-mix(in srgb, var(--pop-accent) 30%, transparent),
                      0 0 0 1px color-mix(in srgb, var(--pop-accent) 14%, transparent);
}

/* anchor landing clears the sticky nav */
html { scroll-padding-top: 84px; }

/* ── Frosted nav ─────────────────────────────────────────────────────────────
   A light, translucent blur by default so the hero visual bleeds through the
   top; it solidifies to a near-opaque background once content scrolls under it
   (toggled by adding .scrolled via the inline scroll listener) so the headline
   never smears through the blur. Pages keep their own nav layout / links; this
   only governs the surface + the scrolled transition. */
nav.frost {
  position: sticky; top: 0; z-index: 40;
  backdrop-filter: saturate(150%) blur(16px);
  -webkit-backdrop-filter: saturate(150%) blur(16px);
  background: var(--nav-bg);
  border-bottom: 1px solid color-mix(in srgb, var(--border) 65%, transparent);
  transition: background-color .25s ease, border-color .25s ease, box-shadow .25s ease;
}
nav.frost.scrolled {
  background: color-mix(in srgb, var(--bg) 98%, transparent);
  border-bottom-color: var(--border);
  box-shadow: 0 1px 0 0 var(--border),
              0 8px 24px -18px color-mix(in srgb, var(--green-dark) 45%, transparent);
}

/* ── Hero stage scaffold ─────────────────────────────────────────────────────
   Holds the WebGL hero visual behind the headline. Pulled up under the sticky
   nav (margin-top:-65px) so the visual extends behind the frosted bar and the
   nav reveals a soft bleed at the top. The ::after is a readability scrim that
   lifts the headline off the visual and fades the visual into the page
   background at the bottom so the next section joins seamlessly. */
.hero-stage {
  position: relative; overflow: hidden;
  margin-top: -65px;
  padding: calc(65px + clamp(28px, 5vh, 66px)) 0 clamp(48px, 7vh, 88px);
}
.hero-stage > canvas {
  position: absolute; inset: 0; width: 100%; height: 100%;
  z-index: 0; display: block;
}
.hero-stage::after {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background:
    radial-gradient(120% 86% at 50% 40%, color-mix(in srgb, var(--bg) 52%, transparent) 0%, transparent 62%),
    linear-gradient(to bottom, transparent 58%, var(--bg) 100%);
}
.hero-stage > .wrap,
.hero-stage > .hero-headline { position: relative; z-index: 2; }
/* CSS fallback when WebGL is unavailable: a calm green wash so the stage never
   looks broken. The canvas (when it paints) sits on top of this. */
.hero-stage {
  background:
    radial-gradient(80% 70% at 50% 30%, color-mix(in srgb, var(--green) 16%, transparent), transparent 70%),
    var(--bg);
}

/* ── Motion system ───────────────────────────────────────────────────────────
   .rise   = on-load staggered entrance (the hero text), delays .d1-.d5.
   .reveal / .reveal-up = scroll-triggered entrance; START HIDDEN, an
            IntersectionObserver adds .in on entry. .reveal is the lighter
            section-head entrance; .reveal-up is the card elevation entrance.
   One fluid recipe: a gentle fade + small slide + a faint blur that resolves
   as it settles, all on the single site easing curve. */
.rise { opacity: 0; transform: translateY(20px); animation: sys-rise .9s var(--site-ease) both; }
.d1 { animation-delay: .06s; } .d2 { animation-delay: .16s; }
.d3 { animation-delay: .28s; } .d4 { animation-delay: .42s; } .d5 { animation-delay: .56s; }
@keyframes sys-rise { to { opacity: 1; transform: none; } }

.reveal {
  opacity: 0; transform: translateY(22px); filter: blur(5px);
  transition: opacity .85s var(--site-ease), transform .85s var(--site-ease), filter .85s var(--site-ease);
  will-change: opacity, transform, filter;
}
.reveal.in { opacity: 1; transform: none; filter: none; }
.reveal.s2 { transition-delay: .06s; } .reveal.s3 { transition-delay: .12s; } .reveal.s4 { transition-delay: .18s; }

.reveal-up {
  opacity: 0; transform: translateY(20px); filter: blur(4px);
  transition: opacity .8s var(--site-ease), transform .8s var(--site-ease), filter .8s var(--site-ease);
  will-change: opacity, transform, filter;
}
.reveal-up.in { opacity: 1; transform: none; filter: none; }
/* calm cascade for groups of cards */
.rv-d1 { transition-delay: .04s; } .rv-d2 { transition-delay: .1s; }
.rv-d3 { transition-delay: .16s; } .rv-d4 { transition-delay: .22s; }

/* ── "Boxes pop and breathe" card language ───────────────────────────────────
   One recipe shared by every emphasis box (give the box class .pop-card): an
   entrance settle via .reveal-up plus a confident hover pop = lift + a very
   subtle scale + a soft green glow + a green border accent. */
.pop-card {
  transition: border-color .26s var(--site-ease),
              transform .32s var(--site-ease),
              box-shadow .32s var(--site-ease);
}
.pop-card:hover {
  transform: translateY(var(--pop-lift)) scale(var(--pop-scale));
  box-shadow: var(--pop-glow);
  border-color: var(--pop-accent);
}

/* Highlighted card: persistent green border + soft glow + a faint top ink
   accent, and a slightly stronger settle-in on reveal. Lifts a touch more on
   hover than the rest. */
.pop-hl {
  border-color: var(--pop-accent) !important;
  box-shadow: var(--shadow),
              0 0 0 1px color-mix(in srgb, var(--pop-accent) 22%, transparent),
              0 18px 40px -16px color-mix(in srgb, var(--pop-accent) 30%, transparent);
  position: relative;
}
.pop-hl::before {
  content: ""; position: absolute; left: 16%; right: 16%; top: 0; height: 2px;
  border-radius: 2px; pointer-events: none;
  background: linear-gradient(90deg, transparent, var(--pop-accent), transparent);
  opacity: .85;
}
.pop-hl:hover {
  transform: translateY(-7px) scale(1.026) !important;
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--pop-accent) 30%, transparent),
              0 22px 52px -14px color-mix(in srgb, var(--pop-accent) 42%, transparent) !important;
}
.pop-hl.reveal-up { transform: translateY(26px) scale(.985); }
.pop-hl.reveal-up.in { transform: none; }

/* ── Feathered section dividers ──────────────────────────────────────────────
   A tinted band (.band, background: var(--card-alt)) melts into the page rather
   than stacking as a boxed slab: the page bg fades into the band's tint over
   ~160px at the top (with a faint green ink bloom riding on top), and the tint
   fades back into the page over ~96px at the bottom. No hard hairlines. */
.band { position: relative; background: var(--card-alt); }
.band::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 160px;
  pointer-events: none; z-index: 0;
  background:
    radial-gradient(120% 100% at 50% 0%, color-mix(in srgb, var(--green) 7%, transparent) 0%, transparent 70%),
    linear-gradient(to bottom, var(--bg) 0%, color-mix(in srgb, var(--bg) 55%, transparent) 36%, transparent 100%);
}
.band::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 96px;
  pointer-events: none; z-index: 0;
  background: linear-gradient(to bottom, transparent 0%, color-mix(in srgb, var(--bg) 55%, transparent) 64%, var(--bg) 100%);
}
.band > .wrap { position: relative; z-index: 1; }

/* ── Scroll-cue chevron ──────────────────────────────────────────────────────
   .scroll-cue = the hero's labelled cue (column: text + bobbing chevron pill).
   .sec-cue    = the quieter, label-free between-section cue.
   Both use a round green-tinted glass pill that gently bobs, and both stop
   bobbing under reduced motion while staying clickable. */
@keyframes sys-bob { 0%,100% { transform: translateY(-3px); } 50% { transform: translateY(3px); } }

.scroll-cue {
  display: inline-flex; flex-direction: column; align-items: center; gap: 9px;
  margin-top: 30px; color: var(--text-sub); text-decoration: none;
  font-size: 0.74rem; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase;
  transition: color .2s ease, transform .26s var(--site-ease);
}
.scroll-cue .sc-chev {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: 50%;
  border: 1px solid color-mix(in srgb, var(--green) 26%, transparent);
  background: color-mix(in srgb, var(--card) 60%, transparent);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  color: var(--green);
  box-shadow: 0 6px 18px -10px color-mix(in srgb, var(--green) 55%, transparent);
  animation: sys-bob 2.4s var(--site-ease) infinite;
}
.scroll-cue .sc-chev svg { width: 18px; height: 18px; }
.scroll-cue:hover { color: var(--green); transform: translateY(2px); }
.scroll-cue:hover .sc-chev {
  border-color: var(--green);
  box-shadow: 0 8px 22px -8px color-mix(in srgb, var(--green) 60%, transparent),
              0 0 22px -6px color-mix(in srgb, var(--green) 38%, transparent);
}
.scroll-cue:focus-visible { outline: 2px solid var(--green); outline-offset: 4px; border-radius: 10px; }

.sec-cue { display: flex; justify-content: center; margin: 52px auto 0; position: relative; z-index: 2; }
.sec-cue a {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: 50%;
  border: 1px solid color-mix(in srgb, var(--green) 24%, transparent);
  background: color-mix(in srgb, var(--card) 55%, transparent);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  color: var(--green);
  box-shadow: 0 6px 18px -11px color-mix(in srgb, var(--green) 55%, transparent);
  animation: sys-bob 2.6s var(--site-ease) infinite;
  transition: color .2s ease, border-color .2s ease, box-shadow .3s var(--site-ease), transform .26s var(--site-ease);
}
.sec-cue a svg { width: 17px; height: 17px; }
.sec-cue a:hover {
  border-color: var(--green); color: var(--green-dark); transform: translateY(2px);
  box-shadow: 0 9px 22px -8px color-mix(in srgb, var(--green) 58%, transparent),
              0 0 20px -6px color-mix(in srgb, var(--green) 36%, transparent);
}
.sec-cue a:focus-visible { outline: 2px solid var(--green); outline-offset: 3px; }
/* on tinted bands the glass pill needs a touch more body so it doesn't vanish */
.band .sec-cue a { background: color-mix(in srgb, var(--card) 72%, transparent); }

/* ── Reduced motion: disable the whole language ──────────────────────────────
   opacity:1, no transform, no animation, no transition. Hover colour cues stay
   (handled by the colour-only declarations above), motion does not. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .rise, .reveal, .reveal-up,
  .pop-hl.reveal-up, .pop-hl.reveal-up.in {
    animation: none !important;
    transition: none !important;
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
  }
  .pop-card, .pop-hl,
  .scroll-cue, .scroll-cue .sc-chev,
  .sec-cue a, nav.frost { transition: none !important; }
  .scroll-cue .sc-chev, .sec-cue a { animation: none !important; }
  .pop-card:hover, .pop-hl:hover,
  .scroll-cue:hover, .sec-cue a:hover { transform: none !important; }
}

/* ─────────────────────────────────────────────────────────────────────────────
   REFERENCE: per-page inline scripts (keep inline; CSP forbids external JS).

   1) Frosted nav solidify on scroll:
        (function () {
          var navEl = document.querySelector('nav.frost'); if (!navEl) return;
          var ticking = false;
          function update() {
            navEl.classList.toggle('scrolled', window.scrollY > 12);
            ticking = false;
          }
          window.addEventListener('scroll', function () {
            if (!ticking) { ticking = true; requestAnimationFrame(update); }
          }, { passive: true });
          update();
        })();

   2) Scroll-reveal observer:
        (function () {
          var REDUCE = matchMedia('(prefers-reduced-motion: reduce)').matches;
          if (REDUCE || !('IntersectionObserver' in window)) return;
          var io = new IntersectionObserver(function (es) {
            es.forEach(function (e) {
              if (e.isIntersecting) { e.target.classList.add('in'); io.unobserve(e.target); }
            });
          }, { threshold: 0.16, rootMargin: '0px 0px -8% 0px' });
          document.querySelectorAll('.reveal, .reveal-up').forEach(function (el) { io.observe(el); });
        })();
   ───────────────────────────────────────────────────────────────────────────── */
