/* motion.css: the motion system of the Alevectis home page. Owner: creative developer.
   Every hidden starting state lives under html.motion. The head hook adds that class only without reduced
   motion, and removes it after 3 seconds if motion.js has not started. With no script, with reduced motion
   and in print, every element is in its resting state. Numbers: exceptional-web reference/motion.md. */

/* 1. Tokens, declared once ------------------------------------------------------------------------ */
:root {
  --dur-feedback: 120ms;
  --dur-state: 200ms;
  --dur-layout: 320ms;
  --dur-enter: 560ms;
  --dur-authored: 800ms;
  --ease-standard: cubic-bezier(.2, 0, 0, 1);
  --ease-decelerate: cubic-bezier(0, 0, .2, 1);
  --ease-accelerate: cubic-bezier(.3, 0, 1, .3);
  --ease-arrive: cubic-bezier(.16, 1, .3, 1);
  --motion-distance: 20px;
  --dir: 1;
  --mo-accent: #0D6868;
  --mo-spot: rgba(13, 104, 104, .11);
}
[dir="rtl"] { --dir: -1; }
[data-tone="dark"] { --mo-accent: #5FA9A6; --mo-spot: rgba(95, 169, 166, .18); }
@media (prefers-reduced-motion: reduce) {
  :root { --dur-layout: 1ms; --dur-enter: 1ms; --dur-authored: 1ms; --motion-distance: 0px; }
}

/* 2. Smooth scroll (Lenis) -------------------------------------------------------------------------- */
html.lenis, html.lenis body { height: auto; }
.lenis-smooth { scroll-behavior: auto !important; }
.lenis-smooth [data-lenis-prevent] { overscroll-behavior: contain; }
.lenis-stopped { overflow: clip; }

/* 3. Waiting states: only under html.motion, released by motion.js with .mo-live --------------------- */
html.motion [data-reveal]:not(.mo-live),
html.motion [data-stagger] > :not(.mo-live) { opacity: 0; }

/* 4. Hero on load: words rise out of a mask, then the sub-line and the buttons (no library needed) ---- */
@keyframes mo-rise { from { transform: translate3d(0, 135%, 0); } }
@keyframes mo-enter { from { opacity: 0; transform: translate3d(0, var(--motion-distance), 0); } }
.mo-w, .mo-wi { display: inline-block; }
html.motion .mo-w { clip-path: inset(-.3em -.3em -.14em -.3em); }
html.motion .mo-wi {
  animation: mo-rise var(--dur-authored) var(--ease-arrive) backwards;
  animation-delay: calc(var(--i, 0) * 55ms + 60ms);
}
html.motion .mo-load {
  animation: mo-enter var(--dur-enter) var(--ease-arrive) backwards;
  animation-delay: var(--d, 0ms);
}
/* The sub-line is never invisible: painted at first paint (it is the largest paint), it settles into place. */
@keyframes mo-settle { from { opacity: .4; transform: translate3d(0, var(--motion-distance), 0); } }
html.motion .mo-load.mo-settle { animation-name: mo-settle; }

/* Statement words stay inline boxes, so the heading keeps its painted lines; opacity still applies to them. */
.mo-sw { display: inline !important; }

/* 5. Hero visual: the svg is the rest; the canvas plays over it; both fill the panel ----------------- */
.mo-hv { position: absolute; inset: 0; border-radius: inherit; overflow: hidden; color: inherit; }
.mo-hv-rest { display: block; width: 100%; height: 100%; overflow: visible; transition: opacity var(--dur-enter) var(--ease-standard); }
.mo-hv-rest .mo-acc-s, .mo-tool .mo-acc-s { stroke: var(--mo-accent); }
.mo-acc { fill: var(--mo-accent); }
.mo-hv-canvas {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0; pointer-events: none;
}
html.motion .mo-hv:not(.is-static) .mo-hv-rest { opacity: 0; }
html.motion .mo-hv.is-live .mo-hv-canvas { opacity: 1; }
html:not(.motion) .mo-hv-canvas { display: none; }
.mo-hv-mark { fill: var(--mo-mark, #0A5252); }
/* The pause control: a quiet round icon button in the panel's corner. Its name is its aria-label. */
.mo-hv-pause {
  /* the visual's corner on the hero ground, above the part that crosses into the navy band */
  position: absolute; inset-block-end: calc(var(--visual-cross, 0px) + 16px); inset-inline-end: 16px;
  display: grid; place-items: center;
  inline-size: 44px; block-size: 44px; padding: 0;
  color: inherit; background-color: rgba(255, 255, 255, .5);
  border: 1px solid rgba(22, 32, 45, .2); border-radius: 50%;
  cursor: pointer;
  transition: background-color var(--dur-state) var(--ease-standard), border-color var(--dur-state) var(--ease-standard);
}
.mo-hv-pause:hover { background-color: #fff; border-color: rgba(22, 32, 45, .45); }
.mo-hv-pause:active { background-color: rgba(255, 255, 255, .7); transition-duration: var(--dur-feedback); }
.mo-hv-pause:focus-visible { outline: 3px solid var(--focus, currentColor); outline-offset: 2px; background-color: #fff; }
.mo-hv-pause[hidden] { display: none; }
.mo-hv-icon { display: block; fill: currentColor; }
.mo-hv-pause[data-state="paused"] .mo-hv-icon-pause,
.mo-hv-pause:not([data-state="paused"]) .mo-hv-icon-play { display: none; }

/* 6. Service cards: a spotlight that follows the pointer (the lift is GSAP, in motion.js) ----------- */
html.js [data-card] { position: relative; isolation: isolate; }
.mo-spot {
  position: absolute; inset: 0; z-index: -1;
  border-radius: inherit; pointer-events: none; opacity: 0;
  background: radial-gradient(380px circle at var(--mx, 50%) var(--my, 50%), var(--mo-spot), transparent 65%);
  transition: opacity var(--dur-state) var(--ease-standard);
}
@media (hover: hover) and (pointer: fine) {
  .mo-card:hover .mo-spot, .mo-card:focus-within .mo-spot { opacity: 1; }
}

.mo-ill { display: block; overflow: visible; }
.mo-ill .mo-d {
  stroke-dasharray: 1 2; stroke-dashoffset: 0;
  transition: stroke-dashoffset var(--dur-authored) var(--ease-arrive);
  transition-delay: calc(var(--i, 0) * 110ms + 120ms);
}
.mo-ill .mo-f {
  transform-box: fill-box; transform-origin: 50% 50%;
  transition: opacity var(--dur-enter) var(--ease-arrive), transform var(--dur-enter) var(--ease-arrive);
  transition-delay: calc(var(--i, 0) * 110ms + 360ms);
}
html.motion .mo-ill:not(.is-drawn) .mo-d { stroke-dashoffset: 1.05; }
html.motion .mo-ill:not(.is-drawn) .mo-f { opacity: 0; transform: scale(.4); }
.mo-h-left, .mo-h-right, .mo-h-down, .mo-h-up, .mo-h-grow {
  transform-box: fill-box; transform-origin: 50% 100%;
  transition: transform var(--dur-enter) var(--ease-standard);
}
@media (hover: hover) {
  [data-card]:hover .mo-h-left, [data-card]:focus-within .mo-h-left { transform: translateX(-12px); }
  [data-card]:hover .mo-h-right, [data-card]:focus-within .mo-h-right { transform: translateX(12px); }
  [data-card]:hover .mo-h-down, [data-card]:focus-within .mo-h-down { transform: translateY(3px); }
  [data-card]:hover .mo-h-up, [data-card]:focus-within .mo-h-up { transform: translateY(-4px); }
  [data-card]:hover .mo-h-grow, [data-card]:focus-within .mo-h-grow { transform: scale(1.2); }
}

/* 7. Process: the rail fills the stage line with scroll and lights each stage's number -------------- */
.mo-process { position: relative; }
.mo-rail { position: absolute; z-index: 0; margin: 0; padding: 0; list-style: none; pointer-events: none; color: inherit; }
.mo-rail[hidden] { display: none; }
.mo-rail-track, .mo-rail-fill { position: absolute; inset: 0; }
.mo-rail-track { background: currentColor; opacity: .18; }
.mo-rail.has-marks .mo-rail-track, .mo-rail.has-marks .mo-rail-node { display: none; }
.mo-rail-fill { background: var(--mo-accent); transform: scaleY(0); transform-origin: 50% 0; }
.mo-rail[data-axis="x"] .mo-rail-fill { transform: scaleX(0); transform-origin: 100% 50%; }
[dir="ltr"] .mo-rail[data-axis="x"] .mo-rail-fill { transform-origin: 0 50%; }
.mo-rail-node {
  position: absolute; width: 10px; height: 10px; margin: -4px 0 0 -4px;
  background: currentColor; opacity: .4;
  transition: opacity var(--dur-state) var(--ease-standard), transform var(--dur-state) var(--ease-standard);
}
.mo-rail-node.is-lit { background: var(--mo-accent); opacity: 1; transform: scale(1.3); }
/* The head points the way the reader travels: down the vertical rail at every width; along a horizontal rail
   in the reading direction (left under rtl, right under ltr). */
.mo-rail-head {
  position: absolute; left: 0; top: 0; width: 18px; height: 16px; margin: -8px 0 0 -8px;
  background: var(--mo-accent); clip-path: polygon(0 0, 100% 0, 50% 100%);
}
.mo-rail[data-axis="x"] .mo-rail-head { width: 16px; height: 18px; margin: -9px 0 0 -8px; clip-path: polygon(0 50%, 100% 0, 100% 100%); }
[dir="ltr"] .mo-rail[data-axis="x"] .mo-rail-head { clip-path: polygon(100% 50%, 0 0, 0 100%); }
.mo-stage-mark {
  position: relative; z-index: 1;
  transition: background-color var(--dur-state) var(--ease-standard), border-color var(--dur-state) var(--ease-standard), color var(--dur-state) var(--ease-standard);
}
/* Progress is carried by the line and the numbers alone: stage text stays at full strength at every moment. */
[data-stage].is-lit > .mo-stage-mark { background-color: var(--mo-accent); border-color: var(--mo-accent); color: #fff; }

/* 8. Tool previews: the CV lines run in from the right, the contact sheet fills ----------------------- */
.mo-tool { display: block; overflow: visible; }
.mo-tool .mo-x {
  transform-box: fill-box; transform-origin: 100% 50%;
  transition: transform var(--dur-enter) var(--ease-arrive);
  transition-delay: calc(var(--i, 0) * 45ms + 100ms);
}
[dir="ltr"] .mo-tool .mo-x { transform-origin: 0 50%; }
.mo-tool .mo-pop {
  transform-box: fill-box; transform-origin: 50% 50%;
  transition: opacity var(--dur-enter) var(--ease-arrive), transform var(--dur-enter) var(--ease-arrive);
  transition-delay: calc(var(--i, 0) * 45ms + 100ms);
}
html.motion .mo-tool:not(.is-built) .mo-x { transform: scaleX(0); }
html.motion .mo-tool:not(.is-built) .mo-pop { opacity: 0; transform: scale(.6); }

/* 9. Partners: the portrait takes its full colour on hover ----------------------------------------- */
@media (hover: hover) {
  [data-partner] img, [data-proof="people"] li img {
    filter: grayscale(.45);
    transition: filter var(--dur-state) var(--ease-standard);
  }
  [data-partner]:hover img, [data-partner]:focus-within img,
  [data-proof="people"] li:hover img, [data-proof="people"] li:focus-within img { filter: none; }
}

/* 10. Header tone: motion.js sets data-header-tone="dark" while a dark section runs under the header.
   The roles are the navy ground's (layout.css .ground-navy); the colours the header hard-codes are
   answered here, including the phone menu panel, which stays white. */
[data-header] {
  transition: background-color var(--dur-layout) var(--ease-standard), border-color var(--dur-layout) var(--ease-standard), color var(--dur-layout) var(--ease-standard);
}
[data-header] .nav__list a {
  transition: background-color var(--dur-state) var(--ease-standard), color var(--dur-layout) var(--ease-standard);
}
[data-header] .logo-word, [data-header] .logo-mark, [data-header] .head__phone svg { transition: fill var(--dur-layout) var(--ease-standard), stroke var(--dur-layout) var(--ease-standard); }
[data-header] .head__phone, [data-header] .menu-btn { transition: color var(--dur-layout) var(--ease-standard), border-color var(--dur-layout) var(--ease-standard), background-color var(--dur-state) var(--ease-standard); }
[data-header][data-header-tone="dark"] {
  --ground: var(--navy-900, #16202D);
  --text: var(--white, #fff);
  --text-2: var(--steel-300, #B4BCC4);
  --rule: var(--steel-700, #334051);
  --control-edge: var(--teal-400, #5FA9A6);
  --mark: var(--teal-400, #5FA9A6);
  --link: var(--white, #fff);
  --focus: var(--teal-300, #7CC0BC);
  --action-rim: var(--teal-400, #5FA9A6);
  --quiet-hover: var(--steel-700, #334051);
  --logo-word: var(--white, #fff);
  --logo-mark: var(--teal-400, #5FA9A6);
}
[data-header][data-header-tone="dark"] .head__phone svg { stroke: var(--teal-400, #5FA9A6); }
[data-header][data-header-tone="dark"] .menu-btn:not([aria-expanded="true"]) { color: var(--white, #fff); border-color: var(--teal-400, #5FA9A6); }
@media (min-width: 1100px) {
  [data-header][data-header-tone="dark"] .nav__list a:hover { background-color: var(--steel-700, #334051); }
  [data-header][data-header-tone="dark"] .nav__list a[aria-current="page"] { box-shadow: inset 0 -3px 0 var(--teal-400, #5FA9A6); }
}
@media (max-width: 1099px) {
  [data-header][data-header-tone="dark"] .nav {
    --text: var(--navy-900, #16202D);
    --link: var(--navy-900, #16202D);
    --focus: var(--navy-900, #16202D);
    --action-rim: var(--teal-700, #0D6868);
  }
}

/* 12. Shared capabilities for every page (site-system.md). motion.js adds the mo-* classes only where the
   data attributes are present; with no script or reduced motion each shows its resting state. ----------- */

/* Page transitions: header persists, the clicked label becomes the next H1, the page itself crossfades. */
@keyframes mo-vt-out { to { opacity: 0; transform: translate3d(0, -12px, 0); } }
@keyframes mo-vt-in { from { opacity: 0; transform: translate3d(0, 16px, 0); } }
@supports (view-transition-name: none) {
  @view-transition { navigation: auto; }
  [data-header] { view-transition-name: site-header; }
  ::view-transition-old(root) { animation: mo-vt-out calc(var(--dur-enter) * .7) var(--ease-accelerate) both; }
  ::view-transition-new(root) { animation: mo-vt-in var(--dur-enter) var(--ease-arrive) both; }
  ::view-transition-group(page-title) { animation-duration: var(--dur-authored); animation-timing-function: var(--ease-arrive); }
  ::view-transition-old(page-title), ::view-transition-new(page-title) { animation-duration: var(--dur-authored); height: 100%; }
  @media (prefers-reduced-motion: reduce) {
    @view-transition { navigation: none; }
  }
}

/* data-draw */
.mo-draws .mo-d {
  stroke-dasharray: 1 2; stroke-dashoffset: 0;
  transition: stroke-dashoffset var(--dur-authored) var(--ease-arrive);
  transition-delay: calc(var(--i, 0) * 110ms);
}
html.motion .mo-draws:not(.is-drawn) .mo-d { stroke-dashoffset: 1.05; }
.mo-draws.mo-draw-set .mo-d { transition: none; }
/* In a data-diagram, filled marks (paths with no data-draw) wait for their lines and fade in as the lines finish,
   instead of standing alone before anything is drawn. Reduced motion, no script and the rest state show them at once. */
html.motion svg[data-diagram].mo-draws:not(.is-drawn) path:not([data-draw]) { opacity: 0; }
html.motion svg[data-diagram].mo-draws.is-drawn path:not([data-draw]) { transition: opacity var(--dur-enter) var(--ease-arrive) 520ms; }
svg[data-diagram].mo-draws.mo-draw-set path:not([data-draw]) { transition: none; }
/* A before-and-after diagram opens on its before, never on an empty card: the ghost group (lines and marks) and every
   order-0 line (what exists before the change) are painted from the first frame. Only the after draws, while the
   before fades to its ghost. */
html.motion svg[data-diagram].mo-draws [data-draw="0"] { stroke-dashoffset: 0; transition: none; }
html.motion svg[data-diagram].mo-draws:not(.is-drawn) [data-ghost] path:not([data-draw]) { opacity: 1; transition: none; }
/* data-diagram / data-part / data-lights: the lit part stays, the others quiet */
.mo-diagram [data-part] { transition: opacity var(--dur-state) var(--ease-standard); }
.mo-diagram.is-lighting [data-part]:not(.is-lit) { opacity: .4; }

/* data-operable: with no script the criteria read as a list; the sentence settles in when it changes */
html:not(.js) [data-operable] input[type="checkbox"],
html:not(.js) [data-operable] input[type="radio"] { display: none; }
@keyframes mo-said { from { opacity: 0; transform: translate3d(0, 6px, 0); } }
html.motion [data-operable-status].mo-said { animation: mo-said var(--dur-layout) var(--ease-arrive); }

/* data-preview: one figure swaps between the rows' drawings from 1024px up; inline drawings below */
[data-preview-target] { position: relative; }
html:not(.js) [data-preview-target] { display: none; }
@media (max-width: 1023.98px) { [data-preview-target] { display: none; } }
@media (min-width: 1024px) { .mo-preview-live [data-preview-index] [data-preview-art] { display: none; } }
.mo-preview-layer {
  display: grid; place-items: center;
  opacity: 0; transform: scale(.96);
  transition: opacity var(--dur-layout) var(--ease-standard), transform var(--dur-layout) var(--ease-arrive);
}
.mo-preview-layer + .mo-preview-layer { position: absolute; inset: 0; }
.mo-preview-layer.is-shown { opacity: 1; transform: none; }

/* data-sequence: a layer waits only while its step is below the line */
.mo-seq-live [data-layer] { transition: opacity var(--dur-enter) var(--ease-arrive), transform var(--dur-enter) var(--ease-arrive), visibility 0s linear 0s; }
/* From first paint until motion.js places the sequence (a moment, well under 300ms), its layers wait: a figure already in
   the first screen never paints full and then empties. motion.js then makes it live (.mo-seq-live) or leaves it at
   rest, full (.mo-seq-rest). With no script, reduced motion or the failsafe, html.motion is absent and every layer shows.
   A waiting layer is visibility:hidden as well as transparent, so its words are out of the page until they show. A
   layer arrives with a fade; a layer that goes back (the reader scrolls up) hides at once, so no word is ever left
   transparent but present. */
html.motion [data-sequence]:not(.mo-seq-live):not(.mo-seq-rest) [data-layer] { opacity: 0; visibility: hidden; }
html.motion .mo-seq-live [data-layer]:not(.is-on) {
  opacity: 0; transform: translate3d(0, 10px, 0); visibility: hidden;
  transition: none;
}
/* data-sequence-from="above": a layer drops in from above (something placed into a container) */
html.motion .mo-seq-live[data-sequence-from="above"] [data-layer]:not(.is-on) { transform: translate3d(0, -18px, 0); }

/* data-ghost: the "before" of a before-and-after diagram. It rests as a faint ghost behind the after (no script,
   reduced motion, print); on load it draws at full strength first, then fades as the after draws in. */
[data-ghost] { opacity: .28; }
html.motion .mo-draws:not(.is-drawn) [data-ghost] { opacity: 1; }
html.motion .mo-draws.is-drawn [data-ghost] { transition: opacity 520ms var(--ease-standard) 420ms; }
.mo-draws.mo-draw-set [data-ghost] { transition: none; }

/* data-keep: a choice keeps layers 1..n; the rest quiet to 25% (a layer still waiting for its step stays hidden) */
:where([data-sequence]) [data-layer] { transition: opacity var(--dur-state) var(--ease-standard); }
[data-sequence] [data-layer].is-dropped { opacity: .25; }

/* data-band: the buttons stagger in once; the classes are removed when they have landed */
html.motion [data-band].mo-band-wait :is(a, button) {
  opacity: 0; transform: translate3d(0, var(--motion-distance), 0);
  transition: opacity var(--dur-enter) var(--ease-arrive), transform var(--dur-enter) var(--ease-arrive);
  transition-delay: calc(var(--band-i, 0) * 80ms);
}
html.motion [data-band].mo-band-wait.is-in :is(a, button) { opacity: 1; transform: none; }

@media print {
  .mo-draws .mo-d { stroke-dashoffset: 0 !important; }
  .mo-diagram [data-part], .mo-seq-live [data-layer], [data-band] a, [data-band] button { opacity: 1 !important; transform: none !important; }
  [data-preview-target] { display: none !important; }
  .mo-preview-live [data-preview-index] [data-preview-art] { display: block !important; }
}

/* 11. Print: the resting state, whatever the script did --------------------------------------------- */
@media print {
  html.motion [data-reveal], html.motion [data-stagger] > *, .mo-wi, .mo-load, .mo-line, .mo-sw, [data-stage] {
    opacity: 1 !important; transform: none !important; animation: none !important;
  }
  html.motion .mo-ill .mo-d { stroke-dashoffset: 0 !important; }
  html.motion .mo-ill .mo-f, html.motion .mo-tool .mo-pop { opacity: 1 !important; transform: none !important; }
  html.motion .mo-tool .mo-x { transform: none !important; }
  html.motion .mo-hv-rest { opacity: 1 !important; }
  .mo-hv-canvas, .mo-hv-pause, .mo-rail, .mo-spot { display: none !important; }
}
