/* Shared microinteractions for the 3 concepts (assets/micro.js adds the classes / DOM).
   Linked last in <head> and prefixed with `html` so it wins over the page styles. */
:root { --m-ease: cubic-bezier(.22, 1, .36, 1); --m-ink: #000; --m-paper: #fff; }

/* Pills: magnetic (translate set by JS) + ink fill that grows from where the pointer entered */
html .pill {
  position: relative; overflow: hidden; isolation: isolate;
  translate: var(--mag-x, 0) var(--mag-y, 0);
  transition: color .4s var(--m-ease), translate .5s var(--m-ease), scale .2s var(--m-ease);
}
html .pill:hover, html .pill:focus-visible { background: var(--m-paper); color: var(--m-paper); }
html .pill::before {
  content: ''; position: absolute; z-index: -1;
  left: var(--fx, 50%); top: var(--fy, 50%);
  width: 0; aspect-ratio: 1; border-radius: 50%;
  background: var(--m-ink); translate: -50% -50%;
  transition: width .55s var(--m-ease);
}
html .pill:hover::before, html .pill:focus-visible::before { width: 260%; }
html .pill > span { display: inline-block; text-box: trim-both cap alphabetic; translate: var(--mag-tx, 0) var(--mag-ty, 0); transition: translate .5s var(--m-ease); }
html .pill:active { scale: .96; }

/* Underline that leaves to the right and comes back from the left */
html .u-line { position: relative; text-decoration: none; opacity: 1; }
html .u-line::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: -.24em; height: 1px;
  background: currentColor; transform-origin: right;
}
html .u-line:hover { opacity: 1; }
html .u-line:hover::after { animation: m-reline .75s var(--m-ease); }
@keyframes m-reline {
  0%   { scale: 1 1; transform-origin: right; }
  45%  { scale: 0 1; transform-origin: right; }
  46%  { scale: 0 1; transform-origin: left; }
  100% { scale: 1 1; transform-origin: left; }
}

/* "(Typeface)" nav: the brackets open up */
html .m-brackets { opacity: 1; }
html .m-brackets:hover { opacity: 1; }
.m-brackets .br { display: inline-block; transition: translate .45s var(--m-ease); }
.m-brackets:hover .br:first-child { translate: -.28em 0; }
.m-brackets:hover .br:last-child { translate: .28em 0; }

/* Project lists: hovered entry steps right, the others recede */
html .projects button { opacity: 1; transition: translate .45s var(--m-ease), opacity .3s; }
html .projects button:hover { opacity: 1; translate: .4em 0; }
html .projects:has(button:hover) li:not(.head) { opacity: .3; transition: opacity .3s; }
html .projects li:not(.head) { transition: opacity .3s; }
html .projects:has(button:hover) li:has(button:hover) { opacity: 1; }

/* "Tất cả dự án →": the arrow runs out and comes back in */
html .all:hover span:last-child { animation: m-arrow .6s var(--m-ease); transform: none; }
@keyframes m-arrow { 0% { translate: 0; } 45% { translate: 110% 0; opacity: 0; } 46% { translate: -110% 0; opacity: 0; } 100% { translate: 0; opacity: 1; } }

/* Thumbnails: colour wipes up over the greyscale image; press feedback */
.m-color {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  mix-blend-mode: normal !important;
  clip-path: inset(100% 0 0 0);
  transition: clip-path .6s var(--m-ease), scale .6s var(--m-ease);
  pointer-events: none;
}
.m-thumb:hover .m-color, .m-thumb:focus-visible .m-color, .m-thumb.is-active .m-color { clip-path: inset(0); }
.m-thumb:hover .m-color { scale: 1.05; }
html .m-thumb:hover img:not(.m-color) { mix-blend-mode: luminosity; }   /* keep the grey base under the wipe */
html .m-thumb { transition: scale .2s var(--m-ease); }
html .m-thumb:active { scale: .97; }

/* Cursor label (project name) over thumbnails */
.m-cursor {
  position: fixed; left: 0; top: 0; z-index: 900; pointer-events: none;
  padding: 8px 12px; border-radius: 999px;
  background: var(--m-ink); color: var(--m-paper);
  font: 500 13px/1 "Inter Tight", "Helvetica Neue", Arial, sans-serif; letter-spacing: -0.01em; white-space: nowrap;
  translate: var(--cx, 0) var(--cy, 0);
  scale: 0; opacity: 0;
  transition: scale .35s var(--m-ease), opacity .2s;
}
.m-cursor.is-on { scale: 1; opacity: 1; }

/* Snipper cursor: a small shape that follows the pointer and morphs between states — a filled dot
   (normal), a ring (over a link, and over anything draggable), and an 8-ray burst (pressing).
   White with mix-blend difference, so it shows on the black home and the white project page alike.
   The native cursor is hidden while it is on. States built in micro.js. */
html.snip-on, html.snip-on * { cursor: none !important; }
.snip {
  position: fixed; left: 0; top: 0; z-index: 9999;
  width: 64px; height: 64px; margin: -32px 0 0 -32px;
  pointer-events: none;
  translate: var(--sx, -200px) var(--sy, -200px);
  mix-blend-mode: difference;
  transition: opacity .25s var(--m-ease), scale .18s var(--m-ease);
}
.snip.is-hidden { opacity: 0; }
.snip.is-down { scale: .82; }                 /* a press dips the whole cursor */
.snip svg { display: block; width: 100%; height: 100%; overflow: visible; }
/* every part sits hidden (scaled to nothing); the active state brings its own part in */
.snip [data-part] {
  transform-box: fill-box; transform-origin: center;
  opacity: 0; scale: 0;
  transition: scale .32s var(--m-ease), opacity .24s var(--m-ease), rotate .4s var(--m-ease);
}
.snip-dot { fill: #fff; }
.snip-ring circle { fill: none; stroke: #fff; stroke-width: 3; }
.snip-ring .c { fill: #fff; stroke: none; }
.snip-burst line { stroke: #fff; stroke-width: 3; stroke-linecap: round; }
.snip-burst { rotate: -35deg; }               /* twists into place when a press starts */
.snip.is-normal .snip-dot { opacity: 1; scale: 1; }
.snip.is-link   .snip-ring { opacity: 1; scale: 1; }
.snip.is-click  .snip-burst { opacity: 1; scale: 1; rotate: 0deg; }

@media (prefers-reduced-motion: reduce) {
  html .pill, .m-cursor, .m-color, .m-brackets .br, html .projects button { transition: none; }
  html .u-line:hover::after, html .all:hover span:last-child { animation: none; }
}
