:root {
  --motion-ease: cubic-bezier(0.77, 0, 0.175, 1);
  --scene-line: #a5bdaa;
  --scene-surface: #d9e7db;
  --scene-shade: #829c88;
  --scene-shadow: #27473526;
  --ribbon-end: #92bba1;
  --scene-highlight: #f3fff8;
  --scene-edge: #5d8870;
  --scene-reflection: #ffffffb8;
}
[data-theme="dark"] {
  --scene-line: #527963;
  --scene-surface: #314b3b;
  --scene-shade: #192b20;
  --scene-shadow: #030b0766;
  --ribbon-end: #294d38;
  --scene-highlight: #c1f5d7;
  --scene-edge: #203e2b;
  --scene-reflection: #d3ffe54d;
}
.motion-scene {
  --motion-state: paused;
  position: relative;
  isolation: isolate;
}
.motion-scene[data-running="true"] {
  --motion-state: running;
}
.motion-toggle {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  flex: 0 0 44px;
  padding: 0;
  margin-left: 18px;
  border: 1px solid var(--rule);
  border-radius: 50%;
  background: transparent;
  color: var(--ink);
}
.motion-toggle .icon {
  width: 17px;
  height: 17px;
}
.motion-toggle:disabled {
  cursor: default;
  opacity: 0.55;
}
.theme-toggle {
  margin-left: 9px;
}
.motion-play {
  display: none;
}
[data-motion="paused"] .motion-play {
  display: block;
}
[data-motion="paused"] .motion-pause {
  display: none;
}
@media (hover: hover) and (pointer: fine) {
  .motion-toggle:hover {
    background: var(--soft);
  }
}

/* The copy is still; only the art and its illumination float. */
.hero-copy,
.hero-art {
  animation: none;
}
.hero-art {
  width: 100%;
}
.hero-float {
  position: relative;
  animation: sculpture-float 5s ease-in-out 0.35s infinite;
}
.hero-light-field {
  position: absolute;
  inset: 8% 2% 13%;
  border-radius: 50%;
  background: radial-gradient(
    ellipse,
    color-mix(in srgb, var(--accent) 17%, transparent),
    transparent 68%
  );
  animation: light-drift 19s var(--motion-ease) infinite alternate;
  pointer-events: none;
}
/* 4.65s of movement followed by a 0.35s hold on every loop. */
@keyframes sculpture-float {
  0%,
  93%,
  100% {
    transform: translate3d(0, 0, 0) rotate(-0.3deg);
  }
  46.5% {
    transform: translate3d(0, -15px, 0) rotate(0.5deg);
  }
}
@keyframes light-drift {
  from {
    transform: translate3d(-5%, 4%, 0) scale(0.95);
    opacity: 0.45;
  }
  to {
    transform: translate3d(8%, -5%, 0) scale(1.08);
    opacity: 1;
  }
}

/* Fragmented operations find a shared structure. */
.perspective {
  grid-template-columns: 1.05fr 1fr;
  align-items: center;
}
.perspective-copy {
  padding-top: 28px;
}
/* ── HOW A FIXED-PIXEL SCENE FITS A FLUID COLUMN ──────────────────────────
   Rewritten 2026-09-16. Every scene below is drawn at a fixed pixel size, and
   every scene sits in a column that is not. The old answer was two independent
   ladders — a min-height ladder on the box and a scale() ladder on the object —
   and because nothing tied them together they disagreed: .assembly-object was
   scaled to 0.8 at 900px and back UP to 0.9 at 680px, so a phone rendered a
   LARGER object inside a SHORTER, overflow:hidden box than a tablet did. That
   is the reported cropping, and it was in the stylesheet as a literal value.

   There are now two patterns, both reading the single --scene-fit token:

     A. Fluid box, fixed object  — the box's min-height is derived from the
        design height times the fit, and the object is scaled by the same fit.
        The box and the thing inside it therefore shrink by exactly the same
        factor and cannot come apart. (assembly, build, anchor)

     B. Fixed box  — the whole box is scaled as a unit and the layout space it
        no longer occupies is given back with negative margins, so the page
        reflows around what the artwork actually covers. (planes)

   Either way there is one number, in one place, and no breakpoint may restate
   it. */
.assembly-scene,
.build-scene {
  min-height: calc(440px * var(--scene-fit));
  display: grid;
  place-items: center;
  overflow: hidden;
}
.scene-wash {
  position: absolute;
  inset: 5%;
  background: radial-gradient(
    ellipse,
    color-mix(in srgb, var(--accent) 13%, transparent),
    transparent 65%
  );
  animation: light-drift 17s var(--motion-ease) infinite alternate;
  pointer-events: none;
}
.assembly-object {
  width: 216px;
  height: 216px;
  position: relative;
  /* Scale first, so the fragments' scattered positions shrink with the object
     rather than after it. At rest they spread to about 470px across once the
     -39deg rotation is applied, which is why the fit floor is 0.55 — that is
     the value at which the widest moment of this scene still clears a 320px
     viewport's gutters. */
  transform: scale(var(--scene-fit)) rotateX(53deg) rotateZ(-39deg);
  transform-style: preserve-3d;
}
.fragment {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: 66px;
  height: 66px;
  border-radius: 4px;
  background:
    linear-gradient(
      125deg,
      var(--scene-reflection),
      transparent 32%,
      transparent 64%,
      #ffffff18 78%,
      transparent
    ),
    linear-gradient(
      150deg,
      var(--scene-surface) 10%,
      var(--scene-line) 58%,
      var(--scene-shade)
    );
  box-shadow:
    inset 0 1px 0 var(--scene-highlight),
    inset 1px 0 0 var(--scene-reflection),
    inset 0 -1px 0 var(--scene-edge),
    1px 2px 0 var(--scene-edge),
    2px 4px 0 var(--scene-shade),
    3px 6px 0 var(--scene-edge),
    5px 9px 8px var(--scene-shadow),
    14px 24px 26px var(--scene-shadow);
  animation: fragments-gather 16s var(--motion-ease) infinite;
  animation-delay: var(--delay);
}
.fragment:nth-child(5) {
  background: linear-gradient(
    135deg,
    var(--scene-highlight),
    var(--accent) 35%,
    var(--scene-edge)
  );
}
.fragment:nth-child(2),
.fragment:nth-child(8) {
  opacity: 0.8;
}
@keyframes fragments-gather {
  0%,
  100% {
    transform: translate3d(var(--dx), var(--dy), 28px);
  }
  35%,
  65% {
    transform: translate3d(0, 0, 0);
  }
}
.scene-caption {
  position: absolute;
  bottom: 20px;
  left: 0;
  right: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 13px;
  color: var(--muted);
  font-size: 11px;
  letter-spacing: 0.01em;
}
.caption-line {
  width: 28px;
  height: 1px;
  background: var(--accent);
}

/* ══ UNREACHABLE SCENES — no markup references any of the four below ══════
   Verified 2026-09-16: grep across every .html file finds no .system-lines,
   .orbit-scene, .automation-example or .workflow-tracer. They are kept rather
   than deleted because removing four interleaved blocks from two stylesheets is
   a change with real regression risk and no visible benefit, and the honest
   trade was to say so instead of doing it quietly.

   ⚠ Each one carries the exact defect corrected on .ribbon-packet further down:
   a pixel-hardcoded trajectory measured against a container whose size is a
   percentage. .flow-packet steps -140px / -15px / 118px along a rail declared
   width:90%; .workflow-tracer steps 81/162/243px down rows whose height is
   never declared; .orbit-satellite translates 92px around a ring of radius 87.
   The author's own workaround was to re-hardcode the pixels inside each media
   query, which is the shape of the bug rather than a fix for it. If any of
   these is revived, give it an offset-path against the geometry it rides — do
   not copy the keyframes. */

/* Business node labels stay put while signals follow their actual routes. */
.system-lines .motion-loop {
  fill: var(--accent);
  stroke: none;
}
.signal-a {
  animation: route-a 12s linear infinite;
}
.signal-b {
  animation: route-b 14s linear infinite;
  animation-delay: -4s;
}
.signal-c {
  animation: route-c 15s linear infinite;
  animation-delay: -8s;
}
.signal-d {
  animation: route-d 13s linear infinite;
  animation-delay: -5s;
}
@keyframes route-a {
  0% {
    transform: translate(100px, 65px);
    opacity: 0;
  }
  10% {
    opacity: 1;
  }
  30% {
    transform: translate(190px, 65px);
  }
  60% {
    transform: translate(190px, 145px);
  }
  85%,
  100% {
    transform: translate(260px, 145px);
    opacity: 0;
  }
}
@keyframes route-b {
  0% {
    transform: translate(420px, 65px);
    opacity: 0;
  }
  10% {
    opacity: 1;
  }
  30% {
    transform: translate(330px, 65px);
  }
  60% {
    transform: translate(330px, 145px);
  }
  85%,
  100% {
    transform: translate(260px, 145px);
    opacity: 0;
  }
}
@keyframes route-c {
  0% {
    transform: translate(100px, 235px);
    opacity: 0;
  }
  10% {
    opacity: 1;
  }
  30% {
    transform: translate(190px, 235px);
  }
  60% {
    transform: translate(190px, 145px);
  }
  85%,
  100% {
    transform: translate(260px, 145px);
    opacity: 0;
  }
}
@keyframes route-d {
  0% {
    transform: translate(420px, 235px);
    opacity: 0;
  }
  10% {
    opacity: 1;
  }
  30% {
    transform: translate(330px, 235px);
  }
  60% {
    transform: translate(330px, 145px);
  }
  85%,
  100% {
    transform: translate(260px, 145px);
    opacity: 0;
  }
}
.system-halo {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 190px;
  height: 82px;
  margin: -41px 0 0 -95px;
  border: 1px solid var(--scene-line);
  border-radius: 12px;
  animation: system-breathe 10s var(--motion-ease) infinite;
}
@keyframes system-breathe {
  0%,
  100% {
    transform: scale(1);
    opacity: 0.25;
  }
  50% {
    transform: scale(1.12);
    opacity: 0.7;
  }
}

/* An orbital field collects information around a stable center. */
.agent-example {
  overflow: hidden;
}
.orbit-scene {
  height: 208px;
  position: relative;
  display: grid;
  place-items: center;
  perspective: 650px;
  margin-bottom: 20px;
}
.orbit-core {
  width: 46px;
  height: 46px;
  border-radius: 50%;
  background:
    radial-gradient(
      ellipse at 30% 22%,
      #ffffffed,
      #ffffff50 9%,
      transparent 28%
    ),
    radial-gradient(circle at 72% 78%, transparent 35%, #091d1255 80%),
    radial-gradient(
      circle at 35% 30%,
      var(--scene-highlight),
      var(--accent) 48%,
      var(--scene-edge) 80%
    );
  box-shadow:
    inset -3px -4px 7px #071e1455,
    inset 1px 1px 2px var(--scene-reflection),
    4px 8px 12px var(--scene-shadow),
    10px 18px 30px var(--scene-shadow);
  animation: core-breathe 12s var(--motion-ease) infinite;
}
.orbit-ring {
  position: absolute;
  width: 174px;
  height: 174px;
  border-radius: 50%;
  border: 1px solid var(--scene-line);
  background: linear-gradient(
    115deg,
    transparent 40%,
    color-mix(in srgb, var(--accent) 9%, transparent)
  );
}
.orbit-one {
  animation: orbit-one 20s linear infinite;
}
.orbit-two {
  width: 145px;
  height: 145px;
  animation: orbit-two 24s linear infinite;
}
.orbit-three {
  width: 195px;
  height: 195px;
  animation: orbit-three 28s linear infinite;
}
.orbit-satellite {
  position: absolute;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
  animation: satellite 18s linear infinite;
}
@keyframes core-breathe {
  0%,
  100% {
    transform: scale(0.94);
  }
  50% {
    transform: scale(1.08);
  }
}
@keyframes orbit-one {
  from {
    transform: rotateZ(-30deg) rotateY(58deg) rotateX(15deg);
  }
  to {
    transform: rotateZ(330deg) rotateY(58deg) rotateX(15deg);
  }
}
@keyframes orbit-two {
  from {
    transform: rotateZ(35deg) rotateY(-55deg) rotateX(25deg);
  }
  to {
    transform: rotateZ(-325deg) rotateY(-55deg) rotateX(25deg);
  }
}
@keyframes orbit-three {
  from {
    transform: rotateX(68deg) rotateZ(0);
  }
  to {
    transform: rotateX(68deg) rotateZ(360deg);
  }
}
@keyframes satellite {
  from {
    transform: rotate(0) translateX(92px);
  }
  to {
    transform: rotate(360deg) translateX(92px);
  }
}

/* Flow packets pause at the central approval gate; station labels don't move. */
.automation-example {
  min-height: 377px;
  padding-top: 242px;
  position: relative;
  overflow: hidden;
}
.automation-field {
  position: absolute;
  top: 20px;
  left: 24px;
  right: 24px;
  height: 198px;
  perspective: 700px;
}
.flow-rail {
  position: absolute;
  width: 90%;
  height: 55px;
  left: 5%;
  top: 84px;
  transform: rotateX(55deg) rotateZ(-15deg);
  border: 1px solid var(--scene-line);
  border-radius: 28px;
}
.flow-packet {
  position: absolute;
  left: 50%;
  top: 82px;
  width: 32px;
  height: 32px;
  border-radius: 5px;
  background: linear-gradient(
    135deg,
    var(--scene-highlight),
    var(--scene-surface) 20%,
    var(--accent) 65%,
    var(--scene-edge)
  );
  box-shadow:
    inset 1px 1px 0 var(--scene-reflection),
    inset -1px -1px 0 var(--scene-edge),
    2px 3px 0 var(--scene-edge),
    4px 6px 0 var(--scene-shade),
    6px 10px 14px var(--scene-shadow);
  animation: packet-route 12s var(--motion-ease) infinite;
}
.packet-two {
  animation-delay: -4s;
  width: 24px;
  height: 24px;
}
.packet-three {
  animation-delay: -8s;
  width: 20px;
  height: 20px;
}
.flow-gate {
  position: absolute;
  left: calc(50% - 26px);
  top: 58px;
  width: 52px;
  height: 89px;
  border: 1px solid var(--accent);
  border-radius: 26px;
  transform: rotateY(35deg) rotateZ(-15deg);
  background: color-mix(in srgb, var(--accent) 5%, transparent);
}
@keyframes packet-route {
  0% {
    transform: translate3d(-140px, 25px, 0) rotate(15deg);
    opacity: 0;
  }
  12% {
    opacity: 1;
  }
  40%,
  57% {
    transform: translate3d(-15px, 0, 0) rotate(-15deg);
    opacity: 1;
  }
  85%,
  100% {
    transform: translate3d(118px, -30px, 0) rotate(15deg);
    opacity: 0;
  }
}

/* The marker is independent from the actual workflow's text and state. */
.workflow-steps .workflow-tracer {
  position: absolute;
  left: 22px;
  top: 36px;
  width: 7px;
  height: 7px;
  min-height: 0;
  padding: 0;
  border-radius: 50%;
  background: #a6debb;
  z-index: 1;
  box-shadow: 0 2px 6px #10171280;
  animation: workflow-travel 14s var(--motion-ease) infinite;
  pointer-events: none;
}
@keyframes workflow-travel {
  0%,
  100% {
    transform: translateY(0);
    opacity: 0;
  }
  8% {
    opacity: 1;
  }
  27% {
    transform: translateY(81px);
  }
  49%,
  68% {
    transform: translateY(162px);
    opacity: 1;
  }
  88% {
    transform: translateY(243px);
    opacity: 1;
  }
  96% {
    transform: translateY(243px);
    opacity: 0;
  }
}

/* A separate sculptural assembly accompanies the still delivery steps. */
.approach-layout {
  display: grid;
  grid-template-columns: 1.35fr 1fr;
  gap: 60px;
  align-items: center;
}
.approach-layout .approach-steps > li {
  grid-template-columns: 36px 1fr;
  gap: 0 20px;
  padding-block: 26px;
}
.approach-layout .approach-deliverable {
  grid-column: 2;
  text-align: left;
}
.approach-layout .approach-steps h3 {
  font-size: 23px;
}
.build-scene {
  min-height: calc(470px * var(--scene-fit));
  background: var(--soft);
  border-radius: 8px;
}
.build-object {
  position: relative;
  width: 210px;
  height: 235px;
  perspective: 900px;
  transform: scale(var(--scene-fit));
}
.build-layer {
  position: absolute;
  left: 15px;
  width: 180px;
  height: 95px;
  border: 1px solid var(--scene-line);
  border-radius: 5px;
  background:
    linear-gradient(
      125deg,
      var(--scene-reflection),
      transparent 32%,
      transparent 64%,
      #ffffff18 78%,
      transparent
    ),
    linear-gradient(
      150deg,
      var(--scene-surface) 10%,
      var(--scene-line) 58%,
      var(--scene-shade)
    );
  box-shadow:
    inset 0 1px 0 var(--scene-highlight),
    inset 1px 0 0 var(--scene-reflection),
    1px 2px 0 var(--scene-edge),
    2px 4px 0 var(--scene-shade),
    3px 6px 0 var(--scene-edge),
    4px 8px 0 var(--scene-shade),
    6px 12px 10px var(--scene-shadow),
    18px 28px 32px var(--scene-shadow);
  transform: rotateX(55deg) rotateZ(-28deg);
}
.build-base {
  top: 150px;
  animation: build-base 16s var(--motion-ease) infinite;
}
.build-middle {
  top: 86px;
  animation: build-middle 16s var(--motion-ease) infinite;
  background:
    linear-gradient(125deg, var(--scene-reflection), transparent 42%),
    linear-gradient(
      145deg,
      var(--scene-surface),
      var(--accent) 65%,
      var(--scene-edge)
    );
}
.build-top {
  top: 22px;
  animation: build-top 16s var(--motion-ease) infinite;
}

@keyframes build-base {
  0%,
  100% {
    transform: translateY(25px) rotateX(55deg) rotateZ(-28deg);
    opacity: 0.5;
  }
  25%,
  75% {
    transform: translateY(0) rotateX(55deg) rotateZ(-28deg);
    opacity: 1;
  }
}
@keyframes build-middle {
  0%,
  100% {
    transform: translate3d(35px, -20px, 0) rotateX(55deg) rotateZ(-28deg);
    opacity: 0.4;
  }
  38%,
  75% {
    transform: translate3d(0, 0, 0) rotateX(55deg) rotateZ(-28deg);
    opacity: 1;
  }
}
@keyframes build-top {
  0%,
  100% {
    transform: translate3d(-35px, -60px, 0) rotateX(55deg) rotateZ(-28deg);
    opacity: 0.3;
  }
  50%,
  75% {
    transform: translate3d(0, 0, 0) rotateX(55deg) rotateZ(-28deg);
    opacity: 1;
  }
}

/* Stable principles, interlocking frames, a still central anchor. */
.anchor-scene {
  height: calc(290px * var(--scene-fit));
  display: grid;
  place-items: center;
  overflow: visible;
  margin-top: 20px;
}
.anchor-object {
  position: relative;
  width: 190px;
  height: 190px;
  perspective: 700px;
  display: grid;
  place-items: center;
  transform: scale(var(--scene-fit));
}
.anchor-frame {
  position: absolute;
  width: 145px;
  height: 145px;
  border: 10px solid var(--scene-line);
  border-radius: 5px;
  transform-style: preserve-3d;
}
.frame-one {
  animation: frame-one 24s linear infinite;
}
.frame-two {
  width: 120px;
  height: 120px;
  border-color: var(--accent);
  animation: frame-two 30s linear infinite;
}
.frame-three {
  width: 180px;
  height: 180px;
  border-width: 1px;
  animation: frame-three 36s linear infinite;
}
.anchor-core {
  width: 30px;
  height: 30px;
  border: 1px solid var(--accent);
  background: var(--accent);
  transform: rotate(45deg);
}
@keyframes frame-one {
  from {
    transform: rotateX(60deg) rotateY(20deg) rotateZ(0);
  }
  to {
    transform: rotateX(60deg) rotateY(20deg) rotateZ(360deg);
  }
}
@keyframes frame-two {
  from {
    transform: rotateX(-25deg) rotateY(58deg) rotateZ(40deg);
  }
  to {
    transform: rotateX(-25deg) rotateY(58deg) rotateZ(400deg);
  }
}
@keyframes frame-three {
  from {
    transform: rotateX(30deg) rotateY(20deg) rotateZ(0);
  }
  to {
    transform: rotateX(30deg) rotateY(20deg) rotateZ(-360deg);
  }
}

/* A stack of translucent planes drifts beside, never over, the FAQ. */
/* Pattern B. The planes are positioned in pixels against a 360x285 stage, so
   the stage is scaled whole and the space it stops occupying is returned to the
   layout — otherwise a 360px-wide box would overflow a 320px phone before any
   scale could help, and the lowest plane (top 70 + drift 60 + height 116 = 246)
   would be clipped by a 240px box. */
.planes-scene {
  width: 360px;
  /* The layout box may never exceed its column, whatever the scale does — a
     transform shrinks what is DRAWN and leaves the rect alone, so scale() on
     its own still pushed a 360px box past a 320px screen and the page scrolled
     sideways. max-width is what stops that; the scale is what stops the planes
     inside being clipped by the shorter box. Both are needed. */
  max-width: 100%;
  height: 285px;
  position: relative;
  margin-top: 35px;
  perspective: 800px;
  overflow: hidden;
  transform: scale(var(--scene-fit));
  transform-origin: top center;
  /* Give back the vertical space the scale no longer occupies, so the FAQ does
     not sit under a band of nothing. */
  margin-bottom: calc(285px * (var(--scene-fit) - 1));
}
.floating-plane {
  position: absolute;
  width: 172px;
  height: 116px;
  left: calc(50% - 86px);
  top: 70px;
  border: 1px solid var(--scene-line);
  border-radius: 5px;
  background: linear-gradient(
    130deg,
    color-mix(in srgb, var(--scene-surface) 80%, transparent),
    color-mix(in srgb, var(--accent) 9%, transparent)
  );
  box-shadow:
    inset 1px 1px 0 var(--scene-reflection),
    inset -1px -1px 0 var(--scene-line),
    1px 2px 0 var(--scene-edge),
    2px 4px 0 var(--scene-line),
    5px 9px 12px var(--scene-shadow),
    12px 22px 30px var(--scene-shadow);
}
.plane-one {
  animation: plane-one 18s var(--motion-ease) infinite;
}
.plane-two {
  animation: plane-two 18s var(--motion-ease) infinite;
}
.plane-three {
  animation: plane-three 18s var(--motion-ease) infinite;
}
.plane-orbit {
  position: absolute;
  width: 235px;
  height: 235px;
  left: calc(50% - 117px);
  top: 20px;
  border: 1px solid var(--scene-line);
  border-radius: 50%;
  opacity: 0.4;
  animation: plane-orbit 24s linear infinite;
}
@keyframes plane-one {
  0%,
  100% {
    transform: translate3d(-20px, -22px, -20px) rotateX(48deg) rotateZ(-28deg);
  }
  50% {
    transform: translate3d(-10px, -42px, -20px) rotateX(48deg) rotateZ(-20deg);
  }
}
@keyframes plane-two {
  0%,
  100% {
    transform: translate3d(0, 15px, 0) rotateX(48deg) rotateZ(-28deg);
  }
  50% {
    transform: translate3d(0, 3px, 0) rotateX(48deg) rotateZ(-24deg);
  }
}
@keyframes plane-three {
  0%,
  100% {
    transform: translate3d(20px, 50px, 20px) rotateX(48deg) rotateZ(-28deg);
  }
  50% {
    transform: translate3d(10px, 60px, 20px) rotateX(48deg) rotateZ(-32deg);
  }
}
@keyframes plane-orbit {
  from {
    transform: rotateY(55deg) rotateX(20deg) rotateZ(0);
  }
  to {
    transform: rotateY(55deg) rotateX(20deg) rotateZ(360deg);
  }
}

/* A continuous geometric ribbon ends the narrative beside the still form. */
.ribbon-scene {
  width: 100%;
  max-width: 440px;
  /* Matched to the viewBox. It used to be 440x235 against a 440x270 drawing,
     so the SVG letterboxed itself into 383x235 and sat inside side bars that
     read as a misaligned scene. The drawing is resolution-independent, so it
     needs no scale factor — only a box the right shape to put it in. */
  aspect-ratio: 440 / 270;
  margin-top: 25px;
  overflow: hidden;
}
.ribbon-art {
  width: 100%;
  height: 100%;
  overflow: visible;
}
/* .ribbon-track removed 2026-09-16. It was a hairline guide drawn from the same
   path data as the ribbon but OUTSIDE the suspended group, so it rendered as a
   faint rectangle hanging a couple of dozen pixels off the ribbon it was meant
   to describe — the visible form of the packet bug corrected below, and the
   thing a viewer actually saw when the dot appeared to travel along a route of
   its own. With the packet riding the ribbon's own geometry there is no rail
   left to draw. */
.ribbon-loop {
  transform-origin: 220px 135px;
  animation: ribbon-tip 20s linear infinite;
}
.ribbon-loop path {
  fill: none;
  stroke: url(#ribbon-green);
  stroke-width: 16;
  stroke-linejoin: bevel;
  opacity: 0.85;
}
/* ── THE PACKET RIDES THE RIBBON ──────────────────────────────────────────
   Corrected 2026-09-16. It did neither of the two things it looked like it was
   doing, and the two faults compounded.

   SUPERSEDED, kept so the change reads as a change: the packet was a sibling of
   .ribbon-loop animated by its own @keyframes ribbon-travel, a list of pixel
   waypoints. Two consequences.

   1. WRONG SPACE. .ribbon-loop is continuously re-transformed by
      ribbon-suspend — translateY(0 to -16px) skewY(-12deg to 8deg)
      scale(0.9 to 0.96) about (220,135). The packet inherited none of it, so it
      traced the *untransformed* path while the visible ribbon was somewhere
      else: about 26px away at rest in a 440-unit viewBox, and that gap swung as
      the skew ran. The two clocks were 20s linear against 18s eased, so they
      never phase-locked either — there was no moment at which they agreed.

   2. WRONG ROUTE. The waypoints went (355,195) to (175,195) to (55,195), along
      the bottom. The path goes H55 at y=65, along the TOP. The packet skipped
      the upper-left arm of the figure-eight entirely and travelled over open
      space instead. Its percentages were not arc-length proportional either, so
      it changed speed at every corner for no reason a viewer could see.

   Both are fixed by removing the second description of the route rather than
   correcting it. The packet is now a CHILD of .ribbon-loop, so the suspend
   transform reaches it by inheritance and cannot be forgotten; and its
   trajectory is offset-path with the ribbon's own "d", so the route is the
   geometry, not a copy of it. Edit the path and the packet follows. */
.ribbon-packet {
  fill: var(--accent);
  offset-path: path("M55 195H175V65H355V195H175V65H55Z");
  /* A disc: rotating it with the tangent would be invisible work, and on the
     vertical arms it would read as a wobble. */
  offset-rotate: 0deg;
  animation: ribbon-roll 20s linear infinite;
}
/* A quiet halo so the packet reads as sitting on the ribbon rather than in
   front of it. Sized in user units, so it scales with the drawing. */
.ribbon-packet-halo {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.5;
  opacity: 0.32;
  offset-path: path("M55 195H175V65H355V195H175V65H55Z");
  offset-rotate: 0deg;
  animation: ribbon-roll 20s linear infinite;
}
/* ── A BOARD TIPPED THE WAY THE BALL IS GOING ──────────────────────────────
   GENERATED by tools/ribbon-motion.mjs — re-run it rather than hand-editing.
   Both blocks come from one description of the shape, because two hand-written
   lists have now disagreed three times: the packet first traced the
   untransformed path while the ribbon was skewed elsewhere; then it was glued
   to the ribbon but circulated on a clock of its own; then it was confined to
   the bottom rail and never saw the rest of the shape.

   ⚠ IT CANNOT BE DOWNHILL ALL THE WAY ROUND, and that is geometry rather than
   an excuse. The path is a figure-eight whose eight segments run
   right/up/right/down/left/up/left/down; under any rigid rotation a segment is
   downhill for only a 175-degree arc of tilt, and threading all eight in travel
   order needs 633 DEGREES of turn per circuit — nearly two full spins of the
   mark. tools/ribbon-motion.mjs carries that arithmetic as a runnable function.
   A brand mark that spins twice a minute is a loading indicator, so the model
   is a marble maze instead: the board is tipped the way the marble should go,
   and gravity still taxes the climbs.

   THE LEAN follows the direction of travel. skewY>0 lowers the right; scaleY>1
   lowers the near edge; scaleY<1 tips the far edge away and foreshortens it,
   which is what travelling up the screen means on a plate.

     s1  time   0.0%..  8.1%  right        skewY  11  scaleY 1.00  (120u in 8.1% of the clock)
     s2  time   8.1%.. 19.3%  up (away)    skewY   0  scaleY 0.87  (130u in 11.2% of the clock)
     s3  time  19.3%.. 40.3%  right        skewY  11  scaleY 1.00  (180u in 21.0% of the clock)
     s4  time  40.3%.. 51.5%  down (near)  skewY   0  scaleY 1.13  (130u in 11.2% of the clock)
     s5  time  51.5%.. 63.7%  left         skewY -11  scaleY 1.00  (180u in 12.2% of the clock)
     s6  time  63.7%.. 74.8%  up (away)    skewY   0  scaleY 0.87  (130u in 11.2% of the clock)
     s7  time  74.8%.. 88.8%  left         skewY -11  scaleY 1.00  (120u in 14.0% of the clock)
     s8  time  88.8%..100.0%  down (near)  skewY   0  scaleY 1.13  (130u in 11.2% of the clock)

   THE SPEED is energy over the rail's own height, integrated — not an easing
   curve picked to look busy. The ball is quickest along the bottom and slowest
   along the top, which is why the top segments occupy far more of the clock
   than their length. VTOP=0.58 keeps it from stalling up there.

   ⚠ ONE DURATION, 22s, for both, and the float is inside these
   keyframes rather than beside them. Two clocks drift out of phase over minutes
   rather than instantly, which is the harder version of this bug to notice. */
@keyframes ribbon-tip {
  0%,
  100% {
    transform: translateY(0.00px) scaleY(1.059) skewY(5.98deg) scale(0.94);
  }
  4.067% {
    transform: translateY(-2.27px) scaleY(1.000) skewY(11.00deg) scale(0.94);
  }
  12.981% {
    transform: translateY(-6.55px) scaleY(0.870) skewY(0.00deg) scale(0.94);
  }
  29.803% {
    transform: translateY(-8.59px) scaleY(1.000) skewY(11.00deg) scale(0.94);
  }
  46.624% {
    transform: translateY(-1.89px) scaleY(1.130) skewY(0.00deg) scale(0.94);
  }
  57.572% {
    transform: translateY(4.12px) scaleY(1.000) skewY(-11.00deg) scale(0.94);
  }
  68.520% {
    transform: translateY(8.26px) scaleY(0.870) skewY(0.00deg) scale(0.94);
  }
  81.836% {
    transform: translateY(8.18px) scaleY(1.000) skewY(-11.00deg) scale(0.94);
  }
  95.152% {
    transform: translateY(2.70px) scaleY(1.130) skewY(0.00deg) scale(0.94);
  }
}

@keyframes ribbon-roll {
  0.000% {
    offset-distance: 0.000%;
  }
  1.898% {
    offset-distance: 2.500%;
  }
  3.795% {
    offset-distance: 5.000%;
  }
  5.693% {
    offset-distance: 7.500%;
  }
  7.591% {
    offset-distance: 10.000%;
  }
  9.525% {
    offset-distance: 12.500%;
  }
  11.614% {
    offset-distance: 15.000%;
  }
  13.913% {
    offset-distance: 17.500%;
  }
  16.500% {
    offset-distance: 20.000%;
  }
  19.520% {
    offset-distance: 22.500%;
  }
  22.791% {
    offset-distance: 25.000%;
  }
  26.063% {
    offset-distance: 27.500%;
  }
  29.335% {
    offset-distance: 30.000%;
  }
  32.607% {
    offset-distance: 32.500%;
  }
  35.879% {
    offset-distance: 35.000%;
  }
  39.151% {
    offset-distance: 37.500%;
  }
  42.296% {
    offset-distance: 40.000%;
  }
  44.987% {
    offset-distance: 42.500%;
  }
  47.358% {
    offset-distance: 45.000%;
  }
  49.502% {
    offset-distance: 47.500%;
  }
  51.472% {
    offset-distance: 50.000%;
  }
  53.370% {
    offset-distance: 52.500%;
  }
  55.268% {
    offset-distance: 55.000%;
  }
  57.165% {
    offset-distance: 57.500%;
  }
  59.063% {
    offset-distance: 60.000%;
  }
  60.961% {
    offset-distance: 62.500%;
  }
  62.859% {
    offset-distance: 65.000%;
  }
  64.779% {
    offset-distance: 67.500%;
  }
  66.843% {
    offset-distance: 70.000%;
  }
  69.108% {
    offset-distance: 72.500%;
  }
  71.647% {
    offset-distance: 75.000%;
  }
  74.593% {
    offset-distance: 77.500%;
  }
  77.863% {
    offset-distance: 80.000%;
  }
  81.135% {
    offset-distance: 82.500%;
  }
  84.407% {
    offset-distance: 85.000%;
  }
  87.679% {
    offset-distance: 87.500%;
  }
  90.824% {
    offset-distance: 90.000%;
  }
  93.515% {
    offset-distance: 92.500%;
  }
  95.886% {
    offset-distance: 95.000%;
  }
  98.029% {
    offset-distance: 97.500%;
  }
  100.000% {
    offset-distance: 100.000%;
  }
}

/* Resolution-independent surface detail rides with the existing objects. */
.fragment::after,
.build-layer::after,
.floating-plane::after {
  content: "";
  position: absolute;
  inset: 7px;
  border: 1px solid var(--scene-reflection);
  border-right-color: var(--scene-line);
  border-bottom-color: var(--scene-line);
  border-radius: 2px;
  pointer-events: none;
}
.build-layer::before {
  content: "";
  position: absolute;
  inset: 17px;
  background:
    repeating-linear-gradient(
      90deg,
      transparent 0 23px,
      var(--scene-line) 23px 24px
    ),
    repeating-linear-gradient(
      0deg,
      transparent 0 23px,
      var(--scene-line) 23px 24px
    );
  opacity: 0.35;
  pointer-events: none;
}
.orbit-ring {
  box-shadow:
    inset 0 1px 0 var(--scene-reflection),
    0 1px 0 var(--scene-edge);
  background: linear-gradient(
    115deg,
    transparent 28%,
    var(--scene-reflection) 49%,
    transparent 51%,
    color-mix(in srgb, var(--accent) 12%, transparent) 85%
  );
}
.orbit-ring::after {
  content: "";
  position: absolute;
  inset: 5px;
  border: 1px solid var(--scene-line);
  border-radius: inherit;
  opacity: 0.4;
}
.orbit-satellite {
  background: radial-gradient(
    circle at 30% 25%,
    var(--scene-highlight),
    var(--accent) 55%,
    var(--scene-edge)
  );
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 10%, transparent);
}
.flow-rail {
  box-shadow:
    inset 0 1px 0 var(--scene-reflection),
    0 2px 0 var(--scene-edge),
    0 7px 14px var(--scene-shadow);
  background: linear-gradient(
    0deg,
    transparent,
    color-mix(in srgb, var(--scene-surface) 40%, transparent)
  );
}
.flow-gate {
  box-shadow:
    inset 2px 0 0 var(--scene-reflection),
    2px 0 0 var(--scene-edge),
    4px 0 0 var(--scene-line),
    8px 4px 14px var(--scene-shadow);
  background: linear-gradient(
    110deg,
    var(--scene-reflection),
    transparent 30%,
    transparent 65%,
    color-mix(in srgb, var(--accent) 20%, transparent)
  );
}
.flow-packet::after {
  content: "";
  position: absolute;
  inset: 5px;
  border: 1px solid var(--scene-reflection);
  border-radius: 2px;
}
.anchor-frame {
  box-shadow:
    inset 1px 1px 0 var(--scene-highlight),
    inset -2px -2px 0 var(--scene-edge),
    1px 1px 0 var(--scene-reflection),
    3px 4px 0 var(--scene-edge),
    7px 10px 14px var(--scene-shadow);
}
.frame-three {
  box-shadow: 0 1px 0 var(--scene-reflection);
}
.anchor-core {
  background: linear-gradient(
    135deg,
    var(--scene-highlight),
    var(--accent) 45%,
    var(--scene-edge)
  );
  box-shadow:
    inset 1px 1px 0 var(--scene-reflection),
    3px 3px 0 var(--scene-edge),
    7px 8px 12px var(--scene-shadow);
}
.system-halo {
  box-shadow:
    inset 0 0 12px color-mix(in srgb, var(--accent) 8%, transparent),
    0 0 0 5px color-mix(in srgb, var(--accent) 4%, transparent);
}
.system-lines .signal-aura {
  opacity: 0.14;
}
.system-lines .signal-core {
  fill: var(--scene-highlight);
}
.workflow-steps .workflow-tracer {
  background: radial-gradient(circle at 35% 30%, #f1fff6, #a6debb 50%, #599d73);
  box-shadow:
    0 0 0 3px #a6debb14,
    0 0 10px #a6debb40;
}
.ribbon-loop .ribbon-depth {
  stroke: var(--scene-edge);
  stroke-width: 18;
  opacity: 1;
  transform: translate(3px, 5px);
}
.ribbon-loop .ribbon-highlight {
  stroke: var(--scene-highlight);
  stroke-width: 1;
  opacity: 0.75;
  transform: translate(-5px, -5px);
}
.ribbon-loop .ribbon-face {
  opacity: 1;
}

/* CSS owns the timeline; JS only decides whether a visible scene may run. */
.motion-scene .motion-loop {
  animation-play-state: var(--motion-state, paused);
}
@media (max-width: 1100px) {
  .approach-layout {
    gap: 30px;
    grid-template-columns: 1.2fr 1fr;
  }
}
@media (max-width: 900px) {
  #primary-nav {
    gap: 17px;
  }
  .motion-toggle {
    margin-left: 12px;
  }
  .perspective {
    gap: 25px;
  }
  .approach-layout {
    gap: 25px;
  }
  .approach-layout .approach-steps h3 {
    font-size: 21px;
  }
}
@media (max-width: 680px) {
  .header-inner .brand {
    font-size: 22px;
    gap: 7px;
  }
  .header-inner .brand svg {
    width: 24px;
    height: 24px;
  }
  .motion-toggle {
    order: 1;
    margin-left: auto;
    margin-right: 0;
  }
  .theme-toggle {
    order: 2;
    margin-left: 5px;
    margin-right: 5px;
  }
  .menu-toggle {
    order: 3;
  }
  #primary-nav {
    order: 4;
  }
  .assembly-scene {
    margin-top: 20px;
  }
  .perspective-copy {
    padding-top: 25px;
  }
  .scene-caption {
    bottom: 10px;
  }
  .orbit-scene {
    height: 190px;
  }
  .automation-example {
    min-height: 360px;
    padding-top: 232px;
  }
  .approach-layout {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 30px;
  }
  .build-scene .scene-caption {
    bottom: 20px;
  }
  .workflow-steps .workflow-tracer {
    left: 18px;
  }
  @keyframes workflow-travel {
    0%,
    100% {
      transform: translateY(0);
      opacity: 0;
    }
    8% {
      opacity: 1;
    }
    27% {
      transform: translateY(76px);
    }
    49%,
    68% {
      transform: translateY(152px);
      opacity: 1;
    }
    88% {
      transform: translateY(228px);
      opacity: 1;
    }
    96% {
      transform: translateY(228px);
      opacity: 0;
    }
  }
}
@media (max-width: 360px) {
  .header-inner .brand {
    font-size: 19px;
    gap: 5px;
  }
  .header-inner .brand svg {
    width: 21px;
    height: 21px;
  }
  .motion-toggle,
  .theme-toggle,
  .nav-enhanced .menu-toggle {
    width: 44px;
    flex-basis: 44px;
  }
  .theme-toggle {
    margin-inline: 3px;
  }
  .header-inner {
    padding-inline: 16px;
  }
  .flow-packet {
    animation-name: packet-route-small;
  }
  @keyframes packet-route-small {
    0% {
      transform: translate(-110px, 25px);
      opacity: 0;
    }
    12% {
      opacity: 1;
    }
    40%,
    57% {
      transform: translate(-15px, 0);
      opacity: 1;
    }
    85%,
    100% {
      transform: translate(85px, -25px);
      opacity: 0;
    }
  }
}
@media (prefers-reduced-motion: reduce) {
  .motion-scene .motion-loop {
    animation: none !important;
  }
  .orbit-one {
    transform: rotateZ(-30deg) rotateY(58deg);
  }
  .orbit-two {
    transform: rotateZ(35deg) rotateY(-55deg);
  }
  .orbit-three {
    transform: rotateX(68deg);
  }
  .frame-one {
    transform: rotateX(60deg) rotateY(20deg);
  }
  .frame-two {
    transform: rotateX(-25deg) rotateY(58deg) rotateZ(40deg);
  }
  .frame-three {
    transform: rotateX(30deg) rotateY(20deg);
  }
  .plane-one {
    transform: translateY(-22px) rotateX(48deg) rotateZ(-28deg);
  }
  .plane-two {
    transform: translateY(15px) rotateX(48deg) rotateZ(-28deg);
  }
  .plane-three {
    transform: translateY(50px) rotateX(48deg) rotateZ(-28deg);
  }
  .ribbon-loop {
    transform: skewY(-10deg) scale(0.9);
  }
  .ribbon-packet,
  .workflow-tracer,
  .system-lines .motion-loop {
    opacity: 0;
  }
  .flow-packet {
    transform: translateX(-60px);
  }
  .packet-two {
    transform: translateX(0);
  }
  .packet-three {
    transform: translateX(65px);
  }
}
