/* Karhu Lab — motion layer.
   Additive to style.css. Every hidden state hangs off a class that motion.ts
   adds at runtime (the pre-hydration pre-hide lives in a tiny inline <style>
   written by the head script, see gateScript in motion.ts) and sits behind
   prefers-reduced-motion: no-preference, so the page is always readable. */

:root{--m-ease:cubic-bezier(.2,.7,.2,1);--m-char:28ms}

/* ---- split text: layout only (never changes metrics) ------------------- */
.m-split{display:inline}
.section-label .m-split{display:flex;align-items:center}
.ch,.m-wd,.m-ln,.m-ln-in{display:inline-block}
.m-wd{white-space:nowrap}
.m-ln{clip-path:inset(0)}
.m-t{display:inline-block;position:relative}

/* ---- rule lines (drawn over transparent borders) ------------------------ */
.m-rule-ht{border-top-color:transparent!important}
.m-rule-hb{border-bottom-color:transparent!important}
.m-rule-hl{border-left-color:transparent!important}
.m-rule{position:absolute;display:block;pointer-events:none}
.m-rule-t,.m-rule-b{left:0;right:0;height:1px;transform-origin:0 50%}
.m-rule-t{top:-1px}
.m-rule-b{bottom:-1px}
.m-rule-hl:before{content:"";position:absolute;left:-1px;top:0;bottom:0;width:1px;background:var(--m-rule-c,currentColor);transform-origin:50% 0;pointer-events:none}

/* ---- portrait: framed for the wipe and the inner drift ------------------ */
html.m-ready .profile-figure{overflow:hidden;border-radius:3px}
html.m-ready:not(.m-reduced) .profile-figure img{transform:scale(1.12)}

/* ---- scroll progress ----------------------------------------------------- */
.m-progress{position:fixed;left:0;top:0;width:100%;height:2px;z-index:8;background:var(--blue);transform:scaleX(0);transform-origin:0 50%;pointer-events:none}

/* ---- compact floating nav ----------------------------------------------- */
.m-nav{position:fixed;top:14px;right:16px;z-index:9;color:var(--ink);font-size:12.5px;letter-spacing:.06em;font-weight:400;opacity:0;visibility:hidden;transform:translateY(-14px);transition:opacity .45s ease,transform .6s var(--m-ease),visibility 0s linear .45s}
.m-nav.is-on{opacity:1;visibility:visible;transform:none;transition-delay:0s}
.m-nav nav{display:flex;align-items:center;gap:22px;padding:4px 8px 4px 9px;border:1px solid rgba(25,57,80,.12);border-radius:999px;background:rgba(248,249,247,.85);-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);box-shadow:0 10px 30px rgba(21,54,78,.08)}
.m-nav-mark{display:flex;align-items:center;justify-content:center;width:40px;height:40px;margin:-6px -4px -6px -6px;border-radius:50%;flex:none}
.m-nav-mark img{width:28px;height:28px;object-fit:contain;display:block}
.m-nav a:not(.m-nav-mark){position:relative;padding:12px 0;display:inline-flex;align-items:center;min-height:40px}
.m-nav a:not(.m-nav-mark):after{content:"";position:absolute;left:0;right:100%;bottom:0;height:1px;background:currentColor;transition:right .3s var(--m-ease)}
.m-nav a:not(.m-nav-mark):hover:after,.m-nav a:not(.m-nav-mark):focus-visible:after{right:0}
.m-nav button{padding:10px 16px;min-height:40px;border-radius:999px;background:var(--ink);color:#fff;letter-spacing:.08em;transition:background .3s,transform .3s var(--m-ease)}
.m-nav button:hover{background:var(--blue)}
.m-nav button:focus-visible,.m-nav a:focus-visible{outline-offset:3px}
@media(max-width:599px){.m-nav{top:10px;right:10px}.m-nav a:not(.m-nav-mark){display:none}.m-nav nav{gap:8px;padding:5px 5px 5px 6px}.m-nav button{padding:9px 13px;font-size:11.5px}}

/* ---- hover & focus micro-interactions (pointer devices only) ------------ */
@media(hover:hover) and (pointer:fine){
  .talk{position:relative;overflow:hidden;isolation:isolate;transition:color .35s var(--m-ease),border-color .35s}
  .talk:before{content:"";position:absolute;inset:-1px;border-radius:inherit;background:var(--ink);transform:scaleX(0);transform-origin:0 50%;transition:transform .45s var(--m-ease);z-index:-1}
  .talk-light:before{background:#f5f8fa}
  html .talk:hover,html .talk-light:hover{background:transparent}
  .talk:hover:before,.talk:focus-visible:before{transform:scaleX(1)}
  .talk span{display:inline-block;transition:transform .35s var(--m-ease)}
  .talk:hover span{transform:translateX(5px)}

  .service-list .service-no,.service-list h3{transition:transform .45s var(--m-ease)}
  .service-list article:hover .service-no,.service-list article:hover h3{transform:translateX(6px)}
  .service-list h3{position:relative}
  .service-list h3:after{content:"";position:absolute;left:0;right:0;bottom:-.3em;height:1px;background:currentColor;opacity:.3;transform:scaleX(0);transform-origin:0 50%;transition:transform .55s var(--m-ease)}
  .service-list article:hover h3:after{transform:scaleX(1)}

  .work-index article:after{content:"→";position:absolute;right:1.2em;top:38px;font-size:clamp(16px,1.3vw,22px);line-height:1.7;color:var(--blue);opacity:0;transform:translateX(-10px);transition:opacity .4s,transform .5s var(--m-ease);pointer-events:none}
  .work-index article:hover:after{opacity:1;transform:none}
  .work-index h3{transition:transform .45s var(--m-ease)}
  .work-index article:hover h3{transform:translateX(6px)}

  .journal-grid article>*{transition:transform .45s var(--m-ease),color .35s}
  .journal-grid article:hover>*{transform:translateY(-4px)}
  .journal-grid article:hover h3{color:var(--blue)}

  html .offering-links button{transition:color .3s}
  html .offering-links button:hover{opacity:1;color:var(--blue)}
  .offering-links .m-t:after{content:"";position:absolute;left:0;right:0;bottom:-.12em;height:1px;background:currentColor;transform:scaleX(0);transform-origin:0 50%;transition:transform .45s var(--m-ease)}
  .offering-links button:hover .m-t:after,.offering-links button:focus-visible .m-t:after{transform:scaleX(1)}

  .frictions p{color:#41596a;transition:color .35s}
  .frictions p:hover{color:var(--ink)}

  .header nav a:after,.header nav button:after{transition:right .35s var(--m-ease)}
}

/* ========================================================================
   Everything below moves. None of it exists for people who asked for less.
   ======================================================================== */
@media(prefers-reduced-motion:no-preference){

  /* (the pre-hide that bridges first paint and hydration is written by the
     head script — see gateScript in motion.ts) */

  /* -- hero intro --------------------------------------------------------- */
  @keyframes m-rise{from{opacity:0;transform:translateY(16px)}to{opacity:1;transform:none}}
  @keyframes m-rise-soft{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
  @keyframes m-line{from{transform:translateY(108%)}to{transform:none}}
  html.m-intro .brand-mark{animation:m-rise-soft 1s var(--m-ease) .05s both}
  html.m-intro .brand-text{animation:m-rise-soft 1s var(--m-ease) .18s both}
  html.m-intro .header nav>*{animation:m-rise-soft .9s var(--m-ease) both;animation-delay:calc(.32s + var(--i,0) * .07s)}
  html.m-intro .edition{animation:m-rise-soft .9s var(--m-ease) .62s both}
  html.m-intro .hero-copy h1:not([data-split]){animation:m-rise 1.1s var(--m-ease) .25s both}
  html.m-intro .hero-copy .m-ln-in{animation:m-line 1.05s var(--m-ease) both;animation-delay:calc(.22s + var(--i,0) * .14s)}
  html.m-intro .hero-copy>p{animation:m-rise 1s var(--m-ease) .62s both}
  html.m-intro .hero-copy .talk{animation:m-rise 1s var(--m-ease) .76s both}
  html.m-intro .hero-aside{animation:m-rise 1s var(--m-ease) .86s both}
  html.m-intro .vertical-note{animation:m-rise-soft 1.1s var(--m-ease) .95s both}
  html.m-intro .scroll-cue{animation:m-rise-soft 1.1s var(--m-ease) 1.15s both}
  html.m-intro .hero-keys{animation:m-rise 1s var(--m-ease) .9s both}

  /* -- scroll reveals ------------------------------------------------------ */
  html .m-up{opacity:0;transform:translateY(22px)}
  html .m-fade{opacity:0}
  html .m-pop{opacity:0;transform:scale(.9)}
  html .m-chars .ch{opacity:0;transform:translateY(.5em)}
  html .m-wipe{clip-path:inset(0 0 100% 0)}
  html .m-wipe img{transform:scale(1.24)}

  html .m-up.is-in,html .m-fade.is-in,html .m-pop.is-in{opacity:1;transform:none;transition:opacity .9s ease,transform 1.1s var(--m-ease);transition-delay:calc(var(--i,0) * var(--m-stagger,80ms))}
  html .m-chars.is-in .ch{opacity:1;transform:none;transition:opacity .7s ease,transform .9s var(--m-ease);transition-delay:calc(var(--d,0ms) + var(--i,0) * var(--m-char))}
  html .m-wipe.is-in{clip-path:inset(0);transition:clip-path 1.3s var(--m-ease);transition-delay:calc(var(--i,0) * var(--m-stagger,80ms))}
  html .m-wipe.is-in img{transform:scale(1.12);transition:transform 1.8s var(--m-ease);transition-delay:calc(var(--i,0) * var(--m-stagger,80ms))}

  /* rule lines draw after their host has started to appear */
  html .m-rule{transform:scaleX(0)}
  html .is-in>.m-rule{transform:none;transition:transform 1.2s var(--m-ease);transition-delay:calc(var(--i,0) * var(--m-stagger,80ms) + .12s)}
  html .m-rule-hl:not(.is-in):before{transform:scaleY(0)}
  html .m-rule-hl.is-in:before{transform:none;transition:transform 1.2s var(--m-ease) .12s}
  html .section-label.m-rv:not(.is-in):after{transform:scaleX(0);transform-origin:0 50%}
  html .section-label.is-in:after{transform:none;transition:transform 1s var(--m-ease) .45s}
  html .signature.m-rv:not(.is-in):before{transform:scaleX(0);transform-origin:0 50%}
  html .signature.is-in:before{transform:none;transition:transform 1s var(--m-ease) .35s}

  /* elements that were already scrolled past appear without a transition */
  .m-instant,.m-instant *,.m-instant:before,.m-instant:after{transition:none!important}

  /* -- parallax (compositor only: `translate` composes with any transform) - */
  .method:after,.perspective:before,.question:after,.ax-section:before{translate:0 var(--py,0px)}

  /* -- dialog --------------------------------------------------------------- */
  @keyframes m-dialog-in{from{opacity:0;transform:translateY(12px) scale(.96)}to{opacity:1;transform:none}}
  @keyframes m-dialog-out{to{opacity:0;transform:translateY(6px) scale(.98)}}
  @keyframes m-fade-in{from{opacity:0}to{opacity:1}}
  @keyframes m-fade-out{to{opacity:0}}
  dialog[open]{animation:m-dialog-in .5s var(--m-ease)}
  dialog[open]::backdrop{animation:m-fade-in .5s ease}
  dialog[open].is-closing{animation:m-dialog-out .26s ease forwards}
  dialog[open].is-closing::backdrop{animation:m-fade-out .26s ease forwards}
}

@media(prefers-reduced-motion:reduce){
  .m-nav,.m-nav *,.talk,.talk *,.talk:before{transition:none!important}
  dialog,dialog::backdrop{animation:none!important}
}
