/* ═══════════════════════════════════════════════════════════════════
   motion.css — sections arriving on scroll

   Pairs with the reveal engine at the top of webroot/js/scripts.js.
   Linked from templates/layout/default.php. Restored from ed92c8e
   ("Add the missing motion.css", reverted in 15dfd03), reveal part only.
   The old .press/.lift rules are left out: button press and hover now
   live with the buttons themselves (home.css, theme.css).

   Opt-in by class, already in the templates:
     .reveal           sections and cards
     .reveal-heading   headings (scroll-driven browsers only)

   SAFETY RULE: the hidden state never lives on the element's own class.
   It lives under .reveal-armed, which only scripts.js adds, or inside the
   @supports block, where the browser drives the animation from scroll
   position and cannot get stuck. No JS, a failed observer, an old browser,
   or reduced motion, and every element renders normally.

   The rise uses the `translate` property, not `transform`. A finished
   scroll-driven animation keeps applying its end state, and if that were a
   transform it would override hover transforms on the same element - the
   service cards (.service-card.reveal) would stop lifting on hover.
   ═══════════════════════════════════════════════════════════════════ */


/* ── Scroll container fix ────────────────────────────────────────────
   home.css, about.css, contact.css and login.css all set
   `html, body { overflow-x: hidden }`. On <body> that quietly makes it a
   scroll container of its own - one that never scrolls, because the page
   scrolls on the root. Scroll-driven animations attach to the NEAREST
   scroll container, so every view() timeline below was bound to that
   motionless body and never advanced: no reveal, anywhere.

   `clip` stops sideways overflow exactly like `hidden` but does not create
   a scroll container, so the timelines reach the real scroller. `html body`
   outranks those page stylesheets, which load after this file. */
html body {
    overflow-x: clip;
}


/* ── JS path (browsers without animation-timeline) ───────────────────
   scripts.js arms elements below the fold and disarms them as they
   arrive; this transition animates that class change. A 32px rise - large
   enough to notice, still calm. */
.reveal {
    transition: opacity 700ms var(--nb-reveal-ease),
                translate 700ms var(--nb-reveal-ease);
}

.reveal.reveal-armed {
    opacity: 0;
    translate: 0 32px;
    will-change: opacity, translate;
}


/* ── Scroll-driven path ──────────────────────────────────────────────
   Progress is a function of scroll position: it scrubs both ways, survives
   a jump to the middle of the page, and costs no main-thread work.
   scripts.js detects support via CSS.supports() and stands down, so the
   two paths never fight. */
@supports (animation-timeline: view()) {
    .reveal,
    .reveal-heading {
        animation: nb-reveal-in linear both;
        animation-timeline: view();
        /* A fixed distance, not a percentage: the rise runs while a section's
           top edge travels from the bottom of the screen to the middle, where
           the eye is. (A percentage scales with section height - the contact
           form container is one tall .reveal and would stay half-faded while
           someone fills it in. The earlier 5%-22% range finished unnoticed
           near the bottom edge.) */
        animation-range: cover 0px cover 50vh;
    }

    /* The JS path has stood down, so an armed class must not hide anything. */
    .reveal.reveal-armed {
        opacity: 1;
        translate: none;
        transition: none;
    }
}

@keyframes nb-reveal-in {
    from { opacity: 0; translate: 0 32px; }
    to   { opacity: 1; translate: none; }
}


/* ── Reduced motion ──────────────────────────────────────────────────
   Switched to fully VISIBLE, not merely un-animated. "Reduce motion" must
   never mean "reduce content". */
@media (prefers-reduced-motion: reduce) {
    .reveal,
    .reveal.reveal-armed,
    .reveal-heading {
        opacity: 1 !important;
        translate: none !important;
        transition: none !important;
        animation: none !important;
    }
}
