/* INOVASYS motion layer — shared by inovasys.ma, inovasys.io and inovasys.ai (Docs/11).
   Source of truth: /motion/. Copied into each site by motion/sync.sh; edit here, not in the copies.
   Everything is gated by html.mo, which motion.js adds only when JS runs and the visitor has not
   asked for reduced motion: without it, every element is shown in its final state. */

:root {
  --mo-ease: cubic-bezier(.16, 1, .3, 1);     /* long, soft settle: reveals, line draw */
  --mo-ease-io: cubic-bezier(.65, 0, .35, 1); /* symmetric: travelling pulse, progress rails */
  --mo-reveal: 900ms;
  --mo-shift: 18px;
  --mo-blur: 5px;
  --mo-flow: var(--flow, #1FA8E0);
}

/* ── 1. Hero intro: lines come into focus, one after the other ─────────── */
.mo [data-intro] { animation: mo-focus 1000ms var(--mo-ease) both; animation-delay: calc(var(--d, 0) * 110ms + 80ms); }
@keyframes mo-focus { from { opacity: 0; transform: translateY(var(--mo-shift)); filter: blur(var(--mo-blur)); } to { opacity: 1; transform: none; filter: none; } }

/* ── 2. Reveal on scroll (single element, or children in sequence) ──────── */
.mo [data-reveal]:not(.is-done),
.mo [data-stagger]:not(.is-done) > * {
  transition: opacity var(--mo-reveal) var(--mo-ease), transform var(--mo-reveal) var(--mo-ease), filter var(--mo-reveal) var(--mo-ease);
  transition-delay: calc(var(--i, 0) * 90ms + var(--d, 0) * 80ms);
}
.mo [data-reveal]:not(.is-in),
.mo [data-stagger]:not(.is-in) > * { opacity: 0; transform: translateY(var(--mo-shift)); filter: blur(var(--mo-blur)); }
.mo [data-reveal="fade"]:not(.is-in) { transform: none; filter: none; }
.mo [data-reveal="scale"]:not(.is-in) { transform: scale(.96); filter: none; }

/* ── 3. Text that fills in as it scrolls (wrap the words in an inline span) ── */
[data-fill] > span {
  --p: 1;
  color: transparent;
  background-image: linear-gradient(var(--fill-on, var(--ink, #0B1C2C)), var(--fill-on, var(--ink, #0B1C2C))), linear-gradient(var(--fill-off, rgba(127,127,127,.35)), var(--fill-off, rgba(127,127,127,.35)));
  background-repeat: no-repeat;
  background-size: calc(var(--p) * 100%) 100%, 100% 100%;
  -webkit-background-clip: text; background-clip: text;
}
html:not(.mo) [data-fill] > span { color: inherit; background: none; }

/* ── 4. Operational line: track, drawn line, nodes that switch on, pulse ── */
.flow-track { fill: none; stroke: currentColor; stroke-opacity: .16; stroke-width: 2; stroke-dasharray: 2 7; stroke-linecap: round; }
.flow-path { fill: none; stroke: var(--mo-flow); stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; }
.flow-glow { fill: none; stroke: var(--mo-flow); stroke-width: 10; stroke-opacity: .18; stroke-linecap: round; stroke-linejoin: round; filter: blur(4px); }
.flow-pulse { fill: #FFFFFF; stroke: var(--mo-flow); stroke-width: 3; opacity: 0; transition: opacity 300ms; }
[data-flow].is-live .flow-pulse { opacity: 1; }

/* SVG nodes: <g class="flow-node" data-at=".4"><circle class="ring" r="11"/><circle class="dot" r="6"/></g> */
.flow-node .dot { fill: var(--node-off, #FFFFFF); stroke: var(--node-off-stroke, rgba(11,28,44,.35)); stroke-width: 1.5; transition: fill 500ms var(--mo-ease), stroke 500ms var(--mo-ease); }
.flow-node .ring { fill: none; stroke: var(--mo-flow); stroke-width: 2; opacity: 0; transform-box: fill-box; transform-origin: center; }
.flow-node.is-on .dot { fill: var(--mo-flow); stroke: var(--mo-flow); }
.mo .flow-node.is-on .ring { animation: mo-ring 1400ms var(--mo-ease) 1; }
.mo .flow-node.is-current .ring { animation: mo-ring 1600ms var(--mo-ease) 2; } /* finite: WCAG 2.2.2 */
@keyframes mo-ring { 0% { opacity: .8; transform: scale(.5); } 100% { opacity: 0; transform: scale(2.6); } }

/* HTML nodes (labels placed over an image) only get the state classes; each site styles them. */

/* ── 5. Steps that light up while scrolling, with a progress rail ───────── */
[data-steps] { --p: 0; }
.mo [data-steps] [data-step] { transition: opacity 500ms var(--mo-ease), color 500ms var(--mo-ease); }
/* progress is carried by markers and rails only: fading the text would drop it below AA contrast */
.steps-rail { position: absolute; background: var(--rail-off, rgba(127,127,127,.25)); overflow: hidden; }
.steps-rail::after { content: ""; position: absolute; inset: 0; background: var(--mo-flow); transform-origin: 0 0; transform: scaleY(var(--p)); }
.steps-rail.is-x::after { transform: scaleX(var(--p)); }
html:not(.mo) .steps-rail::after { transform: none; }

/* ── 6. Stacked cards: sticky, the covered card recedes ──────────────────── */
[data-stack] > * { position: sticky; top: calc(var(--stack-top, 96px) + var(--i, 0) * var(--stack-step, 14px)); transform-origin: 50% 0; }
.mo [data-stack] > * { transform: scale(calc(1 - var(--cover, 0) * .05)); filter: brightness(calc(1 - var(--cover, 0) * .06)); }
@media (max-width: 767px) { [data-stack] > * { position: relative; top: auto; } .mo [data-stack] > * { transform: none; filter: none; } }

/* ── 7. Header that settles once the page scrolls ───────────────────────── */
.mo-header { transition: box-shadow 320ms var(--mo-ease), background-color 320ms var(--mo-ease); }
.mo-header.is-scrolled { box-shadow: 0 10px 30px -18px rgba(6, 18, 30, .45); }

/* ── 8. Pointer light on cards (sober, fine pointers only) ──────────────── */
@media (hover: hover) and (pointer: fine) {
  [data-glow] { position: relative; isolation: isolate; }
  [data-glow]::before { content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; z-index: -1; opacity: 0; transition: opacity 320ms var(--mo-ease);
    background: radial-gradient(420px circle at var(--mx, 50%) var(--my, 50%), var(--glow, rgba(31, 168, 224, .12)), transparent 60%); }
  [data-glow]:hover::before { opacity: 1; }
}

/* ── 9. Generated images: fallback until the file is listed in gen-manifest.js ── */
[data-gen] > .gen-img { display: block; width: 100%; height: auto; }
.mo [data-gen] > .gen-img { animation: mo-focus 900ms var(--mo-ease) both; }
[data-gen].has-gen > :not(.gen-img):not(figcaption):not(ol):not(ul):not(svg.flow-layer) { display: none; }

/* ── 10. Shared ecosystem module: the connector grows from the centre ─────── */
.mo [data-eco] svg { clip-path: circle(calc(var(--p, 0) * 75%) at 50% 0); transition: clip-path 1600ms var(--mo-ease); }
.mo [data-eco].is-in svg { --p: 1; }
.mo [data-eco] svg circle { transform-box: fill-box; transform-origin: center; }
.mo [data-eco].is-in svg circle { animation: mo-ring-soft 1600ms var(--mo-ease) 1200ms 2; }
@keyframes mo-ring-soft { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.35); } }

@media (prefers-reduced-motion: reduce) {
  .flow-pulse { display: none; }
  .flow-node .ring { animation: none !important; }
}

/* ── 11. Coded isometric art (motion/gen_art.py): faces by class, themed by variables ── */
.art, .eco-scene { display: block; width: 100%; height: auto; overflow: visible; }
.art .t, .eco-scene .t { fill: var(--art-t, #F4F7FB); }
.art .l, .eco-scene .l { fill: var(--art-l, #DCE5F3); }
.art .r, .eco-scene .r { fill: var(--art-r, #B9CBE6); }
.art .ta, .eco-scene .ta { fill: var(--art-ta, #C2D9F7); }
.art .la, .eco-scene .la { fill: var(--art-la, #8FB3E6); }
.art .ra, .eco-scene .ra { fill: var(--art-ra, #6F98D6); }
.art polygon, .eco-scene polygon { stroke: var(--art-line, #0B1C2C); stroke-width: 1; stroke-linejoin: round; }
.art-ink { stroke: var(--art-line, #0B1C2C); stroke-width: 1.2; stroke-linecap: round; opacity: .55; }
.art-flow { fill: none; stroke: var(--mo-flow); stroke-width: 2.5; stroke-linecap: round; }
.art-node .ring { fill: none; stroke: var(--mo-flow); stroke-width: 1.5; opacity: .45; }
.art-node .dot { fill: var(--mo-flow); }
.art-frame { fill: none; stroke: var(--art-line, #0B1C2C); stroke-width: 1; opacity: .5; }
.art-mast { stroke: var(--art-line, #0B1C2C); stroke-width: 2; stroke-linecap: round; }
.art-cable { stroke: var(--art-line, #0B1C2C); stroke-width: 1; }
.art-graph { fill: var(--art-t, #F4F7FB); stroke: var(--art-line, #0B1C2C); stroke-width: 1.2; transition: fill 500ms var(--mo-ease); }

/* navy ground variant (panels, dark heroes) */
.art-on-dark { --art-t: #2A4562; --art-l: #1A3044; --art-r: #10233A; --art-ta: #C2D9F7; --art-la: #8FB3E6; --art-ra: #6F98D6; --art-line: #C2D9F7; }

/* hover / selection: the subject lifts, its marker switches on */
.art polygon, .art .art-ink { transition: transform 320ms var(--mo-ease); }
[data-art-host]:hover .art > polygon, [data-art-host]:focus-within .art > polygon,
[data-art-host]:hover .art > .art-ink, [data-art-host]:focus-within .art > .art-ink { transform: translateY(-3px); }
[data-art-host] .art-node .ring { transform-box: fill-box; transform-origin: center; }
.mo [data-art-host]:hover .art-node .ring, .mo [data-art-host]:focus-within .art-node .ring { animation: mo-ring 1400ms var(--mo-ease) 1; }

/* ── 12. Ecosystem scene: the line reaches each universe, which then comes to life once ── */
.eco-scene { --node-off: #FFFFFF; }
.eco-scene .flow-path { stroke-width: 3; }
.eco-scene .u { transition: opacity 400ms var(--mo-ease); }
.mo .eco-scene .u-move { transform: translateY(-26px); transition: transform 1100ms var(--mo-ease); }
.mo .eco-scene .u-ma.is-on .u-move { transform: none; }
.mo .eco-scene .u-layer { opacity: 0; transform: translateY(-22px); transition: opacity 600ms var(--mo-ease), transform 800ms var(--mo-ease); transition-delay: calc(var(--k) * 140ms); }
.mo .eco-scene .u-io.is-on .u-layer { opacity: 1; transform: none; }
.mo .eco-scene .u-edge { opacity: 0; transition: opacity 500ms var(--mo-ease); transition-delay: calc(var(--k) * 90ms + 200ms); }
.mo .eco-scene .u-ai.is-on .u-edge { opacity: 1; }
.eco-scene .u-ai.is-on .art-graph { fill: var(--mo-flow); }
.eco-scene .u-ai .u-node .art-graph { transition-delay: calc(var(--k) * 110ms); }
/* the universe of the current site is highlighted; hovering a card highlights its universe */
[data-here="ma"] .u-ma > .t:first-child, [data-here="io"] .u-io > .t:first-child, [data-here="ai"] .u-ai > .t:first-child { fill: #FFFFFF; }
[data-focus] .eco-scene .u { opacity: .45; }
[data-focus="ma"] .eco-scene .u-ma, [data-focus="io"] .eco-scene .u-io, [data-focus="ai"] .eco-scene .u-ai { opacity: 1; }
.eco-scene .u.is-on .flow-node .dot { fill: var(--mo-flow); stroke: var(--mo-flow); }
.mo .eco-scene .u.is-on .flow-node .ring { animation: mo-ring 1400ms var(--mo-ease) 1; }

/* product plate: one level cyan line across every plate, so a row of cards reads as one chain */
.art-plate { position: relative; }
.art-plate { background-image: linear-gradient(var(--mo-flow), var(--mo-flow)); background-repeat: no-repeat; background-size: 100% 2px; background-position: 0 84%; } /* line in the background: ::before stays free for data-glow */
.art-plate::after { content: ""; position: absolute; left: 50%; bottom: calc(16% - 4px); width: 10px; height: 10px; margin-left: -5px; border-radius: 50%; background: var(--node-off, #FFFFFF); border: 2px solid var(--mo-flow); transition: background 320ms var(--mo-ease), box-shadow 320ms var(--mo-ease); }
[data-art-host]:hover .art-plate::after, [data-art-host]:focus-within .art-plate::after, .art-plate.is-on::after { background: var(--mo-flow); box-shadow: 0 0 0 5px rgba(31, 168, 224, .2); }
.art-plate .art { position: relative; z-index: 1; }

/* A generated image carries its own line and marker: the plate drops its coded ones */
.art-plate.has-gen { background-image: none; padding: 0; align-items: stretch; }
.art-plate.has-gen::after { display: none; }
.art-plate.has-gen > .gen-img { width: 100%; height: 100%; object-fit: cover; }
/* pause button of a continuous line (data-repeat): shown only when motion plays */
.flow-toggle { display: none; }
.mo .flow-toggle { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 16px; border: 1px solid rgba(194, 217, 247, .45); border-radius: 999px; background: rgba(6, 18, 30, .72); color: #EEF0F2; font-family: inherit; font-size: .8125rem; font-weight: 500; line-height: 1; cursor: pointer; transition: background 160ms ease, border-color 160ms ease; }
.mo .flow-toggle:hover { border-color: #C2D9F7; background: rgba(6, 18, 30, .9); }
.flow-toggle:focus-visible { outline: 2px solid #C2D9F7; outline-offset: 3px; }
.flow-toggle .ft-play, .flow-toggle.is-paused .ft-pause { display: none; }
.flow-toggle.is-paused .ft-play { display: inline; }
.flow-toggle::before { content: ""; width: 10px; height: 10px; background: linear-gradient(90deg, currentColor 0 3px, transparent 3px 7px, currentColor 7px); }
.flow-toggle.is-paused::before { background: currentColor; clip-path: polygon(0 0, 100% 50%, 0 100%); }
