/* ============================================================
   NANVERA — shared motion layer
   Simple, restrained, "quiet luxury" transitions: nothing bounces,
   nothing spins, nothing calls attention to itself. Everything here
   is additive — it never changes layout, color or content, only
   how things settle into place and respond to touch.
   ============================================================ */

/* Respect users who've asked the OS for less motion. This must stay
   first so it overrides everything below it for those users. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

html { scroll-behavior: smooth; }

/* ---- Page entrance ----------------------------------------- */
/* A single, very quiet fade+rise on first paint. Short and subtle
   on purpose — a luxury feel comes from restraint, not a show. */
body {
  animation: nv-enter 0.5s cubic-bezier(.22,.61,.36,1) both;
}
@keyframes nv-enter {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ---- Scroll reveal ------------------------------------------- */
/* Sections fade/rise into place as they enter the viewport.
   Progressive enhancement: everything is fully visible by default,
   JS only adds the starting state for elements it can animate,
   so a no-JS visitor never sees anything missing. */
.nv-reveal {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.6s cubic-bezier(.22,.61,.36,1), transform 0.6s cubic-bezier(.22,.61,.36,1);
}
.nv-reveal.nv-in {
  opacity: 1;
  transform: translateY(0);
}

/* ---- Cards, photo frames, panels ------------------------------ */
/* Anything already using these existing component classes gets a
   gentle lift + deepened shadow on hover — no color or size jump. */
.prod-card, .app-card, .card, .cat-card, .problem-card, .prod-media,
.box-card, .quality-card, .download-card {
  transition: transform 0.35s cubic-bezier(.22,.61,.36,1),
              box-shadow 0.35s cubic-bezier(.22,.61,.36,1);
}
.prod-card:hover, .app-card:hover, .card:hover, .cat-card:hover,
.problem-card:hover, .box-card:hover, .quality-card:hover,
.download-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 18px 40px -16px rgba(20,27,24,.18);
}
.prod-media:hover {
  box-shadow: 0 18px 40px -16px rgba(20,27,24,.18);
}

/* Product photo: a very slight zoom inside its frame, the classic
   quiet-luxury product-shot hover. */
.prod-media img {
  transition: transform 0.6s cubic-bezier(.22,.61,.36,1);
}
.prod-media:hover img {
  transform: scale(1.03);
}

/* ---- Buttons --------------------------------------------------- */
.btn, button, a.cta, .cta-btn {
  transition: transform 0.25s cubic-bezier(.22,.61,.36,1),
              box-shadow 0.25s cubic-bezier(.22,.61,.36,1),
              background-color 0.25s ease, color 0.25s ease,
              border-color 0.25s ease;
}
.btn:hover, a.cta:hover, .cta-btn:hover {
  transform: translateY(-2px);
}
.btn:active, a.cta:active, .cta-btn:active,
button:active {
  transform: translateY(0);
}

/* ---- Text links -------------------------------------------------
   An underline that grows in from the left, rather than appearing
   instantly — the small detail that reads as considered rather than
   default-browser. Opt-in via class so nav/logo/buttons are
   untouched. */
.nv-link {
  position: relative;
  text-decoration: none;
  background-image: linear-gradient(currentColor, currentColor);
  background-position: 0 100%;
  background-repeat: no-repeat;
  background-size: 0% 1px;
  transition: background-size 0.35s cubic-bezier(.22,.61,.36,1);
}
.nv-link:hover { background-size: 100% 1px; }

/* ---- Nav items --------------------------------------------------- */
nav a, .nav a, header nav a {
  position: relative;
  transition: color 0.25s ease;
}
nav a::after, .nav a::after, header nav a::after {
  content: "";
  position: absolute;
  left: 0; right: 100%;
  bottom: -2px;
  height: 1px;
  background: currentColor;
  opacity: 0.7;
  transition: right 0.3s cubic-bezier(.22,.61,.36,1);
}
nav a:hover::after, .nav a:hover::after, header nav a:hover::after {
  right: 0;
}

/* ---- Language / tab pills, badges -------------------------------- */
.lang-btn, .tab, .pill, .tier, .badge {
  transition: background-color 0.25s ease, color 0.25s ease,
              border-color 0.25s ease, transform 0.25s ease;
}

/* ---- Mobile menu: slide down/up instead of snapping ---------------
   Every page defines `.mobilenav{display:none}` / `.mobilenav.open
   {display:flex}` inline — display can't be transitioned, so this
   overrides that pair to use a measured max-height + opacity slide
   instead. Kept in sync with the original's own spacing/border so it
   looks identical once open; equal CSS specificity + this file
   loading after the inline <style> block means it wins the cascade
   without editing 49 separate inline rules. */
.mobilenav {
  display: flex !important;
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  padding-top: 0 !important;
  padding-bottom: 0 !important;
  border-top-color: transparent !important;
  transition: max-height 0.4s cubic-bezier(.22,.61,.36,1),
              opacity 0.3s ease,
              padding 0.4s cubic-bezier(.22,.61,.36,1),
              border-top-color 0.4s ease;
}
.mobilenav.open {
  max-height: 480px;
  opacity: 1;
  padding-top: 10px !important;
  padding-bottom: 16px !important;
  border-top-color: var(--line) !important;
}

/* ---- Sticky header: shrinks + gains a shadow once you scroll past
   the hero. Chosen for wayfinding (always know where the nav is)
   rather than decoration — a functional pattern, not a flourish.
   `header.site` / `.headrow` / `.logochip img` are the same classes
   on every page, so one rule covers the whole site. `.nv-scrolled`
   is added by motion.js past a small scroll threshold. */
.headrow { transition: padding-block 0.3s cubic-bezier(.22,.61,.36,1); }
.logochip img { transition: height 0.3s cubic-bezier(.22,.61,.36,1); }
header.site { transition: box-shadow 0.3s ease; }
header.site.nv-scrolled {
  box-shadow: 0 4px 24px -10px rgba(20,27,24,.14);
}
header.site.nv-scrolled .headrow { padding-block: 8px; }
header.site.nv-scrolled .logochip img { height: 32px; }

/* ---- Back to top -------------------------------------------------
   Created by motion.js (no markup changes needed on any page).
   Hidden until you've scrolled a while, fades/rises in, same
   restrained motion language as everything else. */
.nv-totop {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 50;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  opacity: 0;
  transform: translateY(10px);
  pointer-events: none;
  transition: opacity 0.3s ease, transform 0.3s cubic-bezier(.22,.61,.36,1),
              box-shadow 0.3s ease;
}
.nv-totop.nv-show {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}
.nv-totop:hover {
  box-shadow: 0 14px 30px -12px rgba(20,27,24,.22);
  transform: translateY(-2px);
}

/* ---- Form fields ---------------------------------------------------
   A quiet focus state in place of the browser default outline snap —
   relevant mainly to the Request a Quote form on Contact. */
input:not([type=checkbox]):not([type=radio]), textarea, select {
  transition: border-color 0.25s ease, box-shadow 0.25s ease;
}
input:not([type=checkbox]):not([type=radio]):focus, textarea:focus, select:focus {
  outline: none;
  border-color: var(--brand, #0E6B4F) !important;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand, #0E6B4F) 18%, transparent);
}

/* ---- Quote form success/error message ------------------------------
   These two specific IDs only exist on the Contact page. The script
   toggles the `hidden` attribute, which by default can't transition
   (an element with `display:none` has no "before" state to animate
   from) — so this overrides that one pair of elements to use a
   measured slide instead, the same technique as the mobile menu. */
#leadMsgOk, #leadMsgErr {
  display: block !important;
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  margin-bottom: 0 !important;
  padding-top: 0 !important;
  padding-bottom: 0 !important;
  border-width: 0 !important;
  transition: max-height 0.45s cubic-bezier(.22,.61,.36,1), opacity 0.35s ease,
              margin-bottom 0.45s ease, padding 0.45s ease;
}
#leadMsgOk:not([hidden]), #leadMsgErr:not([hidden]) {
  max-height: 160px;
  opacity: 1;
  margin-bottom: 18px !important;
  padding-top: 14px !important;
  padding-bottom: 14px !important;
  border-width: 1px !important;
}

/* ---- Images fade in once loaded, instead of popping in -------------
   motion.js adds .nv-loaded once each image's load event fires (or
   immediately if it's already cached/complete). */
img.nv-fade { opacity: 0; transition: opacity 0.5s ease; }
img.nv-fade.nv-loaded { opacity: 1; }
