/* Collaborate · motion layer · Valentina Cruz · 2026-11-04
   Profile: Editorial/Brand. Signature: "Converge" — two parts build one piece at the same time, in the same space.
   Nothing travels from one side to the other: both parts move at once, with the same curve and duration, and meet.
   Everything that moves lives inside prefers-reduced-motion: no-preference. With reduced motion the page is static and complete.
   Hooks (set by the page):
     [data-motion="part-a"] / [data-motion="part-b"]  two halves of a display headline (H1 on load, H2s in view)
     [data-motion="mark"]                             the two-square mark (its squares meet)
     .l2[data-rotate][data-alt-1][data-alt-2] > .ri   hero ending rotation ("We collaborate to …")
     [data-reveal]                                    block that enters when in view (ignored inside the hero)
     [data-motion="case-image"]                       case plate: image and caption build in the same beat
     [data-motion="step"]                             method step: its number firms up with the reading position */

:root{
  --ease-ui:cubic-bezier(.23,1,.32,1);    /* hover, press, menu, header state, outgoing text */
  --ease-move:cubic-bezier(.16,1,.3,1);   /* reveals, convergence, incoming text */
  --dur-xs:120ms; --dur-s:220ms; --dur-m:600ms; --dur-l:900ms;
  --conv:.18em;                            /* convergence travel, relative to type size */
}

/* Sticky credit column (desktop): each section label rides beside its own section. Static positioning, kept with RM. */
@media (min-width:1024px){
  .s > .lab{position:sticky;top:104px;align-self:start;grid-row:1 / span 12}
}

@media (prefers-reduced-motion:no-preference){

  /* ---------- SIGNATURE on load (CSS only: it does not wait for JS) ----------
     H1 lines are painted at full opacity on the first frame (LCP-safe). They start slightly apart, toward
     opposite sides, and settle into one composition together. The mark's squares meet in the same beat. */
  .hero h1 [data-motion="part-a"]{display:block;animation:mo-from-l var(--dur-l) var(--ease-move) 120ms both}
  .hero h1 [data-motion="part-b"]{display:block;animation:mo-from-r var(--dur-l) var(--ease-move) 120ms both}
  [data-motion="mark"] rect{transform-box:fill-box}
  header [data-motion="mark"] rect:first-of-type,
  .hero [data-motion="mark"] rect:first-of-type{animation:mo-sq-l var(--dur-l) var(--ease-move) 120ms both}
  header [data-motion="mark"] rect:last-of-type,
  .hero [data-motion="mark"] rect:last-of-type{animation:mo-sq-r var(--dur-l) var(--ease-move) 120ms both}

  @keyframes mo-from-l{from{transform:translate3d(calc(var(--conv) * -1),0,0)}to{transform:none}}
  @keyframes mo-from-r{from{transform:translate3d(var(--conv),0,0)}to{transform:none}}
  @keyframes mo-sq-l{from{transform:translateX(-45%)}to{transform:none}}
  @keyframes mo-sq-r{from{transform:translateX(45%)}to{transform:none}}

  /* ---------- below the fold: only when motion.js runs (html.mo) ---------- */
  .mo [data-mo]{transition:opacity var(--dur-m) var(--ease-move),transform var(--dur-m) var(--ease-move)}
  .mo [data-mo="rise"]:not(.in){opacity:0;transform:translate3d(0,16px,0)}

  /* split headlines: both halves converge at the same time, same duration, no stagger */
  .mo [data-mo="converge"]{transition:none}
  .mo [data-mo="converge"] [data-motion^="part-"]{display:block;transition:opacity var(--dur-m) var(--ease-move),transform var(--dur-l) var(--ease-move)}
  .mo [data-mo="converge"]:not(.in) [data-motion="part-a"]{opacity:0;transform:translate3d(calc(var(--conv) * -1),0,0)}
  .mo [data-mo="converge"]:not(.in) [data-motion="part-b"]{opacity:0;transform:translate3d(var(--conv),0,0)}

  /* footer mark: squares meet when it comes into view */
  .mo [data-mo="mark"]{transition:none}
  .mo [data-mo="mark"] rect{transition:transform var(--dur-l) var(--ease-move)}
  .mo [data-mo="mark"]:not(.in) rect:first-of-type{transform:translateX(-45%)}
  .mo [data-mo="mark"]:not(.in) rect:last-of-type{transform:translateX(45%)}

  /* case plates: image develops and caption sets, together */
  .mo [data-mo="case"]{transition:none}
  .mo [data-mo="case"] .img img{transition:opacity 1000ms var(--ease-move),transform 1000ms var(--ease-move)}
  .mo [data-mo="case"] .cap{transition:opacity var(--dur-m) var(--ease-move),transform var(--dur-m) var(--ease-move)}
  .mo [data-mo="case"]:not(.in) .img img{opacity:0;transform:scale(1.04)}
  .mo [data-mo="case"]:not(.in) .cap{opacity:0;transform:translate3d(0,12px,0)}
  .mo [data-mo="case"].done .img img{transition:transform var(--dur-s) var(--ease-ui)}

  /* already on screen when the script starts: shown as-is, no flash, no replay */
  .mo .now, .mo .now *{transition:none !important}

  /* header: a hairline once the page has moved (state) */
  header{transition:box-shadow var(--dur-s) var(--ease-ui)}
  header[data-scrolled="true"]{box-shadow:0 1px 0 var(--rule)}

  /* menu (tablet/phone) */
  nav.links.open{animation:mo-menu var(--dur-s) var(--ease-ui) both}
  @keyframes mo-menu{from{opacity:0;transform:translate3d(0,-8px,0)}to{opacity:1;transform:none}}

  /* press feedback, any pointer */
  .btn{transition:background-color var(--dur-s) var(--ease-ui),transform var(--dur-xs) var(--ease-ui)}
  .btn:active{transform:scale(.985)}

  /* ---------- Hero ending rotation · "We collaborate to …" ----------
     The H1 text in the DOM is one fixed sentence ("We collaborate to win the pitch."). The two alternates live in
     attributes and are drawn by CSS with empty alt text: not read by assistive tech, not part of the H1 text.
     All three share one grid cell, so the line box is reserved for the longest ending before first paint
     (no layout shift when it rotates). "to" never moves or fades; only the ending crossfades in place. */
  .hero h1 [data-rotate][data-motion]{display:grid}   /* beats the part-b display:block above */
  [data-rotate] > .ri,
  [data-rotate]::before,
  [data-rotate]::after{grid-area:1 / 1;min-width:0}
  [data-rotate]::before{content:attr(data-alt-1);content:attr(data-alt-1) / ""}
  [data-rotate]::after{content:attr(data-alt-2);content:attr(data-alt-2) / ""}
  [data-rotate]::before,
  [data-rotate]::after{text-indent:var(--mo-to,1.02em);font-weight:400;opacity:0;pointer-events:none;
    transition:opacity 280ms var(--ease-ui)}
  [data-rotate] .wct-b{transition:opacity 280ms var(--ease-ui)}
  [data-rotate][data-show="1"] .wct-b,
  [data-rotate][data-show="2"] .wct-b{opacity:0}
  [data-rotate][data-show="0"] .wct-b,
  [data-rotate][data-show="1"]::before,
  [data-rotate][data-show="2"]::after{opacity:1;transition:opacity var(--dur-m) var(--ease-move) 280ms}
  /* pause control (WCAG 2.2.2), present only while the ending rotates */
  .hero{position:relative}
  .mo-pause{position:absolute;top:12px;right:var(--m);font:inherit;font-size:13px;line-height:18px;letter-spacing:.012em;
    color:var(--ink-2);background:none;border:0;padding:10px 0 10px 12px;cursor:pointer;text-decoration:underline;
    text-underline-offset:3px;text-decoration-thickness:1px;transition:color var(--dur-s) var(--ease-ui)}
  .mo-pause:hover{color:var(--ink)}
}

/* hover only on fine pointers (no sticky hover on touch) */
@media (prefers-reduced-motion:no-preference) and (hover:hover) and (pointer:fine){
  nav.links a, .hcta, footer a{transition:color var(--dur-s) var(--ease-ui)}
  .case:hover .img img{transform:scale(1.015)}
}

@media (max-width:600px){ :root{--conv:.12em} }

/* ===================== v3d additions ===================== */
@media (prefers-reduced-motion:no-preference){
  :root{--conv:.3em}                                   /* convergence is more visible in v3d */

  /* THE PAIR — scroll-linked companion (desktop, created by motion.js, aria-hidden).
     Sits in the credit column just above the sticky section labels. Transform/opacity only. */
  .mo-pair{position:fixed;left:var(--m);top:77px;z-index:9;display:flex;gap:2px;pointer-events:none;
    transform-origin:0 0;opacity:0;transition:opacity var(--dur-s) var(--ease-ui);will-change:transform}
  .mo-pair.on{opacity:1}
  .mo-pair i{display:block;width:12px;height:12px;background:var(--ink);will-change:transform}
  @media (max-width:1023px){ .mo-pair{display:none} }
  /* after the load animation, the header mark is driven by the scroll (phone/tablet) */
  [data-motion="mark"].mo-live rect{animation:none !important}

  /* "We collaborate to" + ending: both parts meet when they enter */
  .mo [data-mo="pair"]{transition:none}
  .mo [data-mo="pair"] .wct-a,.mo [data-mo="pair"] .wct-b{display:inline-block;transition:opacity var(--dur-m) var(--ease-move),transform var(--dur-l) var(--ease-move)}
  .mo [data-mo="pair"]:not(.in) .wct-a{opacity:0;transform:translate3d(-16px,0,0)}
  .mo [data-mo="pair"]:not(.in) .wct-b{opacity:0;transform:translate3d(16px,0,0)}

  /* step numbers: the two digits meet */
  .mo [data-mo="digits"]{transition:none}
  .mo [data-mo="digits"] .d0,.mo [data-mo="digits"] .d1{display:inline-block;transition:transform var(--dur-l) var(--ease-move)}
  .mo [data-mo="digits"]:not(.in) .d0{transform:translate3d(-.22em,0,0)}
  .mo [data-mo="digits"]:not(.in) .d1{transform:translate3d(.22em,0,0)}

  /* desktop plates: the picture is moved by the scroll (JS), so the develop is opacity only */
  .mo-px [data-mo="case"] .img img,
  .mo-px [data-mo="case"].done .img img{transition:opacity 1000ms var(--ease-move)}
  .mo-px [data-mo="case"]:not(.in) .img img{transform:translate3d(0,3%,0) scale(1.08)}
}
@media (prefers-reduced-motion:no-preference) and (hover:hover) and (pointer:fine){
  .case .img{transition:transform var(--dur-s) var(--ease-ui)}
  .case:hover .img{transform:scale(1.012)}
  .case .see{transition:transform var(--dur-s) var(--ease-ui)}
  .case:hover .see{transform:translate3d(6px,0,0)}
  .score .row h3{transition:transform var(--dur-s) var(--ease-ui)}
  .score .row:hover h3{transform:translate3d(8px,0,0)}
}
@media (max-width:600px){ :root{--conv:.16em} }
@media (prefers-reduced-motion:no-preference){
  .mo-pair i{transition:background-color var(--dur-s) var(--ease-ui)}
  .mo-pair.inv i{background:var(--paper)}
}
