/* =====================================================================================================================
   MOTION, October 2026. Loaded last on every page, so it settles every older motion rule in one place.

   The register is restrained: things settle into place. Nothing bounces, nothing slides in from off-screen, nothing
   loops, and nothing is slow enough to wait for. Only transform and opacity ever animate (colour and background
   shifts on hover are paint-only and allowed); nothing that changes layout (width, height, top, left, padding,
   grid rows) is ever transitioned.

     Hover and press feedback ........ 150ms, ease-out
     Clickable photo and clip tiles .. 200ms, ease-out (scale 1.03)
     Hero, once on first paint ....... 400ms, ease-out, 12px up
     Section reveal on scroll ........ 400ms, ease-out, 12px up (motion.js picks the blocks)

   With "reduce motion" switched on, the block at the end of this file removes every transition and animation.
   No colour value, font size or layout here: only timing, and the states that motion.js toggles.
   ===================================================================================================================== */

:root {
  --m-fast: 150ms;
  --m-tile: 200ms;
  --m-settle: 400ms;
  --m-shift: 12px;
  --m-ease-out: cubic-bezier(.22, 1, .36, 1); /* the site's existing --ease: a gentle ease-out, no overshoot */
}

/* ---- Removed: the old business-switch wipe and the slow whole-page colour fade. The switch is immediate. -------- */
.mode-wipe { display: none; }
body { transition: none; }

/* ---- Removed: transitions on layout properties ------------------------------------------------------------------ */
/* The header used to animate its height on scroll; the price groups their row height. Both now change at once. */
.site-header { transition: background-color var(--m-fast) ease-out, border-color var(--m-fast) ease-out, color var(--m-fast) ease-out; }
.pricing.is-enhanced .price-panel,
body[data-mode] .pricing.is-enhanced .price-panel,
body[data-mode] .pricing.is-enhanced .price-group:not(.is-open) .price-panel,
.service-panel-body { transition: none; }
/* Before/after: the line follows the finger or pointer exactly, with no lag (it used to ease its `left`). */
.ba-slider .ba-after,
.ba-handle { transition: none; }
/* Landing pages: a parallax transition with nothing driving it. */
.landing-hero-media img { transition: none; }

/* ---- 1. The hero settles in once, on first paint ----------------------------------------------------------------- */
/* A CSS animation, so it starts with the first paint and needs no script: nothing flashes, and if motion.js never
   loads the hero still ends in its final state. It plays once (iteration count 1). motion.js adds .hero-settled
   afterwards, so the hero does not replay when the visitor switches business. */
@keyframes m-settle {
  from { opacity: 0; transform: translateY(var(--m-shift)); }
  to { opacity: 1; transform: none; }
}
html:not(.hero-settled) .hero .hero-text > *,
html:not(.hero-settled) .landing-hero-copy > * { animation: m-settle var(--m-settle) var(--m-ease-out) both; }
/* The older entrance hid the hero until a script ran; neutralise it and its transitions. */
html.motion-ready:not(.page-ready) .hero .eyebrow,
html.motion-ready:not(.page-ready) .hero h1,
html.motion-ready:not(.page-ready) .hero-copy,
html.motion-ready:not(.page-ready) .hero-actions,
html.motion-ready:not(.page-ready) .hero-status,
html.motion-ready:not(.page-ready) .scroll-cue,
html.motion-ready:not(.page-ready) .landing-hero-copy > * { opacity: 1; transform: none; }
.hero .eyebrow,
.hero h1,
.hero-copy,
.hero-actions,
.hero-status,
.scroll-cue,
.hero-inner,
.landing-hero-copy > *,
.landing-hero-copy h1,
.landing-hero-copy > p:not(.kicker):not(.breadcrumbs),
.landing-hero-copy .button:not(:hover) { transition-delay: 0ms; }
.hero .eyebrow, .hero h1, .hero-copy, .hero-actions, .hero-status, .scroll-cue, .hero-inner,
.landing-hero-copy > *:not(.button) { transition: none; }

/* ---- 2. Section reveal (motion.js adds .reveal-pending to blocks below the fold, then removes it) -------------- */
[data-reveal-armed] { transition: opacity var(--m-settle) var(--m-ease-out), transform var(--m-settle) var(--m-ease-out); }
.reveal-pending { opacity: 0; transform: translateY(var(--m-shift)); }

/* ---- 3. Hover and press feedback: 150ms ------------------------------------------------------------------------- */
a { transition: color var(--m-fast) ease-out, opacity var(--m-fast) ease-out; }
.main-nav a { transition: color var(--m-fast) ease-out; }
.main-nav a::after { transition: transform var(--m-fast) ease-out; }
.hero-link,
body[data-mode] .contact .direct-links a,
.contact .direct-links a { transition: opacity var(--m-fast) ease-out, background-color var(--m-fast) ease-out; }

/* Buttons: a background shift (the colours were already set on :hover) plus a 1px lift. The old fill that swept in
   from the left edge is gone. */
.button,
body[data-mode] .button,
.landing-page .button,
.review-page .button {
  transition: background-color var(--m-fast) ease-out, color var(--m-fast) ease-out, border-color var(--m-fast) ease-out, transform var(--m-fast) ease-out;
}
.button::after { display: none; transition: none; }
.button:hover,
body[data-mode] .button:hover { transform: translateY(-1px); }
.button:active,
body[data-mode] .button:active { transform: translateY(0); }

.price-jump a,
body[data-mode] .price-jump a,
.carousel-button,
body[data-mode] .carousel-button,
.dialog-nav button,
.dialog-close,
.board-text-link,
.price-toggle,
.comparison-choices button,
.review-score,
.mobile-actions a {
  transition: background-color var(--m-fast) ease-out, color var(--m-fast) ease-out, border-color var(--m-fast) ease-out, opacity var(--m-fast) ease-out, transform var(--m-fast) ease-out;
}
.price-toggle-mark::before,
.price-toggle-mark::after,
body[data-mode] .price-toggle-mark::before,
body[data-mode] .price-toggle-mark::after { transition: transform var(--m-fast) ease-out; }

/* The business switch is the most important control on the site: the selected state changes instantly, in both
   buttons at once. Only the hover tint on the button not yet chosen eases in. */
.business-switch button { transition: color var(--m-fast) ease-out, background-color var(--m-fast) ease-out; }
.business-switch button[aria-selected="true"],
.business-switch button[aria-selected="false"]:not(:hover) { transition: none; }

/* Clickable photo and clip tiles: a slight zoom inside the frame. The dimming filter is gone (filters are not
   transform or opacity). Tiles that do nothing get no hover at all. */
.work-video,
.work-open img,
.gallery-item img,
body[data-mode] .gallery-item img,
.board-open img,
.instagram-grid img,
.ba-item img { transition: transform var(--m-tile) var(--m-ease-out); }
.work-play:hover .work-video, .work-play:focus-visible .work-video,
.work-open:hover img, .work-open:focus-visible img,
.gallery-item:hover img, .gallery-item:focus-visible img,
body[data-mode] .gallery-item:hover img, body[data-mode] .gallery-item:focus-visible img,
body[data-mode="auto"] .gallery-item:hover img, body[data-mode="auto"] .gallery-item:focus-visible img,
.instagram-grid a[href]:hover img { transform: scale(1.03); filter: none; }
.gallery-item::after,
.work-mark,
.ba-knob,
.ba-tag { transition: opacity var(--m-fast) ease-out, transform var(--m-fast) ease-out; }

/* Controls that had no hover response at all. Text-style links and questions dim slightly, the same .75 the hero
   link already used; boxed controls take the existing faint scrim behind them; the review page's two option cards
   lift 2px. Existing colour tokens only. */
.brand,
.text-link,
.board-text-link,
.review-card footer a,
.hero-phone,
.breadcrumbs a,
.landing-header a:not(.button),
.landing-footer-links a,
.landing-page footer a:not(.button),
.site-footer a,
.review-header a,
.review-page footer a,
.form-note a,
.privacy-content a:not(.button),
.landing-brands,
summary { transition: opacity var(--m-fast) ease-out; }
.brand:hover,
.text-link:hover,
.board-text-link:hover,
.review-card footer a:hover,
.hero-phone:hover,
.breadcrumbs a:hover,
.landing-header a:not(.button):hover,
.landing-footer-links a:hover,
.landing-page footer a:not(.button):hover,
.site-footer a:hover,
.review-header a:hover,
.review-page footer a:hover,
.form-note a:hover,
.privacy-content a:not(.button):hover,
.landing-brands:hover,
summary:hover { opacity: .75; }
.business-switch button[aria-selected="false"]:hover,
.price-toggle:hover,
.comparison-choices button[aria-pressed="false"]:hover { background-color: var(--scrim-08); }
.feedback-card { transition: transform var(--m-fast) ease-out, border-color var(--m-fast) ease-out; }
.feedback-card:hover { transform: translateY(-2px); }

/* ---- Focus: one visible ring everywhere, in the ink colour of whatever it sits on ---------------------------------- */
:root { --focus-ring: var(--text-primary); }
body[data-mode="auto"] #reviews,
body[data-mode="home"] #work,
body[data-mode="home"] #contact,
.mobile-actions,
.landing-cta,
.gallery-dialog { --focus-ring: var(--text-on-dark); }
:root body :focus-visible,
:root body[data-mode] :focus-visible,
:root body[data-mode="auto"] :focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 3px; }
/* Inputs and the map frame had no ring at all. */
:root body .enquiry-form :is(input, textarea, select):focus-visible,
:root body iframe:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 3px; }

/* ---- 4. Before/after sliders: say "drag me" ---------------------------------------------------------------------- */
.ba-slider { cursor: ew-resize; touch-action: pan-y; }
.ba-slider[data-dragging] { cursor: ew-resize; }

/* ---- Bug fix (not motion): the car wash's bottom bar cut the phone number to "087 707 0..." on 360px phones,
   because each of its three buttons kept 14px of side padding. 8px lets the number fit; nothing else changes. */
@media (max-width: 400px) {
  body[data-mode="auto"] .mobile-actions a { padding-left: 8px; padding-right: 8px; }
}

/* ---- 5. Reduce motion: everything is simply in its final state ------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition: none !important;
    animation: none !important;
    scroll-behavior: auto !important;
  }
  .reveal-pending,
  .hero .hero-text > *,
  .landing-hero-copy > * { opacity: 1 !important; transform: none !important; }
}

/* ---- 6. October 2026 motion pass: shared with the main page (theme.css has the same rules) ------------------- */
:root { --m-spring: cubic-bezier(.34, 1.36, .64, 1); }
[data-stagger] > .reveal-item { transition: opacity .7s var(--m-ease-out), transform .8s var(--m-ease-out); transition-delay: calc(min(var(--i, 0), 7) * 70ms); }
[data-stagger] > .reveal-item.reveal-pending { opacity: 0; transform: translateY(26px) scale(.98); }
@media (prefers-reduced-motion: no-preference) {
  .button:hover, body[data-mode] .button:hover { transform: translateY(-2px); }
  .button:active, body[data-mode] .button:active, .mobile-actions a:active { transform: scale(.96); transition-duration: .08s; }
  .arrow { display: inline-block; transition: transform .25s var(--m-ease-out); }
  a:hover .arrow { transform: translate(2px, -2px); }
}
/* Decorative arrows are left off on phones, where some systems draw them as emoji. */
.arrow { font-style: normal; }
@media (max-width: 760px) { .arrow { display: none !important; } }
