/* =====================================================================
   Framewright — strona usługi, warstwa wizualna tej strony.
   Układ i komponenty siedzą w main.css. Tutaj jest hero z rysunkiem
   konstrukcyjnym strony oraz dwie listy, których strona główna nie ma.
   ===================================================================== */

/* ---------- Hero usługi ---------- */

/* Nagłówek jest krótszy niż na stronie głównej, więc hero też */
.hero-service {
  padding-block: clamp(7.5rem, 12vw, 9.5rem) clamp(3.5rem, 8vw, 6rem);
}
.hero-service .hero-grid { align-items: center; }
/* Nagłówek tej strony jest krótszy niż na stronie głównej, więc rysunek
   dostaje tyle samo miejsca co tekst */
@media (min-width: 62rem) {
  .hero-service .hero-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}

/* .crumb przeniesione do main.css: uzywa go teraz takze About */

/* Etykieta usługi z jej numerem w zestawie sześciu */
.kicker-service {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2) var(--space-4);
  margin-bottom: var(--space-4);
  font-family: var(--font-mono);
  font-size: var(--step--1);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--accent-on-dark);
}
/* Numer usługi zostaje jednym kawałkiem, więc nie pęka w pół przy
   zawijaniu na telefonie */
.ks-idx {
  white-space: nowrap;
  color: color-mix(in srgb, var(--off-white) 40%, var(--navy));
}
.ks-idx b { font-weight: 500; color: var(--ink-inverse); }

/* Jedna cicha linia wiarygodności, bez pastylek */
.hero-note {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin-block-start: var(--space-6);
  padding-block-start: var(--space-5);
  border-top: 1px solid var(--line-inverse);
  font-family: var(--font-mono);
  font-size: var(--step--1);
  color: color-mix(in srgb, var(--off-white) 58%, var(--navy));
}
/* Separator nalezy do drugiego faktu, wiec przy zawijaniu schodzi
   z nim do nowego wiersza i nigdzie nie wisi */
.hero-note span + span::before {
  content: "";
  display: inline-block;
  width: 4px;
  height: 4px;
  margin-inline-end: var(--space-3);
  border-radius: 50%;
  background: var(--accent-on-dark);
  vertical-align: 0.15em;
}

/* ---------- Rysunek konstrukcyjny strony ----------
   Stylizowany layout strony budowany jak konstrukcja: rama viewportu
   z narożnikami, siatka, cztery moduły, znaczniki pomiarowe, ścieżka
   odwiedzającego i jeden mosiądzowy akcent na wezwaniu do działania.
   Kreski trzymają grubość przez vector-effect w znacznikach. */

.blueprint-art {
  position: relative;
  width: 100%;
  aspect-ratio: 620 / 520;
  pointer-events: none;
  /* Mnożnik czasu: na telefonie ta sama sekwencja leci krócej */
  --t: 1;
}

.bp-canvas {
  position: absolute;
  inset: 0;
  transform: translate3d(
    calc(var(--pointer-x, 0) * 6px),
    calc(var(--pointer-y, 0) * 6px),
    0
  );
}
.bp { width: 100%; height: 100%; }

/* Siatka i linie bazowe */
.bp-baseline,
.bp-col {
  stroke: color-mix(in srgb, var(--off-white) 7%, transparent);
  stroke-width: 1;
}
.bp-col { stroke: color-mix(in srgb, var(--off-white) 5%, transparent); }
.bp-tick {
  stroke: color-mix(in srgb, var(--cyan) 34%, transparent);
  stroke-width: 1;
}

/* Rama viewportu: narożniki konstrukcyjne plus cienkie krawędzie */
.bp-corner {
  stroke: color-mix(in srgb, var(--cyan) 62%, transparent);
  stroke-width: 1.8;
  stroke-linecap: square;
}
.bp-edge {
  stroke: color-mix(in srgb, var(--cyan) 26%, transparent);
  stroke-width: 1;
}

/* Powierzchnia strony pod konstrukcją: bez tego rama nie czyta się
   jako strona, tylko jako zbiór kresek */
.bp-surface {
  fill: color-mix(in srgb, var(--off-white) 2.5%, transparent);
  stroke: none;
}

/* Moduły strony */
.bp-box {
  stroke: color-mix(in srgb, var(--off-white) 20%, transparent);
  stroke-width: 1;
  fill: color-mix(in srgb, var(--off-white) 3%, transparent);
}
.bp-plate {
  stroke: color-mix(in srgb, var(--off-white) 11%, transparent);
  stroke-width: 1;
  fill: color-mix(in srgb, var(--off-white) 2%, transparent);
}
.bp-line {
  stroke: color-mix(in srgb, var(--off-white) 42%, transparent);
  stroke-width: 2;
  stroke-linecap: round;
}
.bp-line-quiet {
  stroke: color-mix(in srgb, var(--off-white) 19%, transparent);
  stroke-width: 1.6;
}
.bp-chip {
  stroke: color-mix(in srgb, var(--cyan) 40%, transparent);
  stroke-width: 1;
  fill: color-mix(in srgb, var(--cyan) 12%, transparent);
}

/* Jedyny mosiądz w rysunku: najważniejsze działanie na stronie */
.bp-cta {
  fill: var(--brass);
  stroke: none;
}
.bp-sweep-edge { stop-color: var(--off-white); stop-opacity: 0; }
.bp-sweep-mid { stop-color: var(--off-white); stop-opacity: 0.5; }
.bp-sweep { transform: translateX(-84px); }

/* Znaczniki pomiarowe */
.bp-dim,
.bp-dim-cap {
  stroke: color-mix(in srgb, var(--cyan) 42%, transparent);
  stroke-width: 1;
}

/* Punkty mocowania modułów na siatce */
.bp-pin { fill: color-mix(in srgb, var(--cyan) 72%, transparent); }

/* Ścieżka odwiedzającego: od wejścia na stronę do wezwania */
.bp-path {
  stroke: color-mix(in srgb, var(--cyan) 74%, transparent);
  stroke-width: 1.6;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.bp-path-pulse {
  --dash: 0.07;
  stroke: color-mix(in srgb, var(--cyan) 80%, var(--off-white));
  stroke-width: 2.6;
  stroke-linecap: round;
  stroke-dasharray: var(--dash) 1;
  stroke-dashoffset: var(--dash);
  opacity: 0;
}

/* ---------- Stan przed sekwencją ----------
   Zatrzymanie w dowolnej klatce ma wyglądać dobrze, więc nic nie
   startuje z zera: moduły są odsunięte, nie skurczone. */

.bp-corner,
.bp-baseline,
.bp-col,
.bp-tick,
.bp-dim-cap { opacity: 0; }
.bp-edge,
.bp-dim,
.bp-path {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
}
.bp-mod {
  opacity: 0;
  transform: translate3d(var(--dx, 0px), var(--dy, 0px), 0);
}
.bp-pin {
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
  transform: scale(0.92);
}

/* ---------- Sekwencja składania ---------- */

.is-built .bp-corner {
  animation: bp-in 300ms var(--ease-out) forwards;
  animation-delay: calc(var(--i, 0) * 50ms * var(--t));
}
.is-built .bp-edge {
  animation: bp-draw 480ms var(--ease-out) forwards;
  animation-delay: calc((200ms + var(--i, 0) * 40ms) * var(--t));
}
.is-built .bp-baseline,
.is-built .bp-col,
.is-built .bp-tick {
  animation: bp-in 400ms var(--ease-out) forwards;
  animation-delay: calc((500ms + var(--i, 0) * 40ms) * var(--t));
}
.is-built .bp-mod {
  animation: bp-settle 520ms var(--ease-in-out) forwards;
  animation-delay: calc((700ms + var(--i, 0) * 70ms) * var(--t));
}
.is-built .bp-dim {
  animation: bp-draw 380ms var(--ease-out) forwards;
  animation-delay: calc((1000ms + var(--i, 0) * 90ms) * var(--t));
}
.is-built .bp-dim-cap {
  animation: bp-in 300ms var(--ease-out) forwards;
  animation-delay: calc((1000ms + var(--i, 0) * 90ms) * var(--t));
}
.is-built .bp-pin {
  animation: bp-pin-in 380ms var(--ease-out) forwards;
  animation-delay: calc((1050ms + var(--i, 0) * 60ms) * var(--t));
}
.is-built .bp-path {
  animation: bp-draw 1050ms var(--ease-in-out) forwards;
  animation-delay: calc(1300ms * var(--t));
}
/* Jeden spokojny sygnał na wezwaniu, nie migotanie */
.is-built .bp-sweep {
  animation: bp-sweep 620ms var(--ease-out) forwards;
  animation-delay: calc(2300ms * var(--t));
}
/* Jedyny ruch w spoczynku: impuls ścieżką raz na dwanaście sekund */
.is-built .bp-path-pulse {
  animation: bp-pulse 12s linear 3s infinite;
}

@keyframes bp-in { to { opacity: 1; } }
@keyframes bp-draw { to { stroke-dashoffset: 0; } }
@keyframes bp-settle { to { opacity: 1; transform: none; } }
@keyframes bp-pin-in { to { opacity: 1; transform: scale(1); } }
@keyframes bp-sweep { to { transform: translateX(146px); } }
@keyframes bp-pulse {
  0% { stroke-dashoffset: var(--dash); opacity: 0; }
  1% { opacity: 0.9; }
  9% { stroke-dashoffset: -1; opacity: 0; }
  100% { stroke-dashoffset: -1; opacity: 0; }
}

/* ---------- Uproszczenie na telefonie ----------
   Nie pomniejszamy rysunku, tylko zdejmujemy detal, który przestaje
   być czytelny, i skracamy sekwencję. */
@media (max-width: 62rem) {
  .blueprint-art {
    --t: 0.62;
    margin-block-start: var(--space-4);
  }
  .bp-detail { display: none; }
  .bp-line { stroke-width: 2.4; }
  .bp-line-quiet { stroke-width: 2; }
}

/* ---------- Listy tej strony ---------- */

.checks {
  display: grid;
  gap: var(--space-4);
  margin: 0;
  padding: 0;
  list-style: none;
}
@media (min-width: 52rem) {
  .checks { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-5) var(--space-7); }
}
.checks li {
  display: flex;
  align-items: start;
  gap: var(--space-4);
  padding-block-end: var(--space-4);
  border-bottom: 1px solid var(--line);
  color: var(--ink-muted);
}
/* Znacznik rysowany CSS-em: dwa boki obrócone o 45 stopni, ta sama
   logika kresek co w znaku marki. Bez dodatkowego SVG w treści. */
.check {
  flex: 0 0 auto;
  width: 13px;
  height: 7px;
  margin-block-start: 0.3em;
  margin-inline-end: 2px;
  border-inline-start: 2px solid var(--accent);
  border-block-end: 2px solid var(--accent);
  transform: rotate(-45deg);
}

.process-rows {
  display: grid;
  gap: 0;
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: none;
}
.process-rows li {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--space-4) var(--space-5);
  padding-block: var(--space-5);
  border-top: 1px solid var(--line);
}
.process-rows li:last-child { border-bottom: 1px solid var(--line); }
@media (min-width: 52rem) {
  .process-rows li { grid-template-columns: 5rem minmax(0, 1fr); gap: var(--space-6); }
}
.process-num {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  letter-spacing: var(--tracking-label);
  color: var(--accent);
}
.process-rows h3 { margin-bottom: var(--space-2); font-size: var(--step-1); }
.process-rows p { color: var(--ink-muted); max-width: 62ch; }

/* Pas domykający jest jednokolumnowy, bez karty z listą */
.start-band > div { max-width: var(--shell-narrow); }
.start-band h2 { margin-block: var(--space-4) var(--space-5); }

/* ---------- Mniej ruchu ---------- */

@media (prefers-reduced-motion: reduce) {
  /* Od razu gotowa konstrukcja, bez sekwencji i bez ruchu w spoczynku */
  .bp-corner,
  .bp-baseline,
  .bp-col,
  .bp-tick,
  .bp-dim-cap,
  .bp-mod,
  .bp-pin { opacity: 1; }
  .bp-mod,
  .bp-pin { transform: none; }
  .bp-edge,
  .bp-dim,
  .bp-path { stroke-dashoffset: 0; }
  .bp-path-pulse { display: none; }
  .bp-sweep { display: none; }
  .bp-canvas { transform: translate3d(0, 0, 0); }

  .is-built .bp-corner,
  .is-built .bp-edge,
  .is-built .bp-baseline,
  .is-built .bp-col,
  .is-built .bp-tick,
  .is-built .bp-mod,
  .is-built .bp-dim,
  .is-built .bp-dim-cap,
  .is-built .bp-pin,
  .is-built .bp-path,
  .is-built .bp-sweep,
  .is-built .bp-path-pulse { animation: none; }
}

/* Bez JS klasa nie dojdzie, więc pokazujemy stan gotowy */
.no-js .bp-corner,
.no-js .bp-baseline,
.no-js .bp-col,
.no-js .bp-tick,
.no-js .bp-dim-cap,
.no-js .bp-mod,
.no-js .bp-pin { opacity: 1; }
.no-js .bp-mod,
.no-js .bp-pin { transform: none; }
.no-js .bp-edge,
.no-js .bp-dim,
.no-js .bp-path { stroke-dashoffset: 0; }
.no-js .bp-sweep { display: none; }

/* =====================================================================
   Marketing Strategy & Systems — marketingowy system operacyjny.
   Rozproszone działania wchodzą po lewej, środek je porządkuje, po
   prawej widać odpowiedź klienta i mierzalny wynik. Bursztyn tylko
   w czterech miejscach: aktywne połączenie, punkt kontroli, odpowiedź
   i wynik. Bazę hero, listy i pas domykający dzieli z jedynką.
   ===================================================================== */

/* Naglowek tej strony jest dluzszy niz na jedynce, wiec kolumna tekstu
   dostaje wiecej miejsca, a rysunek nadrabia wyjsciem za siatke */
@media (min-width: 62rem) {
  .hero-service:has(.ms-art) .hero-grid {
    grid-template-columns: minmax(0, 1.08fr) minmax(0, 0.92fr);
  }
}

.ms-art { aspect-ratio: 700 / 520; }
/* Rysunek wychodzi za siatkę treści, tak jak zbieganie procesów na
   stronie głównej. Szerokość, nie ujemny margines. */
@media (min-width: 62rem) {
  .ms-art { width: calc(100% + clamp(2rem, 5vw, 7rem)); }
}
.ms { width: 100%; height: 100%; }

/* ---------- Rama systemu ---------- */

.ms-corner {
  stroke: color-mix(in srgb, var(--cyan) 62%, transparent);
  stroke-width: 1.8;
  stroke-linecap: square;
}
.ms-edge {
  stroke: color-mix(in srgb, var(--cyan) 26%, transparent);
  stroke-width: 1;
}

/* ---------- Moduły procesu ---------- */

.ms-box {
  stroke: color-mix(in srgb, var(--off-white) 20%, transparent);
  stroke-width: 1;
  fill: color-mix(in srgb, var(--off-white) 3%, transparent);
}
.ms-line {
  stroke: color-mix(in srgb, var(--off-white) 42%, transparent);
  stroke-width: 2;
  stroke-linecap: round;
}
.ms-line-quiet {
  stroke: color-mix(in srgb, var(--off-white) 19%, transparent);
  stroke-width: 1.6;
}
/* Punkty dystrybucji: tu ląduje CHANNELS */
.ms-chip {
  stroke: color-mix(in srgb, var(--cyan) 40%, transparent);
  stroke-width: 1;
  fill: color-mix(in srgb, var(--cyan) 12%, transparent);
}
.ms-riser path {
  stroke: color-mix(in srgb, var(--cyan) 50%, transparent);
  stroke-width: 1.2;
}

/* Rytm działań: pięć znaczników i marker, który stoi na pierwszym */
.ms-tick {
  stroke: color-mix(in srgb, var(--cyan) 38%, transparent);
  stroke-width: 1.4;
}
.ms-marker { fill: color-mix(in srgb, var(--cyan) 78%, transparent); }

/* Połączenia w środku systemu */
.ms-link,
.ms-stub,
.ms-out {
  stroke: color-mix(in srgb, var(--cyan) 55%, transparent);
  stroke-width: 1.4;
  stroke-linejoin: round;
}
/* Aktywne połączenie: bursztyn dochodzi kryciem, bez animowania barwy */
.ms-hot {
  stroke: var(--accent-on-dark);
  stroke-width: 2;
  opacity: 0;
}

/* Punkt kontroli i pomiaru na wyjściu systemu */
.ms-ctrl {
  fill: color-mix(in srgb, var(--brass) 22%, var(--navy));
  stroke: var(--accent-on-dark);
  stroke-width: 1.6;
}
.ms-ctrl-mark {
  stroke: color-mix(in srgb, var(--brass) 60%, transparent);
  stroke-width: 1.2;
}

/* ---------- Ścieżka rezultatu ---------- */

.ms-path {
  stroke: color-mix(in srgb, var(--cyan) 70%, transparent);
  stroke-width: 1.6;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.ms-branch {
  stroke: color-mix(in srgb, var(--cyan) 34%, transparent);
  stroke-width: 1.2;
  stroke-linejoin: round;
}
.ms-node {
  fill: color-mix(in srgb, var(--cyan) 20%, var(--navy));
  stroke: color-mix(in srgb, var(--cyan) 70%, transparent);
  stroke-width: 1.4;
}
.ms-result {
  fill: var(--brass);
  stroke: none;
}
.ms-answer {
  fill: none;
  stroke: var(--accent-on-dark);
  stroke-width: 1.4;
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
}

/* ---------- Sygnały ---------- */

.ms-sig-sys,
.ms-sig-out {
  --dash: 0.07;
  stroke: color-mix(in srgb, var(--cyan) 80%, var(--off-white));
  stroke-width: 2.6;
  stroke-linecap: round;
  stroke-dasharray: var(--dash) 1;
  stroke-dashoffset: var(--dash);
  opacity: 0;
}
.ms-sig-out { --dash: 0.05; }

/* ---------- Znaczniki pomiarowe ---------- */

.ms-dim,
.ms-dim-cap,
.ms-index {
  stroke: color-mix(in srgb, var(--cyan) 40%, transparent);
  stroke-width: 1;
}

/* ---------- Etykiety: prawdziwy tekst, nie tekst w SVG ---------- */

.ms-in {
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: var(--y);
  width: 16.9%;
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: end;
  gap: var(--space-2);
  transform: translate3d(0, var(--dy, 0px), 0) translateY(-50%);
  opacity: 0;
}
.ms-in b {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: clamp(0.5rem, 1.55cqi, 0.68rem);
  letter-spacing: 0.08em;
  color: color-mix(in srgb, var(--off-white) 82%, var(--navy));
  padding-inline-start: var(--space-2);
  border-inline-start: 2px solid color-mix(in srgb, var(--cyan) 45%, transparent);
}
.ms-in i {
  flex: 0 0 auto;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--cyan) 62%, var(--navy));
}

.ms-station {
  position: absolute;
  inset-inline-start: var(--x);
  inset-block-start: var(--y);
  margin: 0;
  transform: translate(-50%, -170%);
  font-family: var(--font-mono);
  font-size: clamp(0.48rem, 1.45cqi, 0.64rem);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  color: color-mix(in srgb, var(--off-white) 58%, var(--navy));
  opacity: 0;
}
.ms-station-key { color: var(--accent-on-dark); }

/* ---------- Stan przed sekwencją ----------
   Moduły wejściowe są odsunięte i przygaszone, ich odcinki nie dobiegają
   do ramy. Nic nie startuje ze skali zero. */

.ms-corner,
.ms-tick,
.ms-marker,
.ms-chip,
.ms-node,
.ms-result,
.ms-dim-cap,
.ms-index { opacity: 0; }
.ms-edge,
.ms-link,
.ms-stub,
.ms-out,
.ms-path,
.ms-branch,
.ms-dim,
.ms-riser path {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
}
.ms-proc {
  opacity: 0;
  transform: translate3d(0, 8px, 0);
}

/* ---------- Sekwencja porządkowania ---------- */

.is-built .ms-corner {
  animation: bp-in 300ms var(--ease-out) forwards;
  animation-delay: calc(var(--i, 0) * 50ms * var(--t));
}
.is-built .ms-edge {
  animation: bp-draw 420ms var(--ease-out) forwards;
  animation-delay: calc((160ms + var(--i, 0) * 40ms) * var(--t));
}
.is-built .ms-dim {
  animation: bp-draw 360ms var(--ease-out) forwards;
  animation-delay: calc(320ms * var(--t));
}
.is-built .ms-dim-cap,
.is-built .ms-index {
  animation: bp-in 300ms var(--ease-out) forwards;
  animation-delay: calc((320ms + var(--i, 0) * 60ms) * var(--t));
}
.is-built .ms-proc {
  animation: bp-settle 460ms var(--ease-out) forwards;
  animation-delay: calc((250ms + var(--i, 0) * 90ms) * var(--t));
}
/* MESSAGE i AUDIENCE wchodzą pierwsze i łączą się z modułem planu */
.is-built .ms-in {
  animation: ms-align 480ms var(--ease-out) forwards;
  animation-delay: calc((520ms + var(--i, 0) * 90ms) * var(--t));
}
.is-built .ms-stub {
  animation: bp-draw 420ms var(--ease-out) forwards;
  animation-delay: calc((600ms + var(--i, 0) * 90ms) * var(--t));
}
.is-built .ms-link {
  animation: bp-draw 380ms var(--ease-out) forwards;
  animation-delay: calc((700ms + var(--i, 0) * 80ms) * var(--t));
}
/* CHANNELS trafia do punktów dystrybucji */
.is-built .ms-chip {
  animation: bp-in 320ms var(--ease-out) forwards;
  animation-delay: calc((840ms + var(--i, 0) * 70ms) * var(--t));
}
.is-built .ms-riser path {
  animation: bp-draw 260ms var(--ease-out) forwards;
  animation-delay: calc((880ms + var(--i, 0) * 70ms) * var(--t));
}
/* CADENCE odpala rytm */
.is-built .ms-tick {
  animation: bp-in 280ms var(--ease-out) forwards;
  animation-delay: calc((1050ms + var(--i, 0) * 60ms) * var(--t));
}
/* Aktywne połączenie i punkt kontroli robią się bursztynowe */
.is-built .ms-hot {
  animation: bp-in 420ms var(--ease-out) forwards;
  animation-delay: calc(1300ms * var(--t));
}
.is-built .ms-out {
  animation: bp-draw 320ms var(--ease-out) forwards;
  animation-delay: calc(1360ms * var(--t));
}
.is-built .ms-path {
  animation: bp-draw 720ms var(--ease-in-out) forwards;
  animation-delay: calc(1420ms * var(--t));
}
.is-built .ms-branch {
  animation: bp-draw 420ms var(--ease-out) forwards;
  animation-delay: calc(1900ms * var(--t));
}
.is-built .ms-node {
  animation: bp-in 320ms var(--ease-out) forwards;
  animation-delay: calc((1560ms + var(--i, 0) * 140ms) * var(--t));
}
.is-built .ms-station {
  animation: bp-in 380ms var(--ease-out) forwards;
  animation-delay: calc((1620ms + var(--i, 0) * 140ms) * var(--t));
}
.is-built .ms-result {
  animation: bp-in 400ms var(--ease-out) forwards;
  animation-delay: calc(2100ms * var(--t));
}

/* Sygnał przez system, potem przez ścieżkę, na końcu odpowiedź klienta.
   Pierwszy przebieg jest częścią wejścia, potem wraca raz na 11 s.
   Nigdy dwa sygnały naraz. */
.is-built .ms-sig-sys { animation: ms-travel 11s linear 1.5s infinite; }
.is-built .ms-sig-out { animation: ms-travel 11s linear 2.15s infinite; }
.is-built .ms-answer { animation: ms-answer 11s var(--ease-out) 2.6s infinite; }
/* Marker cadence: wchodzi kryciem, potem raz na cykl przesuwa się o
   jeden piksel. Tyle wystarczy, żeby rytm żył. */
.is-built .ms-marker {
  animation:
    bp-in 300ms var(--ease-out) forwards,
    ms-marker 11s var(--ease-in-out) infinite;
  animation-delay: calc(1340ms * var(--t)), 2.8s;
}

@keyframes ms-align {
  to { opacity: 1; transform: none; }
}
@keyframes ms-travel {
  0% { stroke-dashoffset: var(--dash); opacity: 0; }
  1% { opacity: 0.95; }
  6% { stroke-dashoffset: -1; opacity: 0; }
  100% { stroke-dashoffset: -1; opacity: 0; }
}
@keyframes ms-answer {
  0%, 1% { opacity: 0; transform: scale(0.82); }
  4% { opacity: 0.85; transform: scale(1); }
  11% { opacity: 0; transform: scale(1.5); }
  100% { opacity: 0; transform: scale(1.5); }
}
@keyframes ms-marker {
  0%, 3% { transform: none; }
  6% { transform: translateX(1px); }
  12%, 100% { transform: none; }
}

/* ---------- Uproszczenie na telefonie ----------
   Trzy wejścia, dwa moduły procesu, jedna etykieta na ścieżce, bez
   detalu pomiarowego. Metafora ma się czytać bez analizy. */
@media (max-width: 62rem) {
  .ms-detail,
  .ms-cadence,
  .ms-station:not(.ms-station-key) { display: none; }
  .ms-tick,
  .ms-marker { display: none; }
  .ms-line { stroke-width: 2.4; }
  .ms-line-quiet { stroke-width: 2; }
}

/* ---------- Mniej ruchu i brak JS ----------
   Od razu stan połączony: bursztyn na aktywnym połączeniu i punkcie
   kontroli, wynik widoczny, zero cykli. Pełna hierarchia zostaje. */

@media (prefers-reduced-motion: reduce) {
  .ms-corner,
  .ms-tick,
  .ms-marker,
  .ms-chip,
  .ms-node,
  .ms-result,
  .ms-dim-cap,
  .ms-index,
  .ms-hot,
  .ms-proc,
  .ms-in,
  .ms-station { opacity: 1; }
  .ms-proc,
  .ms-in { transform: none; }
  .ms-in { transform: translateY(-50%); }
  .ms-edge,
  .ms-link,
  .ms-stub,
  .ms-out,
  .ms-path,
  .ms-branch,
  .ms-dim,
  .ms-riser path { stroke-dashoffset: 0; }
  .ms-sig-sys,
  .ms-sig-out,
  .ms-answer { display: none; }

  .is-built .ms-corner,
  .is-built .ms-edge,
  .is-built .ms-dim,
  .is-built .ms-dim-cap,
  .is-built .ms-index,
  .is-built .ms-proc,
  .is-built .ms-in,
  .is-built .ms-stub,
  .is-built .ms-link,
  .is-built .ms-chip,
  .is-built .ms-riser path,
  .is-built .ms-tick,
  .is-built .ms-marker,
  .is-built .ms-hot,
  .is-built .ms-out,
  .is-built .ms-path,
  .is-built .ms-branch,
  .is-built .ms-node,
  .is-built .ms-station,
  .is-built .ms-result,
  .is-built .ms-sig-sys,
  .is-built .ms-sig-out,
  .is-built .ms-answer { animation: none; }
}

.no-js .ms-corner,
.no-js .ms-tick,
.no-js .ms-marker,
.no-js .ms-chip,
.no-js .ms-node,
.no-js .ms-result,
.no-js .ms-dim-cap,
.no-js .ms-index,
.no-js .ms-hot,
.no-js .ms-proc,
.no-js .ms-in,
.no-js .ms-station { opacity: 1; }
.no-js .ms-proc { transform: none; }
.no-js .ms-in { transform: translateY(-50%); }
.no-js .ms-edge,
.no-js .ms-link,
.no-js .ms-stub,
.no-js .ms-out,
.no-js .ms-path,
.no-js .ms-branch,
.no-js .ms-dim,
.no-js .ms-riser path { stroke-dashoffset: 0; }
.no-js .ms-sig-sys,
.no-js .ms-sig-out,
.no-js .ms-answer { display: none; }

/* =====================================================================
   CRM & Sales Automation — tor sprzedażowy.
   Jedna linia procesu, cztery etapy, trzy karty leadów i cicha warstwa
   automatyzacji pod spodem. Bursztyn znaczy wyłącznie: następne
   działanie, wymagany follow-up, aktywne przypomnienie i potwierdzone
   przejście etapu.
   ===================================================================== */

.crm-art { aspect-ratio: 700 / 520; }
@media (min-width: 62rem) {
  .hero-service:has(.crm-art) .hero-grid {
    grid-template-columns: minmax(0, 1.06fr) minmax(0, 0.94fr);
  }
  /* Tor wybiega poza siatkę treści: proces idzie dalej niż kadr */
  .crm-art { width: calc(100% + clamp(2rem, 5vw, 7rem)); }
}
/* Prawa krawędź gaśnie, więc tor nie kończy się uciętą kreską */
.crm { width: 100%; height: 100%; mask-image: linear-gradient(90deg, #000 88%, transparent); }

/* ---------- Tor i etapy ---------- */

.crm-corner {
  stroke: color-mix(in srgb, var(--cyan) 52%, transparent);
  stroke-width: 1.6;
  stroke-linecap: square;
}
.crm-track {
  stroke: color-mix(in srgb, var(--cyan) 62%, transparent);
  stroke-width: 1.6;
}
.crm-stagepoint circle {
  fill: color-mix(in srgb, var(--cyan) 22%, var(--navy));
  stroke: color-mix(in srgb, var(--cyan) 72%, transparent);
  stroke-width: 1.4;
}
.crm-stagepoint path {
  stroke: color-mix(in srgb, var(--cyan) 40%, transparent);
  stroke-width: 1.2;
}

.crm-dim,
.crm-dim-cap,
.crm-index {
  stroke: color-mix(in srgb, var(--cyan) 38%, transparent);
  stroke-width: 1;
}

/* ---------- Warstwa automatyzacji ---------- */

.crm-auto-line {
  stroke: color-mix(in srgb, var(--off-white) 14%, transparent);
  stroke-width: 1;
}
.crm-hook {
  stroke: color-mix(in srgb, var(--off-white) 11%, transparent);
  stroke-width: 1;
}
.crm-node {
  fill: color-mix(in srgb, var(--off-white) 8%, var(--navy));
  stroke: color-mix(in srgb, var(--cyan) 42%, transparent);
  stroke-width: 1.2;
}
/* Węzeł przypomnienia zapala się dopiero wtedy, gdy jest potrzebny */
.crm-remind-hot {
  fill: var(--accent-on-dark);
  stroke: none;
  opacity: 0;
}
.crm-ping {
  fill: none;
  stroke: var(--accent-on-dark);
  stroke-width: 1.2;
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
}

/* ---------- Karty leadów ---------- */

.crm-card {
  fill: color-mix(in srgb, var(--off-white) 5%, var(--navy));
  stroke: color-mix(in srgb, var(--off-white) 22%, transparent);
  stroke-width: 1;
}
.crm-owner {
  fill: color-mix(in srgb, var(--cyan) 26%, var(--navy));
  stroke: color-mix(in srgb, var(--cyan) 74%, transparent);
  stroke-width: 1.4;
}
.crm-cline {
  stroke: color-mix(in srgb, var(--off-white) 40%, transparent);
  stroke-width: 2;
  stroke-linecap: round;
}
.crm-cline-quiet {
  stroke: color-mix(in srgb, var(--off-white) 18%, transparent);
  stroke-width: 1.6;
}
/* Następne działanie: jedyne miejsce, gdzie karta ma bursztyn */
.crm-next {
  fill: color-mix(in srgb, var(--brass) 82%, transparent);
  stroke: none;
}
.crm-due {
  stroke: color-mix(in srgb, var(--off-white) 26%, transparent);
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-dasharray: 6 5;
}
.crm-stem {
  stroke: color-mix(in srgb, var(--cyan) 45%, transparent);
  stroke-width: 1.2;
}
/* Znacznik braku następnego kroku. Spokojna korekta, nie alarm. */
.crm-flag {
  fill: var(--accent-on-dark);
  stroke: none;
  opacity: 0;
}

.crm-signal {
  --dash: 0.05;
  stroke: color-mix(in srgb, var(--cyan) 80%, var(--off-white));
  stroke-width: 2.6;
  stroke-linecap: round;
  stroke-dasharray: var(--dash) 1;
  stroke-dashoffset: var(--dash);
  opacity: 0;
}

/* ---------- Etykiety: prawdziwy tekst, nie tekst w SVG ---------- */

.crm-stage,
.crm-label {
  position: absolute;
  inset-inline-start: var(--x);
  inset-block-start: var(--y);
  margin: 0;
  font-family: var(--font-mono);
  font-size: clamp(0.48rem, 1.45cqi, 0.64rem);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  opacity: 0;
}
.crm-stage {
  transform: translateX(-50%);
  color: color-mix(in srgb, var(--off-white) 62%, var(--navy));
}
.crm-stage b { font-weight: 500; color: color-mix(in srgb, var(--off-white) 38%, var(--navy)); }
.crm-label { color: color-mix(in srgb, var(--off-white) 34%, var(--navy)); }
.crm-label-hot {
  transform: translateX(-50%);
  color: var(--accent-on-dark);
}

/* ---------- Stan przed sekwencją ---------- */

.crm-corner,
.crm-stagepoint,
.crm-node,
.crm-dim-cap,
.crm-index,
.crm-owner,
.crm-next,
.crm-due { opacity: 0; }
.crm-track,
.crm-stem,
.crm-dim,
.crm-auto-line,
.crm-hook {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
}
.crm-lead {
  opacity: 0;
  transform: translate3d(var(--dx, 0px), 0, 0);
}

/* ---------- Sekwencja: proces zaczyna działać ---------- */

.is-built .crm-corner {
  animation: bp-in 300ms var(--ease-out) forwards;
  animation-delay: calc(var(--i, 0) * 60ms * var(--t));
}
.is-built .crm-track {
  animation: bp-draw 420ms var(--ease-out) forwards;
}
.is-built .crm-stagepoint {
  animation: bp-in 300ms var(--ease-out) forwards;
  animation-delay: calc((350ms + var(--i, 0) * 70ms) * var(--t));
}
.is-built .crm-stage {
  animation: bp-in 320ms var(--ease-out) forwards;
  animation-delay: calc((480ms + var(--i, 0) * 70ms) * var(--t));
}
.is-built .crm-dim {
  animation: bp-draw 340ms var(--ease-out) forwards;
  animation-delay: calc(560ms * var(--t));
}
.is-built .crm-dim-cap,
.is-built .crm-index {
  animation: bp-in 280ms var(--ease-out) forwards;
  animation-delay: calc((560ms + var(--i, 0) * 60ms) * var(--t));
}
.is-built .crm-auto-line {
  animation: bp-draw 520ms var(--ease-out) forwards;
  animation-delay: calc(500ms * var(--t));
}
.is-built .crm-node {
  animation: bp-in 280ms var(--ease-out) forwards;
  animation-delay: calc((600ms + var(--i, 0) * 60ms) * var(--t));
}
.is-built .crm-hook {
  animation: bp-draw 320ms var(--ease-out) forwards;
  animation-delay: calc((700ms + var(--i, 0) * 80ms) * var(--t));
}
.is-built .crm-label {
  animation: bp-in 320ms var(--ease-out) forwards;
  animation-delay: calc(760ms * var(--t));
}

/* Lead 01: wjeżdża do systemu, dostaje właściciela i następny krok,
   potem przechodzi etap. Jedna animacja, żeby ruch był ciągły. */
.is-built .crm-a {
  animation: crm-enter-a 1050ms both;
  animation-delay: calc(600ms * var(--t));
}
.is-built .crm-a .crm-stem {
  animation: bp-draw 380ms var(--ease-out) forwards;
  animation-delay: calc(1650ms * var(--t));
}
.is-built .crm-a .crm-owner {
  animation: bp-in 320ms var(--ease-out) forwards;
  animation-delay: calc(850ms * var(--t));
}
.is-built .crm-a .crm-next,
.is-built .crm-a .crm-due {
  animation: bp-in 320ms var(--ease-out) forwards;
  animation-delay: calc(1000ms * var(--t));
}

/* Lead 02: staje bez następnego kroku i czeka, aż system to wyłapie */
.is-built .crm-b {
  animation: crm-enter-b 1350ms both;
  animation-delay: calc(1500ms * var(--t));
}
.is-built .crm-b .crm-owner {
  animation: bp-in 300ms var(--ease-out) forwards;
  animation-delay: calc(1700ms * var(--t));
}
.is-built .crm-b .crm-stem {
  animation: crm-stem-b 1000ms var(--ease-out) forwards;
  animation-delay: calc(1600ms * var(--t));
}
.is-built .crm-flag {
  animation: bp-in 340ms var(--ease-out) forwards;
  animation-delay: calc(1800ms * var(--t));
}
.is-built .crm-remind-hot {
  animation: bp-in 340ms var(--ease-out) forwards;
  animation-delay: calc(1850ms * var(--t));
}
.is-built .crm-label-hot {
  animation: bp-in 340ms var(--ease-out) forwards;
  animation-delay: calc(1900ms * var(--t));
}
.is-built .crm-b .crm-next,
.is-built .crm-b .crm-due {
  animation: bp-in 320ms var(--ease-out) forwards;
  animation-delay: calc(2150ms * var(--t));
}

/* Lead 03: cichy, ma już wszystko */
.is-built .crm-c {
  animation: bp-settle 420ms var(--ease-out) forwards;
  animation-delay: calc(900ms * var(--t));
}
.is-built .crm-c .crm-stem {
  animation: bp-draw 360ms var(--ease-out) forwards;
  animation-delay: calc(1000ms * var(--t));
}
.is-built .crm-c .crm-owner,
.is-built .crm-c .crm-next,
.is-built .crm-c .crm-due {
  animation: bp-in 320ms var(--ease-out) forwards;
  animation-delay: calc(1080ms * var(--t));
}

/* Spoczynek: jeden sygnał torem raz na dwanaście sekund, chwilowy
   błysk przy przypomnieniu i milimetrowy ruch znacznika terminu.
   Karty stoją. Pierwszy przebieg to pierwszy cykl tej animacji. */
.is-built .crm-signal { animation: ms-travel 12s linear 3.2s infinite; }
.is-built .crm-ping { animation: ms-answer 12s var(--ease-out) 3.9s infinite; }
.is-built .crm-c .crm-due {
  animation:
    bp-in 320ms var(--ease-out) forwards,
    crm-nudge 12s var(--ease-in-out) infinite;
  animation-delay: calc(1080ms * var(--t)), 3.6s;
}

@keyframes crm-enter-a {
  0% { opacity: 0; transform: translate3d(calc(var(--dx) - 18px), 0, 0); animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1); }
  22% { opacity: 1; transform: translate3d(var(--dx), 0, 0); animation-timing-function: linear; }
  62% { transform: translate3d(var(--dx), 0, 0); animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1); }
  100% { opacity: 1; transform: none; }
}
@keyframes crm-enter-b {
  0% { opacity: 0; transform: translate3d(calc(var(--dx) - 14px), 0, 0); animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1); }
  18% { opacity: 1; transform: translate3d(var(--dx), 0, 0); animation-timing-function: linear; }
  66% { transform: translate3d(var(--dx), 0, 0); animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1); }
  100% { opacity: 1; transform: none; }
}
/* Wspornik z przerwą, dorysowany dopiero po przypomnieniu */
@keyframes crm-stem-b {
  0% { stroke-dashoffset: 1; }
  20% { stroke-dashoffset: 0.45; }
  60% { stroke-dashoffset: 0.45; }
  100% { stroke-dashoffset: 0; }
}
@keyframes crm-nudge {
  0%, 4% { transform: none; }
  7% { transform: translateX(1px); }
  13%, 100% { transform: none; }
}

/* ---------- Uproszczenie na telefonie ----------
   Trzy etapy, jedna karta z historią, jeden mechanizm przypomnienia.
   Metafora ma się czytać bez analizy diagramu. */
@media (max-width: 62rem) {
  .crm-detail,
  .crm-last,
  .crm-a,
  .crm-c,
  .crm-label:not(.crm-label-hot) { display: none; }
  .crm-cline { stroke-width: 2.4; }
  .crm-cline-quiet { stroke-width: 2; }
}

/* ---------- Mniej ruchu i brak JS ---------- */

@media (prefers-reduced-motion: reduce) {
  .crm-corner,
  .crm-stagepoint,
  .crm-node,
  .crm-dim-cap,
  .crm-index,
  .crm-owner,
  .crm-next,
  .crm-due,
  .crm-lead,
  .crm-stage,
  .crm-label,
  .crm-flag,
  .crm-remind-hot { opacity: 1; }
  .crm-lead { transform: none; }
  .crm-track,
  .crm-stem,
  .crm-dim,
  .crm-auto-line,
  .crm-hook { stroke-dashoffset: 0; }
  .crm-signal,
  .crm-ping { display: none; }

  .is-built .crm-corner,
  .is-built .crm-track,
  .is-built .crm-stagepoint,
  .is-built .crm-stage,
  .is-built .crm-dim,
  .is-built .crm-dim-cap,
  .is-built .crm-index,
  .is-built .crm-auto-line,
  .is-built .crm-node,
  .is-built .crm-hook,
  .is-built .crm-label,
  .is-built .crm-lead,
  .is-built .crm-lead .crm-stem,
  .is-built .crm-lead .crm-owner,
  .is-built .crm-lead .crm-next,
  .is-built .crm-lead .crm-due,
  .is-built .crm-flag,
  .is-built .crm-remind-hot,
  .is-built .crm-signal,
  .is-built .crm-ping { animation: none; }
}

.no-js .crm-corner,
.no-js .crm-stagepoint,
.no-js .crm-node,
.no-js .crm-dim-cap,
.no-js .crm-index,
.no-js .crm-owner,
.no-js .crm-next,
.no-js .crm-due,
.no-js .crm-lead,
.no-js .crm-stage,
.no-js .crm-label,
.no-js .crm-flag,
.no-js .crm-remind-hot { opacity: 1; }
.no-js .crm-lead { transform: none; }
.no-js .crm-track,
.no-js .crm-stem,
.no-js .crm-dim,
.no-js .crm-auto-line,
.no-js .crm-hook { stroke-dashoffset: 0; }
.no-js .crm-signal,
.no-js .crm-ping { display: none; }

/* =====================================================================
   Sales Process Optimization — ścieżka procesu i jej korekta.
   Bohaterem jest kształt drogi, nie pojedynczy lead: żadnych kart,
   sygnały są bezimienne, a naprawa polega na przerysowaniu geometrii.
   Bursztyn znaczy tu: miejsce tarcia, aktywny pomiar i poprawione
   połączenie. Stan końcowy jest prostszy od początkowego.
   ===================================================================== */

.spo-art { aspect-ratio: 700 / 520; }
@media (min-width: 62rem) {
  .hero-service:has(.spo-art) .hero-grid {
    grid-template-columns: minmax(0, 1.06fr) minmax(0, 0.94fr);
  }
  .spo-art { width: calc(100% + clamp(2rem, 5vw, 7rem)); }
}
.spo { width: 100%; height: 100%; mask-image: linear-gradient(90deg, #000 93%, transparent); }

/* ---------- Ścieżka i punkty kontrolne ---------- */

.spo-line {
  stroke: color-mix(in srgb, var(--cyan) 66%, transparent);
  stroke-width: 1.8;
  stroke-linejoin: round;
  stroke-linecap: round;
}
/* Zbędna pętla: znika po korekcie */
.spo-loop {
  stroke: color-mix(in srgb, var(--cyan) 46%, transparent);
  stroke-width: 1.8;
  stroke-linejoin: round;
}
.spo-neck {
  stroke: color-mix(in srgb, var(--cyan) 62%, transparent);
  stroke-width: 1.4;
  opacity: 0;
}
.spo-branch {
  stroke: color-mix(in srgb, var(--cyan) 34%, transparent);
  stroke-width: 1.3;
  stroke-linejoin: round;
}
.spo-park {
  stroke: color-mix(in srgb, var(--off-white) 24%, transparent);
  stroke-width: 1.2;
  fill: none;
  opacity: 0;
}
.spo-parked {
  fill: color-mix(in srgb, var(--cyan) 34%, var(--navy));
  stroke: color-mix(in srgb, var(--cyan) 52%, transparent);
  stroke-width: 1.2;
  opacity: 0;
}

.spo-point circle {
  fill: color-mix(in srgb, var(--cyan) 22%, var(--navy));
  stroke: color-mix(in srgb, var(--cyan) 72%, transparent);
  stroke-width: 1.4;
}
.spo-point path {
  stroke: color-mix(in srgb, var(--cyan) 40%, transparent);
  stroke-width: 1.2;
}

.spo-corner {
  stroke: color-mix(in srgb, var(--cyan) 52%, transparent);
  stroke-width: 1.6;
  stroke-linecap: square;
}
.spo-dim,
.spo-dim-cap,
.spo-index {
  stroke: color-mix(in srgb, var(--cyan) 36%, transparent);
  stroke-width: 1;
}

/* ---------- Pomiar postoju: jedyny bursztyn przed korektą ---------- */

.spo-mline,
.spo-mcap {
  stroke: var(--accent-on-dark);
  stroke-width: 1.2;
}
.spo-dwell { fill: color-mix(in srgb, var(--brass) 78%, transparent); stroke: none; }
.spo-measure { opacity: 0; }

/* ---------- Poprawione przejście ---------- */

.spo-fix {
  stroke: color-mix(in srgb, var(--cyan) 74%, transparent);
  stroke-width: 1.8;
  stroke-linecap: round;
}
.spo-mend {
  fill: var(--accent-on-dark);
  stroke: none;
  opacity: 0;
}
.spo-mend-mark {
  stroke: color-mix(in srgb, var(--brass) 46%, transparent);
  stroke-width: 1.2;
  opacity: 0;
}
.spo-after-dim,
.spo-after-cap {
  stroke: color-mix(in srgb, var(--cyan) 40%, transparent);
  stroke-width: 1;
  opacity: 0;
}
.spo-label-after { color: color-mix(in srgb, var(--off-white) 48%, var(--navy)); }
.spo-mend-ping {
  fill: none;
  stroke: var(--accent-on-dark);
  stroke-width: 1.2;
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
}

/* ---------- Sygnały: bezimienne szanse, nie karty ---------- */

.spo-sig,
.spo-out,
.spo-rest {
  --dash: 0.045;
  /* Miejsce w kolejce przed tarciem. Kazdy sygnal staje we wlasnym,
     wiec odstepy widac, zamiast zlepka jednej dlugiej kreski. */
  --q: 0.348;
  stroke: color-mix(in srgb, var(--cyan) 80%, var(--off-white));
  stroke-width: 2.8;
  stroke-linecap: round;
  stroke-dasharray: var(--dash) 1;
  stroke-dashoffset: var(--dash);
  opacity: 0;
}
.spo-out { stroke: color-mix(in srgb, var(--cyan) 56%, transparent); stroke-width: 2.4; }

/* ---------- Etykiety ---------- */

.spo-stage,
.spo-label {
  position: absolute;
  inset-inline-start: var(--x);
  inset-block-start: var(--y);
  margin: 0;
  transform: translateX(-50%);
  font-family: var(--font-mono);
  font-size: clamp(0.48rem, 1.45cqi, 0.64rem);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  opacity: 0;
}
.spo-stage { color: color-mix(in srgb, var(--off-white) 62%, var(--navy)); }
.spo-stage b { font-weight: 500; color: color-mix(in srgb, var(--off-white) 38%, var(--navy)); }
.spo-label { color: var(--accent-on-dark); }

/* ---------- Stan przed sekwencją ---------- */

.spo-corner,
.spo-point,
.spo-dim-cap,
.spo-index { opacity: 0; }
.spo-line,
.spo-loop,
.spo-branch,
.spo-dim { stroke-dasharray: 1; stroke-dashoffset: 1; }
.spo-fix { stroke-dasharray: 1; stroke-dashoffset: 1; }

/* ---------- Sekwencja: mapowanie, diagnoza, korekta ---------- */

.is-built .spo-corner {
  animation: bp-in 300ms var(--ease-out) forwards;
  animation-delay: calc(var(--i, 0) * 60ms * var(--t));
}
.is-built .spo-line {
  animation: bp-draw 520ms var(--ease-out) forwards;
  animation-delay: calc(var(--i, 0) * 90ms * var(--t));
}
.is-built .spo-loop {
  animation: bp-draw 460ms var(--ease-out) forwards;
  animation-delay: calc(180ms * var(--t));
}
.is-built .spo-neck {
  animation: bp-in 300ms var(--ease-out) forwards;
  animation-delay: calc(560ms * var(--t));
}
.is-built .spo-branch {
  animation: bp-draw 420ms var(--ease-out) forwards;
  animation-delay: calc(760ms * var(--t));
}
.is-built .spo-park {
  animation: bp-in 300ms var(--ease-out) forwards;
  animation-delay: calc(1000ms * var(--t));
}
.is-built .spo-point {
  animation: bp-in 300ms var(--ease-out) forwards;
  animation-delay: calc((400ms + var(--i, 0) * 70ms) * var(--t));
}
.is-built .spo-stage {
  animation: bp-in 320ms var(--ease-out) forwards;
  animation-delay: calc((520ms + var(--i, 0) * 70ms) * var(--t));
}
.is-built .spo-dim {
  animation: bp-draw 340ms var(--ease-out) forwards;
  animation-delay: calc(620ms * var(--t));
}
.is-built .spo-dim-cap,
.is-built .spo-index {
  animation: bp-in 280ms var(--ease-out) forwards;
  animation-delay: calc((620ms + var(--i, 0) * 60ms) * var(--t));
}

/* Sygnały jadą, zwalniają przed tarciem, po korekcie ruszają dalej.
   Kolejka robi się sama: przy tej samej krzywej i stałym odstępie
   startu wolniejszy odcinek zaciska odstępy w przestrzeni. */
.is-built .spo-sig {
  animation: spo-flow 2900ms both;
  animation-delay: calc((700ms + var(--i, 0) * 110ms) * var(--t));
}
.is-built .spo-out {
  animation: spo-filter 900ms var(--ease-out) both;
  animation-delay: calc((880ms + var(--i, 0) * 190ms) * var(--t));
}
.is-built .spo-parked {
  animation: bp-in 320ms var(--ease-out) forwards;
  animation-delay: calc((1740ms + var(--i, 0) * 190ms) * var(--t));
}

/* Diagnoza: pomiar wchodzi, gdy kolejka już stoi */
/* Pomiar znika dokladnie wtedy, gdy korekta sie konczy: inaczej
   bursztynowa linia wisi nad miejscem, ktorego juz nie ma */
.is-built .spo-measure {
  animation: spo-measure 900ms var(--ease-out) forwards;
  animation-delay: calc(1700ms * var(--t));
}
.is-built .spo-label:not(.spo-label-after) {
  animation: spo-measure 900ms var(--ease-out) forwards;
  animation-delay: calc(1760ms * var(--t));
}
/* Korekta: pętla gaśnie, proste przejście się dorysowuje */
.is-built .spo-loop {
  animation:
    bp-draw 460ms var(--ease-out) forwards,
    spo-drop 340ms var(--ease-out) forwards;
  animation-delay: calc(180ms * var(--t)), calc(2000ms * var(--t));
}
.is-built .spo-neck {
  animation:
    bp-in 300ms var(--ease-out) forwards,
    spo-drop 300ms var(--ease-out) forwards;
  animation-delay: calc(560ms * var(--t)), calc(2000ms * var(--t));
}
.is-built .spo-fix {
  animation: bp-draw 380ms var(--ease-out) forwards;
  animation-delay: calc(2100ms * var(--t));
}
.is-built .spo-mend,
.is-built .spo-mend-mark {
  animation: bp-in 340ms var(--ease-out) forwards;
  animation-delay: calc(2400ms * var(--t));
}
/* Ten sam odcinek zmierzony ponownie, juz spokojnie: krotsza linia,
   chlodny blekit zamiast bursztynu */
.is-built .spo-after-dim,
.is-built .spo-after-cap {
  animation: bp-in 380ms var(--ease-out) forwards;
  animation-delay: calc(2440ms * var(--t));
}
.is-built .spo-label-after {
  animation: bp-in 380ms var(--ease-out) forwards;
  animation-delay: calc(2520ms * var(--t));
}

/* Spoczynek: jeden sygnał poprawioną drogą raz na dwanaście sekund
   i krótkie rozjaśnienie poprawionego połączenia zaraz po nim. */
.is-built .spo-rest { animation: ms-travel 12s linear 4.2s infinite; }
.is-built .spo-mend-ping { animation: ms-answer 12s var(--ease-out) 4.9s infinite; }

@keyframes spo-flow {
  0% { stroke-dashoffset: var(--dash); opacity: 0; animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1); }
  3% { opacity: 0.95; }
  20% { stroke-dashoffset: calc(var(--q) * -0.86); animation-timing-function: linear; }
  32% { stroke-dashoffset: calc(var(--q) * -0.96); animation-timing-function: linear; }
  55% { stroke-dashoffset: calc(var(--q) * -1); animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1); }
  92% { stroke-dashoffset: -1; opacity: 0.95; }
  100% { stroke-dashoffset: -1; opacity: 0; }
}
@keyframes spo-filter {
  0% { stroke-dashoffset: var(--dash); opacity: 0; }
  8% { opacity: 0.85; }
  88% { stroke-dashoffset: -1; opacity: 0.85; }
  100% { stroke-dashoffset: -1; opacity: 0; }
}
@keyframes spo-measure {
  0% { opacity: 0; }
  16% { opacity: 1; }
  74% { opacity: 1; }
  100% { opacity: 0; }
}
@keyframes spo-drop {
  to { opacity: 0; }
}

/* ---------- Uproszczenie na telefonie ----------
   Cztery punkty kontrolne, jeden sygnał na ścieżce, jeden odfiltrowany,
   jeden pomiar. Problem i korekta widoczne bez analizy. */
@media (max-width: 62rem) {
  .spo-detail,
  .spo-last,
  .spo-sig-extra { display: none; }
  .spo-line,
  .spo-fix { stroke-width: 2; }
}

/* ---------- Mniej ruchu i brak JS ----------
   Stan po optymalizacji: bez pętli, z poprawionym połączeniem
   i odfiltrowanymi szansami na odgałęzieniu. */

@media (prefers-reduced-motion: reduce) {
  .spo-corner,
  .spo-point,
  .spo-dim-cap,
  .spo-index,
  .spo-stage,
  .spo-park,
  .spo-parked,
  .spo-mend,
  .spo-mend-mark,
  .spo-after-dim,
  .spo-after-cap,
  .spo-label-after { opacity: 1; }
  .spo-line,
  .spo-branch,
  .spo-dim,
  .spo-fix { stroke-dashoffset: 0; }
  .spo-loop,
  .spo-neck,
  .spo-measure,
  .spo-label:not(.spo-label-after),
  .spo-sig,
  .spo-out,
  .spo-rest,
  .spo-mend-ping { display: none; }

  .is-built .spo-corner,
  .is-built .spo-line,
  .is-built .spo-loop,
  .is-built .spo-neck,
  .is-built .spo-branch,
  .is-built .spo-park,
  .is-built .spo-parked,
  .is-built .spo-point,
  .is-built .spo-stage,
  .is-built .spo-dim,
  .is-built .spo-dim-cap,
  .is-built .spo-index,
  .is-built .spo-sig,
  .is-built .spo-out,
  .is-built .spo-measure,
  .is-built .spo-label,
  .is-built .spo-fix,
  .is-built .spo-mend,
  .is-built .spo-mend-mark,
  .is-built .spo-after-dim,
  .is-built .spo-after-cap,
  .is-built .spo-label-after,
  .is-built .spo-rest,
  .is-built .spo-mend-ping { animation: none; }
}

.no-js .spo-corner,
.no-js .spo-point,
.no-js .spo-dim-cap,
.no-js .spo-index,
.no-js .spo-stage,
.no-js .spo-park,
.no-js .spo-parked,
.no-js .spo-mend,
.no-js .spo-mend-mark,
.no-js .spo-after-dim,
.no-js .spo-after-cap,
.no-js .spo-label-after { opacity: 1; }
.no-js .spo-line,
.no-js .spo-branch,
.no-js .spo-dim,
.no-js .spo-fix { stroke-dashoffset: 0; }
.no-js .spo-loop,
.no-js .spo-neck,
.no-js .spo-measure,
.no-js .spo-label:not(.spo-label-after),
.no-js .spo-sig,
.no-js .spo-out,
.no-js .spo-rest,
.no-js .spo-mend-ping { display: none; }

/* =====================================================================
   Microsoft 365 & Cloud — wspólne środowisko pracy.
   Nie chmura i nie ściana ikon: rzut miejsca pracy. Pięć modułów
   dostaje swoje miejsca we wspólnej ramie, strefy mają granicę
   i punkt dostępu, a jeden dokument z trzech kopii staje się
   jedynym źródłem i przechodzi do następnego kroku.
   Bursztyn znaczy tu: źródło, kontrolowane przejście, następne
   działanie. Nigdzie indziej go nie ma.
   ===================================================================== */

.m3-art { aspect-ratio: 576 / 412; }
@media (min-width: 62rem) {
  .hero-service:has(.m3-art) .hero-grid {
    grid-template-columns: minmax(0, 1.06fr) minmax(0, 0.94fr);
  }
  /* Rysunek wychodzi poza kolumnę, ale bez maski: rama ma być domknięta,
     więc prawa krawędź nie może gasnąć */
  .m3-art { width: calc(100% + clamp(1.5rem, 4vw, 5rem)); }
}
.m3 { width: 100%; height: 100%; }
/* Wariant mobilny konstrukcji: ta sama geometria, domknieta wyzej */
.m3-m { display: none; }

/* ---------- Rama środowiska ---------- */

.m3-surface {
  fill: color-mix(in srgb, var(--off-white) 2.5%, transparent);
  stroke: none;
}
.m3-corner {
  stroke: color-mix(in srgb, var(--cyan) 58%, transparent);
  stroke-width: 1.6;
  stroke-linecap: square;
}
.m3-edge {
  stroke: color-mix(in srgb, var(--cyan) 24%, transparent);
  stroke-width: 1;
}

/* ---------- Granica stref i punkty dostępu ----------
   Bezpieczeństwo jako element konstrukcji: obrys, przejście, znacznik
   roli. Bez tarcz i kłódek. */

.m3-zone {
  stroke: color-mix(in srgb, var(--cyan) 30%, transparent);
  stroke-width: 1;
}
.m3-gate {
  fill: color-mix(in srgb, var(--cyan) 20%, var(--navy));
  stroke: color-mix(in srgb, var(--cyan) 72%, transparent);
  stroke-width: 1.4;
}
.m3-gate-lip {
  stroke: color-mix(in srgb, var(--cyan) 52%, transparent);
  stroke-width: 1.4;
}
.m3-gate-quiet {
  fill: var(--navy);
  stroke: color-mix(in srgb, var(--cyan) 44%, transparent);
  stroke-width: 1.2;
}
/* Znaczniki ról: po lewej zespół, po prawej jedno wąskie uprawnienie */
.m3-pip { fill: color-mix(in srgb, var(--cyan) 46%, transparent); stroke: none; }
/* Punkt dostępu odpowiada tylko wtedy, gdy coś przez niego przechodzi */
.m3-gate-ping {
  fill: none;
  stroke: var(--accent-on-dark);
  stroke-width: 1.2;
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
}

/* ---------- Moduły ---------- */

.m3-box {
  stroke: color-mix(in srgb, var(--off-white) 20%, transparent);
  stroke-width: 1;
  fill: color-mix(in srgb, var(--off-white) 3%, transparent);
}
.m3-line {
  stroke: color-mix(in srgb, var(--off-white) 42%, transparent);
  stroke-width: 2;
  stroke-linecap: round;
}
.m3-line-quiet {
  stroke: color-mix(in srgb, var(--off-white) 19%, transparent);
  stroke-width: 1.6;
}
.m3-bar {
  stroke: color-mix(in srgb, var(--cyan) 46%, transparent);
  stroke-width: 2.4;
  stroke-linecap: round;
}
.m3-link {
  stroke: color-mix(in srgb, var(--cyan) 34%, transparent);
  stroke-width: 1.2;
}

/* ---------- Trzy kopie jednego dokumentu ---------- */

.m3-doc rect {
  stroke: color-mix(in srgb, var(--off-white) 34%, transparent);
  stroke-width: 1.2;
  fill: color-mix(in srgb, var(--off-white) 4%, transparent);
}
.m3-doc path {
  stroke: color-mix(in srgb, var(--off-white) 26%, transparent);
  stroke-width: 1.1;
}
.m3-source rect { stroke: color-mix(in srgb, var(--cyan) 74%, transparent); }
/* Krótki błysk rozpoznania duplikatu, potem znika */
.m3-dupe {
  stroke: color-mix(in srgb, var(--cyan) 40%, transparent);
  stroke-width: 1;
  opacity: 0;
}
.m3-strike {
  stroke: color-mix(in srgb, var(--off-white) 20%, transparent);
  stroke-width: 1.1;
}
/* Jedyne oznaczenie źródła: bursztyn pod dokumentem i znacznik w rogu */
.m3-src-mark {
  stroke: var(--accent-on-dark);
  stroke-width: 1.6;
  stroke-linecap: round;
  opacity: 0;
}
.m3-src-tag { fill: var(--accent-on-dark); stroke: none; opacity: 0; }

/* ---------- Kontrolowane przejście do następnego kroku ---------- */

.m3-route {
  stroke: var(--accent-on-dark);
  stroke-width: 1.6;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.m3-node { fill: var(--accent-on-dark); stroke: none; opacity: 0; }
/* Zadanie, które dopisało się samo po przekazaniu dokumentu */
.m3-newrow {
  stroke: color-mix(in srgb, var(--accent-on-dark) 72%, transparent);
  stroke-width: 2;
  stroke-linecap: round;
  opacity: 0;
}
.m3-pulse {
  --dash: 0.05;
  stroke: var(--accent-on-dark);
  stroke-width: 2.6;
  stroke-linecap: round;
  stroke-dasharray: var(--dash) 1;
  stroke-dashoffset: var(--dash);
  opacity: 0;
}

/* ---------- Znaczniki pomiarowe ---------- */

.m3-dim,
.m3-dim-cap,
.m3-index {
  stroke: color-mix(in srgb, var(--cyan) 36%, transparent);
  stroke-width: 1;
}

/* ---------- Etykiety: prawdziwy tekst, nie tekst w SVG ---------- */

.m3-label,
.m3-zone-label {
  position: absolute;
  inset-inline-start: var(--x);
  inset-block-start: var(--y);
  margin: 0;
  transform: translateX(-50%);
  font-family: var(--font-mono);
  font-size: clamp(0.48rem, 1.45cqi, 0.64rem);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  opacity: 0;
}
.m3-label { color: color-mix(in srgb, var(--off-white) 62%, var(--navy)); }
.m3-label-src { color: var(--accent-on-dark); }
.m3-label-gate { color: color-mix(in srgb, var(--off-white) 46%, var(--navy)); }
.m3-zone-label { color: color-mix(in srgb, var(--off-white) 34%, var(--navy)); }

/* ---------- Stan przed sekwencją ----------
   Moduły leżą luzem: odsunięte i przygaszone, nie skurczone. */

.m3-surface,
.m3-corner,
.m3-gate,
.m3-gate-lip,
.m3-gate-quiet,
.m3-pip,
.m3-doc,
.m3-strike,
.m3-dim-cap,
.m3-index { opacity: 0; }
.m3-edge,
.m3-zone,
.m3-dim,
.m3-link,
.m3-route,
.m3-dupe { stroke-dasharray: 1; stroke-dashoffset: 1; }
.m3-mod {
  opacity: 0;
  transform: translate3d(var(--dx, 0px), var(--dy, 0px), 0);
}

/* ---------- Sekwencja: rozproszenie, struktura, dostęp, przekazanie ---------- */

/* 1. Moduły pojawiają się luzem, jeszcze poza swoimi miejscami */
.is-built .m3-mod {
  animation:
    bp-in 320ms var(--ease-out) forwards,
    m3-settle 500ms var(--ease-in-out) forwards;
  animation-delay:
    calc(var(--i, 0) * 60ms * var(--t)),
    calc((780ms + var(--i, 0) * 55ms) * var(--t));
}

/* 2. Rysuje się rama wspólnego środowiska */
.is-built .m3-corner {
  animation: bp-in 300ms var(--ease-out) forwards;
  animation-delay: calc((300ms + var(--i, 0) * 50ms) * var(--t));
}
.is-built .m3-edge {
  animation: bp-draw 480ms var(--ease-out) forwards;
  animation-delay: calc((380ms + var(--i, 0) * 40ms) * var(--t));
}
.is-built .m3-surface {
  animation: bp-in 420ms var(--ease-out) forwards;
  animation-delay: calc(420ms * var(--t));
}

/* 3. Granice stref i punkty dostępu */
.is-built .m3-zone {
  animation: bp-draw 440ms var(--ease-out) forwards;
  animation-delay: calc(700ms * var(--t));
}
.is-built .m3-gate,
.is-built .m3-gate-lip,
.is-built .m3-gate-quiet {
  animation: bp-in 280ms var(--ease-out) forwards;
  animation-delay: calc(820ms * var(--t));
}
.is-built .m3-pip {
  animation: bp-in 280ms var(--ease-out) forwards;
  animation-delay: calc((880ms + var(--i, 0) * 50ms) * var(--t));
}

/* 4. Etykiety i detal konstrukcyjny */
.is-built .m3-label,
.is-built .m3-zone-label {
  animation: bp-in 320ms var(--ease-out) forwards;
  animation-delay: calc((900ms + var(--i, 0) * 55ms) * var(--t));
}
.is-built .m3-dim {
  animation: bp-draw 340ms var(--ease-out) forwards;
  animation-delay: calc(1000ms * var(--t));
}
.is-built .m3-dim-cap,
.is-built .m3-index {
  animation: bp-in 280ms var(--ease-out) forwards;
  animation-delay: calc((1000ms + var(--i, 0) * 60ms) * var(--t));
}

/* 5. Trzy kopie tego samego dokumentu */
.is-built .m3-doc {
  animation: bp-in 300ms var(--ease-out) forwards;
  animation-delay: calc((1080ms + var(--i, 0) * 60ms) * var(--t));
}
/* 6. System rozpoznaje duplikaty: krótki błysk, nie stały obrys */
.is-built .m3-dupe {
  animation: m3-match 640ms var(--ease-out) forwards;
  animation-delay: calc((1240ms + var(--i, 0) * 80ms) * var(--t));
}
/* 7. Zbędne kopie gasną i dostają przekreślenie */
.is-built .m3-copy {
  animation:
    bp-in 300ms var(--ease-out) forwards,
    m3-supersede 340ms var(--ease-out) forwards;
  animation-delay:
    calc((1080ms + var(--i, 0) * 60ms) * var(--t)),
    calc(1500ms * var(--t));
}
.is-built .m3-strike {
  animation: bp-in 300ms var(--ease-out) forwards;
  animation-delay: calc((1540ms + var(--i, 0) * 60ms) * var(--t));
}
/* 8. Zostaje jedno źródło robocze */
.is-built .m3-src-mark,
.is-built .m3-src-tag {
  animation: bp-in 320ms var(--ease-out) forwards;
  animation-delay: calc(1620ms * var(--t));
}
.is-built .m3-label-src {
  animation: bp-in 320ms var(--ease-out) forwards;
  animation-delay: calc(1680ms * var(--t));
}
/* 9. Punkt dostępu przechodzi w stan kontrolowanego przejścia */
.is-built .m3-gate {
  animation:
    bp-in 280ms var(--ease-out) forwards,
    m3-open 320ms var(--ease-out) forwards;
  animation-delay: calc(820ms * var(--t)), calc(1800ms * var(--t));
}
.is-built .m3-label-gate {
  animation: bp-in 320ms var(--ease-out) forwards;
  animation-delay: calc(1820ms * var(--t));
}
/* 10. Dokument przechodzi do następnego działania */
.is-built .m3-route {
  animation: bp-draw 420ms var(--ease-out) forwards;
  animation-delay: calc(1880ms * var(--t));
}
.is-built .m3-node,
.is-built .m3-newrow {
  animation: bp-in 300ms var(--ease-out) forwards;
  animation-delay: calc(2200ms * var(--t));
}
/* 11. Dopiero na końcu widać powiązania modułów, po kolei */
.is-built .m3-link {
  animation: bp-draw 360ms var(--ease-out) forwards;
  animation-delay: calc((2000ms + var(--i, 0) * 70ms) * var(--t));
}

/* Spoczynek: jeden sygnał od dokumentu do zadania raz na trzynaście
   sekund, z krótkim rozjaśnieniem punktu dostępu po drodze. */
.is-built .m3-pulse { animation: ms-travel 13s linear 5s infinite; }
.is-built .m3-gate-ping { animation: ms-answer 13s var(--ease-out) 5.4s infinite; }

@keyframes m3-settle { to { transform: none; } }
@keyframes m3-match {
  0% { stroke-dashoffset: 1; opacity: 0; }
  30% { opacity: 0.8; }
  55% { stroke-dashoffset: 0; opacity: 0.8; }
  100% { stroke-dashoffset: 0; opacity: 0.22; }
}
@keyframes m3-supersede { to { opacity: 0.38; } }
@keyframes m3-open { to { stroke: var(--accent-on-dark); } }

/* ---------- Uproszczenie na telefonie ----------
   Trzy moduły, jedna historia dokumentu, jedna granica uprawnień
   i jedno następne działanie. Bez drobnych etykiet i linii pomiarowych. */
@media (max-width: 62rem) {
  /* Kadr obcina dol rysunku, wiec rama domyka sie nad pusta strefa */
  .m3-art { aspect-ratio: 576 / 280; }
  .m3-detail,
  .m3-far,
  .m3-copy-local,
  .m3-d { display: none; }
  .m3-m { display: block; }
  .m3-line { stroke-width: 2.4; }
  .m3-line-quiet { stroke-width: 2; }
  .m3-route { stroke-width: 2; }

  /* Krotszy kadr, wiec etykiety dostaja wlasne polozenie pionowe */
  .m3-label { inset-block-start: var(--ym, var(--y)); }
}

/* ---------- Mniej ruchu i brak JS ----------
   Od razu stan uporządkowany: źródło oznaczone, kopie wygaszone,
   dostęp kontrolowany, dokument przekazany dalej. */

@media (prefers-reduced-motion: reduce) {
  .m3-surface,
  .m3-corner,
  .m3-gate,
  .m3-gate-lip,
  .m3-gate-quiet,
  .m3-pip,
  .m3-doc,
  .m3-strike,
  .m3-dim-cap,
  .m3-index,
  .m3-label,
  .m3-zone-label,
  .m3-src-mark,
  .m3-src-tag,
  .m3-node,
  .m3-newrow { opacity: 1; }
  .m3-edge,
  .m3-zone,
  .m3-dim,
  .m3-link,
  .m3-route { stroke-dashoffset: 0; }
  .m3-mod { opacity: 1; transform: none; }
  .m3-copy { opacity: 0.38; }
  .m3-gate { stroke: var(--accent-on-dark); }
  .m3-dupe { stroke-dashoffset: 0; opacity: 0.22; }
  .m3-pulse,
  .m3-gate-ping { display: none; }

  .is-built .m3-surface,
  .is-built .m3-corner,
  .is-built .m3-edge,
  .is-built .m3-zone,
  .is-built .m3-gate,
  .is-built .m3-gate-lip,
  .is-built .m3-gate-quiet,
  .is-built .m3-pip,
  .is-built .m3-mod,
  .is-built .m3-link,
  .is-built .m3-doc,
  .is-built .m3-copy,
  .is-built .m3-strike,
  .is-built .m3-src-mark,
  .is-built .m3-src-tag,
  .is-built .m3-route,
  .is-built .m3-node,
  .is-built .m3-newrow,
  .is-built .m3-dim,
  .is-built .m3-dim-cap,
  .is-built .m3-index,
  .is-built .m3-label,
  .is-built .m3-zone-label,
  .is-built .m3-pulse,
  .is-built .m3-gate-ping { animation: none; }
}

.no-js .m3-surface,
.no-js .m3-corner,
.no-js .m3-gate,
.no-js .m3-gate-lip,
.no-js .m3-gate-quiet,
.no-js .m3-pip,
.no-js .m3-doc,
.no-js .m3-strike,
.no-js .m3-dim-cap,
.no-js .m3-index,
.no-js .m3-label,
.no-js .m3-zone-label,
.no-js .m3-src-mark,
.no-js .m3-src-tag,
.no-js .m3-node,
.no-js .m3-newrow { opacity: 1; }
.no-js .m3-edge,
.no-js .m3-zone,
.no-js .m3-dim,
.no-js .m3-link,
.no-js .m3-route { stroke-dashoffset: 0; }
.no-js .m3-mod { opacity: 1; transform: none; }
.no-js .m3-copy { opacity: 0.38; }
.no-js .m3-gate { stroke: var(--accent-on-dark); }
.no-js .m3-dupe { stroke-dashoffset: 0; opacity: 0.22; }
.no-js .m3-pulse,
.no-js .m3-gate-ping { display: none; }

/* =====================================================================
   Ongoing Tech Partnership — kratownica pod stalym nadzorem.
   Konstrukcja stoi i dziala. Sygnal kontrolny przechodzi pasem
   gornym, jedno przeslo bez zastrzalu zbiera coraz wieksze
   obciazenie, wchodzi pomiar, dorysowuje sie jeden zastrzal
   i obciazenie rozklada sie rowniej. Zadnej przebudowy.
   Bursztyn znaczy tu: aktywny pomiar, miejsce do uwagi, wprowadzona
   korekta, potwierdzone usprawnienie.
   ===================================================================== */

.otp-art { aspect-ratio: 598 / 306; }
@media (min-width: 62rem) {
  .hero-service:has(.otp-art) .hero-grid {
    grid-template-columns: minmax(0, 1.12fr) minmax(0, 0.88fr);
  }
  .otp-art { width: calc(100% + clamp(1.5rem, 4vw, 5rem)); }
}
.otp { width: 100%; height: 100%; }
/* Wariant mobilny: te same przesla, krotsza konstrukcja */
.otp-m { display: none; }

/* ---------- Konstrukcja ---------- */

.otp-chord {
  stroke: color-mix(in srgb, var(--cyan) 62%, transparent);
  stroke-width: 1.8;
  stroke-linecap: round;
}
.otp-post {
  stroke: color-mix(in srgb, var(--cyan) 34%, transparent);
  stroke-width: 1.2;
}
.otp-diag {
  stroke: color-mix(in srgb, var(--off-white) 26%, transparent);
  stroke-width: 1.4;
}
/* Korekta zostaje widoczna: to ona jest wartoscia stalej wspolpracy */
.otp-diag-new {
  stroke: color-mix(in srgb, var(--accent-on-dark) 82%, transparent);
  stroke-width: 1.6;
  stroke-linecap: round;
}
.otp-leg {
  stroke: color-mix(in srgb, var(--cyan) 42%, transparent);
  stroke-width: 1.4;
}
.otp-base {
  stroke: color-mix(in srgb, var(--off-white) 12%, transparent);
  stroke-width: 1;
}
.otp-anchor {
  stroke: color-mix(in srgb, var(--cyan) 46%, transparent);
  stroke-width: 1.2;
}
.otp-node {
  fill: color-mix(in srgb, var(--cyan) 22%, var(--navy));
  stroke: color-mix(in srgb, var(--cyan) 70%, transparent);
  stroke-width: 1.4;
  transform-box: fill-box;
  transform-origin: center;
}

/* Kikut pod rozbudowe: miejsce na to, co przyjdzie pozniej */
.otp-stub {
  stroke: color-mix(in srgb, var(--cyan) 20%, transparent);
  stroke-width: 1.2;
  stroke-dasharray: 5 5;
}
.otp-stub-node {
  stroke: color-mix(in srgb, var(--cyan) 30%, transparent);
  stroke-width: 1.2;
  fill: none;
}

/* ---------- Obciazenie przesel ---------- */

.otp-load {
  fill: color-mix(in srgb, var(--cyan) 44%, transparent);
  stroke: none;
  transform-box: fill-box;
  transform-origin: top;
}
.otp-load-hot { fill: color-mix(in srgb, var(--cyan) 66%, transparent); }

/* ---------- Kontrola i korekta ---------- */

.otp-span,
.otp-span-cap {
  stroke: var(--accent-on-dark);
  stroke-width: 1.2;
}
.otp-mark {
  fill: none;
  stroke: var(--accent-on-dark);
  stroke-width: 1.4;
}
.otp-mark-ok { fill: var(--accent-on-dark); stroke: none; }
.otp-mark-ping {
  fill: none;
  stroke: var(--accent-on-dark);
  stroke-width: 1.2;
  transform-box: fill-box;
  transform-origin: center;
}

/* Sygnal kontrolny: jeden, spokojny, nigdy dwa naraz */
.otp-check,
.otp-rest {
  --dash: 0.06;
  stroke: color-mix(in srgb, var(--cyan) 80%, var(--off-white));
  stroke-width: 2.6;
  stroke-linecap: round;
  stroke-dasharray: var(--dash) 1;
  stroke-dashoffset: var(--dash);
  opacity: 0;
}

/* ---------- Znaczniki pomiarowe ---------- */

.otp-dim,
.otp-dim-cap,
.otp-index {
  stroke: color-mix(in srgb, var(--cyan) 32%, transparent);
  stroke-width: 1;
}

/* ---------- Etykiety: prawdziwy tekst, nie tekst w SVG ---------- */

.otp-label {
  position: absolute;
  inset-inline-start: var(--x);
  inset-block-start: var(--y);
  margin: 0;
  transform: translateX(-50%);
  font-family: var(--font-mono);
  font-size: clamp(0.48rem, 1.45cqi, 0.64rem);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  color: color-mix(in srgb, var(--off-white) 58%, var(--navy));
  opacity: 0;
}
.otp-label-ok { color: var(--accent-on-dark); }

/* ---------- Stan przed sekwencja ---------- */

.otp-chord,
.otp-post,
.otp-diag,
.otp-diag-new,
.otp-leg,
.otp-base,
.otp-dim { stroke-dasharray: 1; stroke-dashoffset: 1; }
.otp-node,
.otp-anchor,
.otp-stub,
.otp-stub-node,
.otp-dim-cap,
.otp-index,
.otp-span,
.otp-span-cap,
.otp-mark,
.otp-mark-ok,
.otp-mark-ping,
.otp-label { opacity: 0; }
/* Wskazniki nie startuja z zera, tylko z niskiego stanu */
.otp-load { transform: scaleY(0.12); }

/* ---------- Sekwencja: kontrola, diagnoza, wzmocnienie ---------- */

/* 1. Konstrukcja staje w stanie sprawnym */
.is-built .otp-chord {
  animation: bp-draw 520ms var(--ease-out) forwards;
  animation-delay: calc(var(--i, 0) * 40ms * var(--t));
}
.is-built .otp-post {
  animation: bp-draw 380ms var(--ease-out) forwards;
  animation-delay: calc((120ms + var(--i, 0) * 40ms) * var(--t));
}
.is-built .otp-leg {
  animation: bp-draw 360ms var(--ease-out) forwards;
  animation-delay: calc(320ms * var(--t));
}
.is-built .otp-base {
  animation: bp-draw 420ms var(--ease-out) forwards;
  animation-delay: calc(380ms * var(--t));
}
.is-built .otp-anchor {
  animation: bp-in 300ms var(--ease-out) forwards;
  animation-delay: calc(560ms * var(--t));
}
.is-built .otp-diag {
  animation: bp-draw 460ms var(--ease-out) forwards;
  animation-delay: calc((380ms + var(--i, 0) * 90ms) * var(--t));
}
.is-built .otp-node {
  animation:
    bp-in 300ms var(--ease-out) forwards,
    otp-respond 340ms var(--ease-out) forwards;
  animation-delay:
    calc((620ms + var(--i, 0) * 60ms) * var(--t)),
    calc((880ms + var(--i, 0) * 180ms) * var(--t));
}
.is-built .otp-stub,
.is-built .otp-stub-node {
  animation: bp-in 380ms var(--ease-out) forwards;
  animation-delay: calc(760ms * var(--t));
}
.is-built .otp-label {
  animation: bp-in 320ms var(--ease-out) forwards;
  animation-delay: calc((820ms + var(--i, 0) * 60ms) * var(--t));
}
.is-built .otp-dim {
  animation: bp-draw 340ms var(--ease-out) forwards;
  animation-delay: calc(900ms * var(--t));
}
.is-built .otp-dim-cap,
.is-built .otp-index {
  animation: bp-in 280ms var(--ease-out) forwards;
  animation-delay: calc((900ms + var(--i, 0) * 60ms) * var(--t));
}

/* 2. Obciazenie przesel dochodzi do stanu spoczynkowego */
.is-built .otp-load {
  animation: otp-load-set 520ms var(--ease-out) forwards;
  animation-delay: calc((760ms + var(--i, 0) * 70ms) * var(--t));
}

/* 3. Sygnal kontrolny przechodzi pasem gornym */
.is-built .otp-check {
  animation: otp-scan 900ms linear both;
  animation-delay: calc(700ms * var(--t));
}

/* 4. Jedno przeslo zbiera wiecej, niz powinno */
.is-built .otp-load-hot {
  animation:
    otp-load-set 520ms var(--ease-out) forwards,
    otp-load-strain 420ms var(--ease-out) forwards,
    otp-load-settle 460ms var(--ease-out) forwards;
  animation-delay:
    calc(900ms * var(--t)),
    calc(1250ms * var(--t)),
    calc(1900ms * var(--t));
}

/* 5. Pomiar rozpietosci i znacznik uwagi. Reszta konstrukcji cofa sie
      na moment, zeby bylo widac, o ktore przeslo chodzi. */
.is-built .otp-span,
.is-built .otp-span-cap {
  animation: otp-measure 900ms var(--ease-out) forwards;
  animation-delay: calc(1400ms * var(--t));
}
.is-built .otp-mark {
  animation: otp-measure 1000ms var(--ease-out) forwards;
  animation-delay: calc(1420ms * var(--t));
}
.is-built .otp-recede {
  animation: otp-recede 760ms var(--ease-in-out) forwards;
  animation-delay: calc(1430ms * var(--t));
}

/* 6. Jeden dorysowany zastrzal, potem obciazenie rozklada sie rowniej */
.is-built .otp-diag-new {
  animation: bp-draw 480ms var(--ease-out) forwards;
  animation-delay: calc(1600ms * var(--t));
}
.is-built .otp-load-near {
  animation:
    otp-load-set 520ms var(--ease-out) forwards,
    otp-load-settle 460ms var(--ease-out) forwards;
  animation-delay:
    calc((760ms + var(--i, 0) * 70ms) * var(--t)),
    calc(1950ms * var(--t));
}
.is-built .otp-mark-ok {
  animation: bp-in 320ms var(--ease-out) forwards;
  animation-delay: calc(2000ms * var(--t));
}
.is-built .otp-label-ok {
  animation: bp-in 320ms var(--ease-out) forwards;
  animation-delay: calc(2100ms * var(--t));
}

/* Spoczynek: kolejna kontrola raz na szesnascie sekund i krotka
   odpowiedz potwierdzonego punktu. Poza tym nic sie nie rusza. */
.is-built .otp-rest { animation: ms-travel 16s linear 5.5s infinite; }
.is-built .otp-mark-ping { animation: ms-answer 16s var(--ease-out) 6.6s infinite; }

@keyframes otp-load-set { to { transform: scaleY(var(--l, 0.4)); } }
@keyframes otp-load-strain { to { transform: scaleY(var(--l2, 1)); } }
@keyframes otp-load-settle { to { transform: scaleY(var(--l3, 0.5)); } }
@keyframes otp-scan {
  0% { stroke-dashoffset: var(--dash); opacity: 0; }
  6% { opacity: 0.9; }
  94% { stroke-dashoffset: -1; opacity: 0.9; }
  100% { stroke-dashoffset: -1; opacity: 0; }
}
@keyframes otp-respond {
  0% { opacity: 1; transform: scale(1); }
  40% { opacity: 1; transform: scale(1.22); }
  100% { opacity: 1; transform: scale(1); }
}
@keyframes otp-measure {
  0% { opacity: 0; }
  18% { opacity: 1; }
  70% { opacity: 1; }
  100% { opacity: 0; }
}
@keyframes otp-recede {
  0% { opacity: 1; }
  26% { opacity: 0.45; }
  68% { opacity: 0.45; }
  100% { opacity: 1; }
}

/* ---------- Uproszczenie na telefonie ----------
   Te same pasy i ta sama skala, tylko trzy szersze przesla zamiast
   pieciu. Kadru nie zmieniamy: przy powiekszeniu rysunku kreskowanie
   liczone przez non-scaling-stroke rozjezdza sie z pathLength i linie
   rysuja sie w czesci. */
@media (max-width: 62rem) {
  .otp-detail,
  .otp-d { display: none; }
  .otp-m { display: block; }
  .otp-label { inset-inline-start: var(--xm, var(--x)); }
  .otp-chord { stroke-width: 2.2; }
  .otp-diag,
  .otp-diag-new { stroke-width: 1.8; }
}

/* ---------- Mniej ruchu i brak JS ----------
   Stan po wzmocnieniu: zastrzal na miejscu, znacznik potwierdzony,
   obciazenie wyrownane, zadnych kontroli w tle. */

@media (prefers-reduced-motion: reduce) {
  .otp-chord,
  .otp-post,
  .otp-diag,
  .otp-diag-new,
  .otp-leg,
  .otp-base,
  .otp-dim { stroke-dashoffset: 0; }
  .otp-node,
  .otp-anchor,
  .otp-stub,
  .otp-stub-node,
  .otp-dim-cap,
  .otp-index,
  .otp-mark-ok,
  .otp-label { opacity: 1; }
  .otp-load { transform: scaleY(var(--l3, var(--l, 0.4))); }
  .otp-span,
  .otp-span-cap,
  .otp-mark,
  .otp-mark-ping,
  .otp-check,
  .otp-rest { display: none; }

  .is-built .otp-chord,
  .is-built .otp-post,
  .is-built .otp-diag,
  .is-built .otp-diag-new,
  .is-built .otp-leg,
  .is-built .otp-base,
  .is-built .otp-anchor,
  .is-built .otp-node,
  .is-built .otp-stub,
  .is-built .otp-stub-node,
  .is-built .otp-load,
  .is-built .otp-load-hot,
  .is-built .otp-load-near,
  .is-built .otp-recede,
  .is-built .otp-dim,
  .is-built .otp-dim-cap,
  .is-built .otp-index,
  .is-built .otp-label,
  .is-built .otp-mark-ok,
  .is-built .otp-check,
  .is-built .otp-rest,
  .is-built .otp-mark-ping { animation: none; }
}

.no-js .otp-chord,
.no-js .otp-post,
.no-js .otp-diag,
.no-js .otp-diag-new,
.no-js .otp-leg,
.no-js .otp-base,
.no-js .otp-dim { stroke-dashoffset: 0; }
.no-js .otp-node,
.no-js .otp-anchor,
.no-js .otp-stub,
.no-js .otp-stub-node,
.no-js .otp-dim-cap,
.no-js .otp-index,
.no-js .otp-mark-ok,
.no-js .otp-label { opacity: 1; }
.no-js .otp-load { transform: scaleY(var(--l3, var(--l, 0.4))); }
.no-js .otp-span,
.no-js .otp-span-cap,
.no-js .otp-mark,
.no-js .otp-mark-ping,
.no-js .otp-check,
.no-js .otp-rest { display: none; }
