/* ==========================================================================
   DNP MOTION LAYER  (static/css/motion.css)
   --------------------------------------------------------------------------
   All premium animations live in THIS file + static/js/motion.js.
   Nothing here changes layout, business logic or existing page content.

   HOW TO TUNE
   - Speed:      edit the --motion-* tokens just below.
   - Distance:   --motion-distance (how far items slide up while revealing).
   - Turn off:   remove the two <link>/<script> tags for motion.* from the pages.

   SAFETY RULES BUILT IN
   - Only `transform` and `opacity` are animated (GPU friendly, no layout shifts).
   - Content is never hidden unless motion.js is running (see [data-motion]).
   - `prefers-reduced-motion: reduce` switches every effect off.
   ========================================================================== */

:root {
  --motion-ease: cubic-bezier(.2, .75, .2, 1);   /* smooth "ease-out" used everywhere */
  --motion-fast: .2s;                            /* hover / press feedback */
  --motion-base: .6s;                            /* section + card reveal */
  --motion-slow: .85s;                           /* hero + heading reveal */
  --motion-distance: 22px;                       /* slide-up distance */
  --motion-word-step: 45ms;                      /* delay between heading words */
  --dnp-focus-ring: #a8844b;                     /* keyboard focus colour (gold) */
}

/* ---------- 1. Scroll reveal (cards, sections, blocks) ------------------- */
/* motion.js adds data-motion="pending" ONLY to items that are below the fold,
   then switches to "in" when they scroll into view. Items already visible on
   load are never hidden, so the page appears instantly. */
[data-motion="pending"] {
  opacity: 0;
  transform: translate3d(0, var(--motion-distance), 0);
}
[data-motion="in"] {
  opacity: 1;
  transform: none;
  transition:
    opacity var(--motion-base) var(--motion-ease) var(--motion-delay, 0ms),
    transform var(--motion-base) var(--motion-ease) var(--motion-delay, 0ms);
}

/* ---------- 2. Heading word reveal --------------------------------------- */
/* motion.js wraps each word:  <span class="mw"><span class="mw-i">Word</span></span>
   The inner word slides up out of a small mask. Transform-only: text is never
   transparent, and without JS the heading is untouched. */
.mw {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
  padding-bottom: .14em;      /* keeps descenders (g, y, p) from being clipped */
  margin-bottom: -.14em;
}
.mw-i {
  display: inline-block;
  transform: translate3d(0, 108%, 0);
}
[data-motion-split="in"] .mw-i {
  transform: none;
  transition: transform var(--motion-slow) var(--motion-ease)
              calc(var(--i, 0) * var(--motion-word-step));
}

/* ---------- 3. Hero slider entrance -------------------------------------- */
/* Runs each time a slide gets the existing `.on` class. h1 uses transform only
   so the main headline paints immediately (good for LCP). */
@keyframes motion-rise      { from { transform: translate3d(0, 18px, 0); } to { transform: none; } }
@keyframes motion-fade-rise { from { opacity: 0; transform: translate3d(0, 14px, 0); } to { opacity: 1; transform: none; } }
@keyframes motion-image-in  { from { transform: scale(1.06); } to { transform: scale(1); } }

.ec-slide.on h1       { animation: motion-rise var(--motion-slow) var(--motion-ease) both; }
.ec-slide.on .ec-tag  { animation: motion-fade-rise var(--motion-base) var(--motion-ease) .05s both; }
.ec-slide.on p        { animation: motion-fade-rise var(--motion-base) var(--motion-ease) .18s both; }
.ec-slide.on .ec-cta  { animation: motion-fade-rise var(--motion-base) var(--motion-ease) .3s both; }
/* One slow, finite zoom-out on the slide image (plays once per slide, not a loop). */
.ec-slide.on img      { animation: motion-image-in 1.6s var(--motion-ease) both; }

/* ---------- 4. Sticky header: soft shadow once the page is scrolled ------ */
.site-header { transition: box-shadow var(--motion-base) var(--motion-ease), background-color var(--motion-base) ease; }
.site-header.is-scrolled { box-shadow: 0 8px 30px rgba(20, 50, 27, .10); }

/* ---------- 5. Buttons, links, forms: micro-interactions ----------------- */
.btn, .small-btn, .ec-cta, .tool, .chip, .view-all {
  transition-property: transform, box-shadow, background-color, color, border-color;
  transition-duration: var(--motion-fast);
  transition-timing-function: var(--motion-ease);
}
.btn:active, .small-btn:active, .tool:active, .chip:active { transform: scale(.97); }

/* Clear keyboard focus on everything clickable (WCAG 2.4.7). */
a:focus-visible, button:focus-visible, [role="button"]:focus-visible,
summary:focus-visible, .ec-dots i:focus-visible {
  outline: 2px solid var(--dnp-focus-ring);
  outline-offset: 3px;
  border-radius: 6px;
}
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 2px solid var(--dnp-focus-ring);
  outline-offset: 1px;
}

/* Fields: gentle focus glow + red shake-free error hint */
.field { transition: border-color var(--motion-fast) ease, box-shadow var(--motion-fast) ease; }
.field:focus { box-shadow: 0 0 0 4px rgba(23, 75, 37, .12); }
.field:user-invalid { border-color: #b91c1c; box-shadow: 0 0 0 3px rgba(185, 28, 28, .10); }

/* Busy / loading state for buttons. Add aria-busy="true" (or the class
   .is-loading) to a button while its request is running. */
.btn[disabled], .small-btn[disabled], button[aria-busy="true"] { opacity: .7; cursor: progress; }
@keyframes motion-spin { to { transform: rotate(360deg); } }
button[aria-busy="true"]::after, .btn.is-loading::after {
  content: "";
  width: 14px; height: 14px;
  margin-left: 8px;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  display: inline-block;
  animation: motion-spin .7s linear infinite;   /* only while busy */
}

/* Toast messages already exist (.toast); make the slide a little softer. */
.toast { transition-timing-function: var(--motion-ease); }

/* ---------- 6. Hover polish (mouse devices only) ------------------------- */
@media (hover: hover) {
  .ec-cats a img, .product-image img, .article > img { will-change: auto; }
  .ec-cats a:hover img { transform: scale(1.06); }
  .ec-cats a img { transition: transform .5s var(--motion-ease); }
}

/* ---------- 7. Reduced motion: switch everything off --------------------- */
@media (prefers-reduced-motion: reduce) {
  [data-motion="pending"], [data-motion="in"] { opacity: 1 !important; transform: none !important; transition: none !important; }
  .mw-i { transform: none !important; transition: none !important; }
  .ec-slide.on h1, .ec-slide.on .ec-tag, .ec-slide.on p, .ec-slide.on .ec-cta, .ec-slide.on img { animation: none !important; }
  button[aria-busy="true"]::after, .btn.is-loading::after { animation-duration: 2s; }  /* spinner stays, just slower */
  .btn:active, .small-btn:active, .tool:active, .chip:active { transform: none; }
}

/* ---------- 8. Layout-shift guard for images ----------------------------- */
/* Images now carry width/height attributes so the browser reserves space
   (prevents CLS). This zero-specificity rule keeps their displayed height
   automatic unless a class in style.css sets a height itself. */
:where(img[width][height]) { height: auto; }
