/* =========================================================================
   Andrej Olsen — Motion layer
   Subtle scroll-reveal + microinteractions. Calm, editorial, never flashy.
   All motion is opt-out via prefers-reduced-motion.
   ========================================================================= */

/* ---- Scroll reveal ------------------------------------------------------ */
/* JS adds .reveal to content nodes, then .in when they enter the viewport.
   Stagger is carried per-element in --rv (seconds). */
.reveal {
  opacity: 0;
  transform: translateY(16px);
  transition:
    opacity .7s cubic-bezier(.22,.61,.36,1),
    transform .7s cubic-bezier(.22,.61,.36,1);
  transition-delay: var(--rv, 0s);
  will-change: opacity, transform;
}
.reveal.in {
  opacity: 1;
  transform: none;
}
/* once settled, drop will-change so we don't pin layers */
.reveal.done { will-change: auto; }

/* ---- Hero entrance (runs once on load) ---------------------------------- */
@keyframes olsenRise {
  from { opacity: 0; transform: translateY(20px); }
  to   { opacity: 1; transform: none; }
}
@keyframes olsenFade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
/* headline settles out of a soft focus — editorial, not flashy */
@keyframes olsenSettle {
  from { opacity: 0; transform: translateY(22px); filter: blur(7px); }
  60%  { filter: blur(0); }
  to   { opacity: 1; transform: none; filter: none; }
}
/* small elements slide in from the left */
@keyframes olsenSlideIn {
  from { opacity: 0; transform: translateX(-10px); }
  to   { opacity: 1; transform: none; }
}
/* meta blocks drift in from the right */
@keyframes olsenDrift {
  from { opacity: 0; transform: translateX(14px); }
  to   { opacity: 1; transform: none; }
}
/* logo mark breathes into place */
@keyframes olsenMark {
  from { opacity: 0; transform: scale(.88) rotate(-4deg); }
  to   { opacity: 1; transform: none; }
}

.boot .eyebrow      { animation: olsenRise .8s cubic-bezier(.22,.61,.36,1) both; animation-delay: .1s; }
.boot .eyebrow .ey-dot { animation: olsenPop .5s cubic-bezier(.22,.61,.36,1) both; animation-delay: .55s; }
.boot .hero-h       { animation: olsenSettle 1.05s cubic-bezier(.22,.61,.36,1) both; animation-delay: .18s; }
.boot .hero-lede    { animation: olsenRise .9s cubic-bezier(.22,.61,.36,1) both; animation-delay: .42s; }
.boot .prose p:nth-of-type(1) { animation: olsenRise .9s cubic-bezier(.22,.61,.36,1) both; animation-delay: .56s; }
.boot .prose p:nth-of-type(2) { animation: olsenRise .9s cubic-bezier(.22,.61,.36,1) both; animation-delay: .68s; }

/* the accent phrase settles from ink to teal — a quiet wash of colour */
.boot .hero-h .accent { animation: olsenInkWash 1.7s cubic-bezier(.22,.61,.36,1) both; animation-delay: .75s; }
@keyframes olsenInkWash { from { color: var(--ink); } }

/* sidebar: identity first, then the nav cascades item by item */
.boot .sidebar { animation: olsenFade .7s ease both; }
.boot .sb-badge { animation: olsenMark .8s cubic-bezier(.22,.61,.36,1) both; animation-delay: .08s; }
.boot .sb-name, .boot .sb-role { animation: olsenSlideIn .7s cubic-bezier(.22,.61,.36,1) both; animation-delay: .2s; }
.boot .sb-role { animation-delay: .3s; }
.boot .sb-nav .sb-link { animation: olsenSlideIn .55s cubic-bezier(.22,.61,.36,1) both; }
.boot .sb-nav .sb-link:nth-child(1) { animation-delay: .42s; }
.boot .sb-nav .sb-link:nth-child(2) { animation-delay: .48s; }
.boot .sb-nav .sb-link:nth-child(3) { animation-delay: .54s; }
.boot .sb-nav .sb-link:nth-child(4) { animation-delay: .6s; }
.boot .sb-nav .sb-link:nth-child(5) { animation-delay: .66s; }
.boot .sb-nav .sb-link:nth-child(6) { animation-delay: .72s; }
.boot .sb-nav .sb-link:nth-child(7) { animation-delay: .78s; }
.boot .sb-foot { animation: olsenFade .8s ease both; animation-delay: .9s; }

/* meta column: portrait, then the blocks drift in */
.boot .meta .portrait { animation: olsenFade 1s ease both; animation-delay: .35s; }
.boot .meta .meta-block { animation: olsenDrift .7s cubic-bezier(.22,.61,.36,1) both; }
.boot .meta .meta-block:nth-of-type(1) { animation-delay: .5s; }
.boot .meta .meta-block:nth-of-type(2) { animation-delay: .6s; }
.boot .meta .meta-block:nth-of-type(3) { animation-delay: .7s; }
.boot .meta .meta-block:nth-of-type(4) { animation-delay: .8s; }
.boot .meta .meta-rule { animation: olsenFade .9s ease both; animation-delay: .75s; }

/* the systems-map drawing eases in last, behind everything */
.boot .bg-net { animation: olsenBgIn 1.8s ease both; animation-delay: .6s; }
@keyframes olsenBgIn { from { opacity: 0; } }

/* ---- Microinteractions -------------------------------------------------- */
/* one shared easing family — the soft curve the sidebar uses */
:root { --olsen-ease: cubic-bezier(.22,.61,.36,1); }

/* nav: active marker grows from the number, hover nudges right */
.sb-link { position: relative; transition: background .25s var(--olsen-ease), color .25s var(--olsen-ease), transform .25s var(--olsen-ease); }
.sb-link:hover { transform: translateX(2px); }
.sb-link .sb-num { transition: color .25s var(--olsen-ease), transform .25s var(--olsen-ease); }
.sb-link:hover .sb-num { transform: translateX(1px); }

/* skill chips: gentle lift + teal wash */
.chip {
  transition: transform .28s var(--olsen-ease),
              border-color .28s var(--olsen-ease), background .28s var(--olsen-ease),
              color .28s var(--olsen-ease), box-shadow .28s var(--olsen-ease);
}
.chip:hover {
  transform: translateY(-2px);
  border-color: var(--teal);
  color: var(--teal-deep);
  background: var(--teal-ghost);
  box-shadow: 0 6px 16px -12px var(--teal);
}

/* cards (tech-stack + interests): hairline lifts toward teal */
.stack-card, .int-card {
  transition: transform .32s var(--olsen-ease),
              border-color .32s var(--olsen-ease), box-shadow .32s var(--olsen-ease);
}
.stack-card:hover, .int-card:hover {
  transform: translateY(-3px);
  border-color: var(--line-2);
  box-shadow: 0 18px 40px -28px rgba(0,0,0,.4);
}
.int-card .ic-mk { transition: width .35s var(--olsen-ease); }
.int-card:hover .ic-mk { width: 40px; }

/* tech-stack rows: name slides a touch, hairline tints */
.stack-row { transition: border-color .25s var(--olsen-ease); }
.stack-row .sr-n { transition: transform .25s var(--olsen-ease), color .25s var(--olsen-ease); }
.stack-card:hover .sc-label { color: var(--teal-deep); }
.stack-card .sc-label { transition: color .3s var(--olsen-ease); }

/* timeline rows: soft teal wash like the sidebar nav, no layout shift */
.job, .edu { position: relative; }
.job::before, .edu::before {
  content: ""; position: absolute; inset: 0 -14px; border-radius: 8px;
  background: transparent; transition: background .3s var(--olsen-ease);
  pointer-events: none; z-index: -1;
}
.job:hover::before, .edu:hover::before { background: var(--teal-ghost); }
.job .jy, .edu .ey { transition: color .3s var(--olsen-ease), transform .3s var(--olsen-ease); }
.job:hover .jy, .edu:hover .ey { color: var(--teal-deep); transform: translateX(2px); }
.job:hover .jrole { color: var(--teal-deep); }
.job .jrole { transition: color .3s var(--olsen-ease); }

/* recommendation rows: the sidebar nudge — transform, not padding */
.rec { transition: background .3s var(--olsen-ease), transform .3s var(--olsen-ease); border-radius: 8px; position: relative; }
.rec::before {
  content: ""; position: absolute; inset: 0 -14px; border-radius: 8px;
  background: transparent; transition: background .3s var(--olsen-ease);
  pointer-events: none; z-index: -1;
}
.rec:hover { transform: translateX(4px); }
.rec:hover::before { background: var(--teal-ghost); }
.rec .rec-link svg { transition: transform .3s var(--olsen-ease); }
.rec:hover .rec-link svg { transform: translate(2px, -2px); }

/* contact links: serif title shifts, hairline arrow flies out */
.clink .cl-t { transition: color .3s var(--olsen-ease), transform .3s var(--olsen-ease); }
.clink:hover .cl-t { transform: translateX(3px); }
.clink .cl-h svg { transition: transform .3s var(--olsen-ease); }
.clink:hover .cl-h svg { transform: translate(2px, -2px); }

/* segmented toggles: pressed feel */
.seg button { transition: background .18s ease, color .18s ease, transform .12s ease; }
.seg button:active { transform: scale(.94); }
.seg button.on { animation: olsenPop .28s cubic-bezier(.22,.61,.36,1); }
@keyframes olsenPop { 0% { transform: scale(.9); } 60% { transform: scale(1.04); } 100% { transform: none; } }

/* theme switch snaps instantly — transitioning background-color on these
   structural, constantly-re-rendered elements froze them mid-interpolation.
   Components keep their own hover transitions (defined above). */
.sp-token { transition: box-shadow .2s ease; }

/* mobile sheet: nav links cascade when the menu opens */
@media (max-width: 760px) {
  .sidebar.open .sb-panel .sb-link { animation: olsenSlideIn .4s cubic-bezier(.22,.61,.36,1) both; }
  .sidebar.open .sb-panel .sb-link:nth-child(1) { animation-delay: .1s; }
  .sidebar.open .sb-panel .sb-link:nth-child(2) { animation-delay: .15s; }
  .sidebar.open .sb-panel .sb-link:nth-child(3) { animation-delay: .2s; }
  .sidebar.open .sb-panel .sb-link:nth-child(4) { animation-delay: .25s; }
  .sidebar.open .sb-panel .sb-link:nth-child(5) { animation-delay: .3s; }
  .sidebar.open .sb-panel .sb-link:nth-child(6) { animation-delay: .35s; }
  .sidebar.open .sb-panel .sb-link:nth-child(7) { animation-delay: .4s; }
  .sidebar.open .sb-extra { animation: olsenFade .5s ease both; animation-delay: .45s; }
}

/* badge: faint breathing sheen on hover */
.sb-badge { transition: transform .3s cubic-bezier(.22,.61,.36,1), box-shadow .3s ease; }
.sb-id:hover .sb-badge { transform: rotate(-3deg) scale(1.04); box-shadow: 0 10px 24px -14px var(--teal); }

/* status dot: soft pulse when available */
.sb-dot { position: relative; }
.sb-dot::after {
  content: ""; position: absolute; inset: -4px; border-radius: 999px;
  border: 1.5px solid var(--teal); opacity: 0;
}
.sb-dot:not(.off)::after { animation: olsenPulse 2.6s ease-out infinite; }
@keyframes olsenPulse {
  0%   { opacity: .5; transform: scale(.6); }
  70%  { opacity: 0;  transform: scale(1.5); }
  100% { opacity: 0;  transform: scale(1.5); }
}

/* section eyebrow dot + sec-num quietly pulse into place handled by reveal */
.sec-head .sec-num { transition: color .2s ease; }

/* mobile sheet links get the same nudge */
@media (max-width: 760px) {
  .sb-link:hover { transform: none; }
}

/* hover affordances only where a pointer exists */
@media (hover: none) {
  .chip:hover, .stack-card:hover, .int-card:hover { transform: none; box-shadow: none; }
}

/* ---- Reduced motion: honour the user ------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1 !important; transform: none !important; transition: none !important; }
  .boot .eyebrow, .boot .eyebrow .ey-dot, .boot .hero-h, .boot .hero-lede, .boot .prose p,
  .boot .sidebar, .boot .sb-badge, .boot .sb-name, .boot .sb-role,
  .boot .sb-nav .sb-link, .boot .sb-foot,
  .boot .meta, .boot .meta .portrait, .boot .meta .meta-block, .boot .meta .meta-rule,
  .boot .bg-net, .sidebar.open .sb-panel .sb-link, .sidebar.open .sb-extra { animation: none !important; }
  .boot .hero-h .accent { animation: none !important; }
  .sb-dot:not(.off)::after { animation: none !important; }
  * { scroll-behavior: auto !important; }
  .chip:hover, .stack-card:hover, .int-card:hover, .sb-link:hover,
  .rec:hover, .clink:hover .cl-t, .sb-id:hover .sb-badge { transform: none !important; }
}
