/* World 1 · storytelling motion layer (Agent 1, wave 2). All motion CSS lives here, never in style.css.
   Scope: the conversion block only (section.cta on the homepage, /contact, /cases, /about).
   Rules of the house:
   - the resting state is always the approved design. Every effect here is additive, so if the
     trigger never fires the section still reads exactly as designed.
   - transform, opacity and SVG stroke only. Nothing here can move a box.
   - injected helpers are .mo-* and always aria-hidden, absolutely positioned, pointer-events:none.
   - prefers-reduced-motion:reduce lands every element in its final state with no sequencing. */

/* ============================================================ 1. CTA status items
   Each .cta-points li keeps its neutral glass marker (.ic-r). motion.js injects an
   aria-hidden svg inside it that resolves to an orange check: the marker fills, then the
   check draws. Absolutely positioned over the marker, so the bullet list never reflows.
   Stagger comes from --mo-d, written per li by motion.js (0ms / 350ms / 700ms). */
.cta .cta-points .ic-r { position: relative; }
.cta .cta-points .mo-tick { position: absolute; left: -1.4px; top: -1.4px; width: 18px; height: 18px; pointer-events: none; }
.cta .cta-points .mo-tick-fill { fill: rgba(255, 255, 255, .94); opacity: 0; }  /* r=9 covers the whole marker, so the rim never peeks through unevenly */
.cta .cta-points .mo-tick-path {
  fill: none; stroke: var(--w1-orange, #FF5A1F); stroke-width: 1.9;
  stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 1; stroke-dashoffset: 1;                 /* path carries pathLength="1" */
}
.cta .cta-points.mo-in .mo-tick-fill {
  opacity: 1;
  transition: opacity .26s var(--ease, cubic-bezier(.22,.9,.3,1));
  transition-delay: var(--mo-d, 0ms);
}
.cta .cta-points.mo-in .mo-tick-path {
  stroke-dashoffset: 0;
  transition: stroke-dashoffset .42s var(--ease, cubic-bezier(.22,.9,.3,1));
  transition-delay: calc(var(--mo-d, 0ms) + 90ms);           /* the fill leads, the check follows */
}

/* ============================================================ 2. testimonial stars
   The five stars resolve left to right, opacity only, once. Secondary to everything else.
   .mo-armed is added by motion.js at the same moment it starts observing, so the stars are
   never hidden unless the sequence is actually going to run. */
.cta .cta-quote.mo-armed .mo-star { opacity: 0; }
.cta .cta-quote.mo-armed.mo-in .mo-star {
  opacity: 1;
  transition: opacity .34s var(--ease, cubic-bezier(.22,.9,.3,1));
  transition-delay: var(--mo-d, 0ms);
}

/* ============================================================ 3. intake form: light through the glass
   One aria-hidden helper per text field, clipped to the field box, carrying a soft azure band
   that travels across on focus. Transform inside an overflow:hidden helper, so nothing escapes
   and nothing shifts. Field geometry (--mo-fh / --mo-fr) is written by motion.js on focus. */
.cta .cta-form label { position: relative; }
.cta .cta-form label > .mo-glass {
  position: absolute; left: 0; right: 0; bottom: 0;
  height: var(--mo-fh, 44px); border-radius: var(--mo-fr, 14px);
  overflow: hidden; pointer-events: none; opacity: 0;
  transition: opacity .18s linear;
}
.cta .cta-form label > .mo-glass::after {
  content: ""; position: absolute; top: 0; bottom: 0; width: 46%;
  transform: translateX(-150%);
  background: linear-gradient(100deg, rgba(150,200,255,0) 0%, rgba(146,196,255,.30) 42%, rgba(120,178,255,.24) 60%, rgba(150,200,255,0) 100%);
}
.cta .cta-form label:focus-within > .mo-glass { opacity: 1; }
.cta .cta-form label:focus-within > .mo-glass::after { animation: moGlassSweep 1s var(--ease, cubic-bezier(.22,.9,.3,1)) both; }
@keyframes moGlassSweep { from { transform: translateX(-150%); } to { transform: translateX(250%); } }

/* a tiny orange acknowledgement on the chip that was just chosen: one ring, out in .62s.
   .mo-ack is added on change and removed again, so the resting checked state stays as designed. */
@keyframes moChipAck {
  from { box-shadow: 0 0 0 0 rgba(255, 90, 31, .42); }
  to   { box-shadow: 0 0 0 5px rgba(255, 90, 31, 0); }
}
.cta .chips label.mo-ack input:checked { animation: moChipAck .62s var(--ease, cubic-bezier(.22,.9,.3,1)) both; }

/* ============================================================ reduced motion
   Final state, immediately, no sequencing, no injected animation. */
@media (prefers-reduced-motion: reduce) {
  .cta .cta-points .mo-tick-fill { opacity: 1; }
  .cta .cta-points .mo-tick-path { stroke-dashoffset: 0; }
  .cta .cta-points .mo-tick-fill,
  .cta .cta-points .mo-tick-path,
  .cta .cta-quote .mo-star { transition: none !important; }
  .cta .cta-quote.mo-armed .mo-star,
  .cta .cta-quote.mo-armed.mo-in .mo-star { opacity: 1; }
  .cta .cta-form label > .mo-glass { display: none; }
  .cta .chips label.mo-ack input:checked { animation: none; }
}

/* ============================================================ 4. comparison: identify, then resolve
   Resting design (red X on Before, white disc + green check on After) lives in style.css and is the
   default. motion.js arms each list (.mo-armed) into the pre-state: a faint neutral ring, strokes not
   yet drawn, the line at 72% ink. Then .mo-in on the list runs the items one by one through --mo-d
   (0 / 280 / 560 / 840ms). The After list is flipped by motion.js only after the Before list has
   finished plus a short pause, so the narrative reads: problems identified, then resolved.
   Text responds by colour, not opacity, so the icon (a sibling, own strokes) is never dimmed with it. */
.cmp-card ul.mo-armed li { color: rgba(36, 36, 36, .72); transform: translateY(2px); }
.cmp-after ul.mo-armed li { color: rgba(255, 255, 255, .72); }
.cmp-card ul.mo-armed .cmp-ic-ring { stroke: rgba(15, 23, 42, .16); fill: rgba(15, 23, 42, 0); }
.cmp-after ul.mo-armed .cmp-ic-ring { stroke: rgba(255, 255, 255, .5); fill: rgba(255, 255, 255, 0); }
.cmp-card ul.mo-armed .cmp-ic path { stroke-dashoffset: 1; }

.cmp-card ul.mo-armed.mo-in li {
  color: var(--ink, #242424); transform: translateY(0);
  transition: color .4s var(--ease, cubic-bezier(.22,.9,.3,1)), transform .4s var(--ease, cubic-bezier(.22,.9,.3,1));
  transition-delay: calc(var(--mo-d, 0ms) + 180ms);
}
.cmp-after ul.mo-armed.mo-in li { color: #fff; }
/* the strokes draw first: X = two short strokes 110ms apart, check = one path */
.cmp-card ul.mo-armed.mo-in .cmp-ic path {
  stroke-dashoffset: 0;
  transition: stroke-dashoffset .2s var(--ease, cubic-bezier(.22,.9,.3,1));
  transition-delay: var(--mo-d, 0ms);
}
.cmp-card ul.mo-armed.mo-in .cmp-ic-s2 { transition-delay: calc(var(--mo-d, 0ms) + 110ms); }
.cmp-after ul.mo-armed.mo-in .cmp-ic path { transition-duration: .28s; }
/* then the ring settles into its colour */
.cmp-before ul.mo-armed.mo-in .cmp-ic-ring {
  stroke: rgba(230, 83, 75, .34); fill: rgba(230, 83, 75, .07);
  transition: stroke .32s var(--ease, cubic-bezier(.22,.9,.3,1)), fill .32s var(--ease, cubic-bezier(.22,.9,.3,1));
  transition-delay: calc(var(--mo-d, 0ms) + 220ms);
}
.cmp-after ul.mo-armed.mo-in .cmp-ic-ring {
  stroke: rgba(255, 255, 255, .95); fill: rgba(255, 255, 255, .94);
  transition: stroke .32s var(--ease, cubic-bezier(.22,.9,.3,1)), fill .32s var(--ease, cubic-bezier(.22,.9,.3,1));
  transition-delay: calc(var(--mo-d, 0ms) + 200ms);
}

/* ============================================================ 5. web design card: a physical object
   Everything here is additive to the .svc-glass material in style.css. Pointer-driven parts are gated
   on a real hover device; motion.js writes --px/--py (image parallax, max ±4/±3px), --ps (image scale)
   and --sx/--sy (specular position) through a damped loop, and only while the card is hovered. */
@media (hover: hover) and (pointer: fine) {
  .svc-glass {
    transition: transform .45s var(--ease, cubic-bezier(.22,.9,.3,1)), box-shadow .45s var(--ease, cubic-bezier(.22,.9,.3,1));
  }
  .svc-glass:hover {
    transform: translateY(-3px);
    box-shadow: inset 0 1px 0 rgba(255,255,255,.95), inset 0 0 0 1px rgba(255,255,255,.7), 0 0 0 1px rgba(150,200,255,.34),
      inset 0 -22px 46px -34px rgba(120,84,24,.10), 0 30px 70px rgba(6,26,54,.11), 0 0 34px rgba(120,185,255,.16);
  }
  .svc-glass::before { transition: opacity .45s var(--ease, cubic-bezier(.22,.9,.3,1)); }
  .svc-glass:hover::before { opacity: 1; }
  /* image: slow scale + damped parallax, both through the same transform so they never fight */
  .svc-glass .svc-media > img {
    will-change: transform;
    transform: translate3d(var(--px, 0px), var(--py, 0px), 0) scale(var(--ps, 1));
  }
  .svc-glass .svc-media > img { transition: filter .6s var(--ease, cubic-bezier(.22,.9,.3,1)); }
  .svc-glass:hover .svc-media > img { filter: saturate(1.05) brightness(1.015); }
  /* the orange panel answers, barely */
  .svc-glass .svc-media::before { transition: opacity .7s var(--ease, cubic-bezier(.22,.9,.3,1)); }
  .svc-glass:hover .svc-media::before { opacity: 1; }
  /* one specular band moving across the glass with the cursor: a band, not a spotlight */
  .svc-glass .svc-media > .mo-spec {
    position: absolute; inset: -30%; z-index: 2; pointer-events: none; opacity: 0; will-change: transform;
    background: linear-gradient(112deg, rgba(255,255,255,0) 34%, rgba(255,255,255,.10) 45%, rgba(255,255,255,.17) 50%, rgba(255,255,255,.10) 55%, rgba(255,255,255,0) 66%);
    transform: translate3d(var(--sx, 0px), var(--sy, 0px), 0);
    transition: opacity .7s var(--ease, cubic-bezier(.22,.9,.3,1));
  }
  .svc-glass:hover .svc-media > .mo-spec { opacity: 1; }
  /* capability chips: a tiny azure edge and a 1px lift, each on its own */
  .svc-glass .tags span { transition: box-shadow .16s var(--ease, cubic-bezier(.22,.9,.3,1)), transform .16s var(--ease, cubic-bezier(.22,.9,.3,1)), background .16s var(--ease, cubic-bezier(.22,.9,.3,1)); }
  .svc-glass .tags span:hover {
    transform: translateY(-1px); background: rgba(255,255,255,.6);
    box-shadow: inset 0 1px 0 #fff, inset 0 0 0 1px rgba(255,255,255,.85), 0 0 0 1px rgba(42,143,255,.45);
  }
  /* CTA: optical clarity, the flip label the site already has, and the orange point arriving from the right */
  .svc-glass .btn-wide { transition: box-shadow .2s var(--ease, cubic-bezier(.22,.9,.3,1)), background .2s var(--ease, cubic-bezier(.22,.9,.3,1)), transform .2s var(--ease, cubic-bezier(.22,.9,.3,1)); }
  .svc-glass .btn-wide:hover {
    transform: none;
    background: linear-gradient(135deg, rgba(87,172,255,.98), rgba(42,134,240,.98));
    box-shadow: inset 0 1px 0 rgba(255,255,255,.6), inset 0 0 0 1px rgba(255,255,255,.24), inset 0 -10px 18px -12px rgba(10,60,150,.3), 0 0 0 1px rgba(150,200,255,.55), 0 10px 24px rgba(30,123,230,.3);
  }
  .svc-glass .btn-wide::after { transition: opacity .2s var(--ease, cubic-bezier(.22,.9,.3,1)), transform .2s var(--ease, cubic-bezier(.22,.9,.3,1)); }
  .svc-glass .btn-wide:hover::after { opacity: 1; transform: translateX(0); }
}
/* touch: no hover states, press feedback instead */
@media (hover: none) {
  .svc-glass .btn-wide:active { transform: scale(.985); }
  .svc-glass .tags span:active { transform: scale(.96); }
  .svc-glass .btn-wide, .svc-glass .tags span { transition: transform .12s var(--ease, cubic-bezier(.22,.9,.3,1)); }
}
/* scroll-in reveal on the stacked layout: armed by motion.js only when it is going to run */
.svc-glass.mo-armed .svc-top > * { opacity: 0; transform: translateY(8px); }
.svc-glass.mo-armed .svc-media { opacity: .92; transform: translateY(6px); }
.svc-glass.mo-armed.mo-in .svc-top > * {
  opacity: 1; transform: translateY(0);
  transition: opacity .55s var(--ease, cubic-bezier(.22,.9,.3,1)), transform .55s var(--ease, cubic-bezier(.22,.9,.3,1));
  transition-delay: var(--mo-d, 0ms);
}
.svc-glass.mo-armed.mo-in .svc-media {
  opacity: 1; transform: translateY(0);
  transition: opacity .6s var(--ease, cubic-bezier(.22,.9,.3,1)), transform .6s var(--ease, cubic-bezier(.22,.9,.3,1));
}

/* ============================================================ reduced motion, additions
   Comparison: every mark is already in its final state (style.css); make sure arming can never hold
   it back and nothing sequences. Card: no lift, no parallax, no scale, no reveal. Material stays. */
@media (prefers-reduced-motion: reduce) {
  .cmp-card ul.mo-armed li, .cmp-after ul.mo-armed li { color: inherit; transform: none; }
  .cmp-card ul.mo-armed .cmp-ic path { stroke-dashoffset: 0; }
  .cmp-before ul.mo-armed .cmp-ic-ring { stroke: rgba(230,83,75,.34); fill: rgba(230,83,75,.07); }
  .cmp-after ul.mo-armed .cmp-ic-ring { stroke: rgba(255,255,255,.95); fill: rgba(255,255,255,.94); }
  .cmp-card ul.mo-armed li, .cmp-card ul.mo-armed .cmp-ic path, .cmp-card ul.mo-armed .cmp-ic-ring, .cmp-after::after { transition: none !important; }
  .svc-glass, .svc-glass:hover { transform: none; transition: box-shadow .3s linear; }
  .svc-glass .svc-media > img { transform: none !important; transition: none; }
  .svc-glass .svc-media > .mo-spec { display: none; }
  .svc-glass .tags span:hover, .svc-glass .btn-wide:hover { transform: none; }
  .svc-glass.mo-armed .svc-top > *, .svc-glass.mo-armed .svc-media { opacity: 1; transform: none; transition: none; }
}

/* ============================================================ 6. founder-led still life
   One wide photograph as the conclusion of "Fewer people between the decision and the thing being
   built." Armed by motion.js only when the reveal will run: 0.94 -> 1, scale .99 -> 1, 8px -> 0.
   On a hover device the image scales to 1.012 and follows the pointer by at most ±2px through a
   damped loop (--hx/--hy written by motion.js), and the top edge catches one thin highlight. */
.how-still.mo-armed > img { opacity: .94; transform: translateY(8px) scale(.99); }
.how-still.mo-armed.mo-in > img {
  opacity: 1; transform: translateY(0) scale(1);
  transition: opacity .7s var(--ease, cubic-bezier(.22,.9,.3,1)), transform .7s var(--ease, cubic-bezier(.22,.9,.3,1));
}
@media (hover: hover) and (pointer: fine) {
  .how-still.mo-in > img, .how-still:not(.mo-armed) > img {
    will-change: transform;
    transform: translate3d(var(--hx, 0px), var(--hy, 0px), 0) scale(var(--hs, 1));
    transition: none;
  }
  .how-still { transition: box-shadow .5s var(--ease, cubic-bezier(.22,.9,.3,1)); }
  .how-still:hover { box-shadow: 0 0 0 1px rgba(35,135,232,.26), 0 28px 66px rgba(6,26,54,.11); }
  .how-still:hover::before { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .how-still.mo-armed > img { opacity: 1; transform: none; transition: none; }
  .how-still > img { transform: none !important; }
  .how-still, .how-still::before { transition: none; }
}

/* ============================================================ 7. principles glass
   The panel under "You see the work every week". motion.js arms it (.mo-armed) only when the
   sequence will run: columns at opacity 0 / 6px, icon strokes undrawn. .mo-in resolves the columns
   one after another (--mo-d = 0 / 140 / 280ms), and each icon draws 220ms after its column lands.
   The dots appear with the strokes. One faint sheen (.mo-sheen) follows the pointer across the glass. */
.benefits.mo-armed .pr-col { opacity: 0; transform: translateY(6px); }
.benefits.mo-armed .pr-ic path { stroke-dashoffset: 1; }
.benefits.mo-armed .pr-ic .pr-dot { opacity: 0; }
.benefits.mo-armed.mo-in .pr-col {
  opacity: 1; transform: translateY(0);
  transition: opacity .5s var(--ease, cubic-bezier(.22,.9,.3,1)), transform .5s var(--ease, cubic-bezier(.22,.9,.3,1)), background .3s var(--ease, cubic-bezier(.22,.9,.3,1));
  transition-delay: var(--mo-d, 0ms), var(--mo-d, 0ms), 0ms;
}
.benefits.mo-armed.mo-in .pr-ic path {
  stroke-dashoffset: 0;
  transition: stroke-dashoffset .5s var(--ease, cubic-bezier(.22,.9,.3,1)), stroke .3s var(--ease, cubic-bezier(.22,.9,.3,1));
  transition-delay: calc(var(--mo-d, 0ms) + 220ms), 0ms;
}
.benefits.mo-armed.mo-in .pr-ic .pr-dot {
  opacity: 1;
  transition: opacity .3s var(--ease, cubic-bezier(.22,.9,.3,1)), fill .3s var(--ease, cubic-bezier(.22,.9,.3,1));
  transition-delay: calc(var(--mo-d, 0ms) + 420ms), 0ms;
}
@media (hover: hover) and (pointer: fine) {
  .benefits > .mo-sheen {
    position: absolute; inset: -20%; z-index: 0; pointer-events: none; opacity: 0; will-change: transform;
    background: linear-gradient(112deg, rgba(255,255,255,0) 38%, rgba(255,255,255,.10) 47%, rgba(255,255,255,.16) 50%, rgba(255,255,255,.10) 53%, rgba(255,255,255,0) 62%);
    transform: translate3d(var(--gx, 0px), 0, 0);
    transition: opacity .6s var(--ease, cubic-bezier(.22,.9,.3,1));
  }
  .benefits:hover > .mo-sheen { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .benefits.mo-armed .pr-col { opacity: 1; transform: none; transition: none; }
  .benefits.mo-armed .pr-ic path { stroke-dashoffset: 0; transition: none; }
  .benefits.mo-armed .pr-ic .pr-dot { opacity: 1; transition: none; }
  .benefits > .mo-sheen { display: none; }
  .pr-col:hover p { transform: none; }
}

/* ============================================================ 8. studio artwork
   Reveal only: opacity .94 -> 1, scale .99 -> 1, 8px -> 0, once. Playback lives in motion.js. */
.studio-art.mo-armed { opacity: .94; transform: translateY(8px) scale(.99); }
.studio-art.mo-armed.mo-in { opacity: 1; transform: none; transition: opacity .7s var(--ease, cubic-bezier(.22,.9,.3,1)), transform .7s var(--ease, cubic-bezier(.22,.9,.3,1)), box-shadow .5s var(--ease, cubic-bezier(.22,.9,.3,1)), filter .6s var(--ease, cubic-bezier(.22,.9,.3,1)); }
@media (prefers-reduced-motion: reduce) { .studio-art.mo-armed { opacity: 1; transform: none; transition: none; } }

/* ============================================================ 9. selected work entrance
   Marker: 4px -> 0. Image: scale .992 -> 1, opacity .96 -> 1 over .7s. Panel: 8px -> 0, 180ms later. Once. */
.work-label.mo-armed { opacity: 0; transform: translateY(4px); }
.work-label.mo-armed.mo-in { opacity: 1; transform: none; transition: opacity .5s var(--ease, cubic-bezier(.22,.9,.3,1)), transform .5s var(--ease, cubic-bezier(.22,.9,.3,1)); }
.testi-featured.mo-armed { opacity: .96; transform: scale(.992); }
.testi-featured.mo-armed .testi-quote-card { opacity: 0; transform: translateY(8px); }
.testi-featured.mo-armed.mo-in { opacity: 1; transform: none; transition: opacity .7s var(--ease, cubic-bezier(.22,.9,.3,1)), transform .7s var(--ease, cubic-bezier(.22,.9,.3,1)); }
.testi-featured.mo-armed.mo-in .testi-quote-card { opacity: 1; transform: none; transition: opacity .55s var(--ease, cubic-bezier(.22,.9,.3,1)) .18s, transform .55s var(--ease, cubic-bezier(.22,.9,.3,1)) .18s; }
@media (prefers-reduced-motion: reduce) {
  .work-label.mo-armed, .testi-featured.mo-armed, .testi-featured.mo-armed .testi-quote-card { opacity: 1; transform: none; transition: none; }
}
