/* ============================================================
   Nuz Motion V1 (2026-09-27) · css/nuz-motion.css + js/nuz-motion.js, on every current page.
   Eugenio: "stay subtle, but add subtle graceful touches in unexpected places".
   Additive only: nothing here replaces a page's own animation (new rules use their own properties —
   scale / rotate / translate, pseudo-elements, or elements with no motion of their own).
   Brand motion: one curve, cubic-bezier(.2,.7,.2,1); fade-ups of ~8px; presses give a little.
   Scope: html.nm (set by js/nuz-motion.js) and no-preference for reduced motion. ?motion=0 turns the layer off.
   ============================================================ */
:root { --nm-ease: cubic-bezier(.2, .7, .2, 1); --nm-spring: cubic-bezier(.3, 1.4, .5, 1); }

/* ---------- 1 · Page transitions: the header stays put, the page under it fades up ---------- */
@view-transition { navigation: auto; }
@media (prefers-reduced-motion: reduce) { @view-transition { navigation: none; } }
::view-transition-group(*) { animation-duration: .46s; animation-timing-function: cubic-bezier(.2, .7, .2, 1); }
::view-transition-old(root) { animation: .2s cubic-bezier(.2, .7, .2, 1) both nm-vt-out; }
::view-transition-new(root) { animation: .42s cubic-bezier(.2, .7, .2, 1) .04s both nm-vt-in; }
/* the picked intro card grows into the Quiz Me hero; a card title flies to the page heading */
::view-transition-group(nm-hero) { animation-duration: .6s; border-radius: 28px; overflow: clip; }
::view-transition-old(nm-hero), ::view-transition-new(nm-hero) { height: 100%; object-fit: cover; overflow: clip; }
::view-transition-old(nm-hero) { animation: none; } /* stays opaque under the new one: no see-through middle */
::view-transition-new(nm-hero) { animation: .3s cubic-bezier(.2, .7, .2, 1) .04s both nm-fade-in; }
::view-transition-group(nm-title) { animation-duration: .55s; }
@keyframes nm-vt-out { to { opacity: 0; } }
@keyframes nm-vt-in { from { opacity: 0; translate: 0 10px; } }
@keyframes nm-fade-in { from { opacity: 0; } }

@media (prefers-reduced-motion: no-preference) {
  .nm .nz-tabs { view-transition-name: nm-tabs; }
  .nm .nm-pill { view-transition-name: nm-pill; }
  .nm .nz-tabs a[data-tab=quiz] { view-transition-name: nm-tab-quiz; }
  .nm .nz-tabs a[data-tab=portrait] { view-transition-name: nm-tab-portrait; }
  .nm .nz-tabs a[data-tab=games] { view-transition-name: nm-tab-games; }
  .nm .nz-ic[data-nz=profile] { view-transition-name: nm-profile; }
  .nm .nz-ic[data-nz=settings] { view-transition-name: nm-settings; }
  .nm .brand img[src$="logo.svg"] { view-transition-name: nm-logo; }
  .nm .brand .mark, .nm .brand .mascot-mark { view-transition-name: nm-mark; }
  .nm .ng-slot { view-transition-name: nm-guardian; }
  .nm.nm-vt-hero #hero { view-transition-name: nm-hero; }

  /* ---------- 2 · Header: the current-tab pill glides. Color matches the door (blue, orange, green). ---------- */
  .nm .nz-tabs { position: relative; }
  .nm .nz-tabs a { position: relative; z-index: 1; transition: color .3s var(--nm-ease); }
  .nm .nz-tabs.nm-pilled a[aria-current="page"] { background: transparent; }
  .nm .nm-pill { position: absolute; z-index: 0; border-radius: 999px; background: #4766F0; pointer-events: none; }
  .nm .nz-tabs[data-cur=portrait] .nm-pill { background: #4766F0; }
  .nm .nz-tabs[data-cur=quiz] .nm-pill { background: #FF8914; }
  .nm .nz-tabs[data-cur=games] .nm-pill { background: #2E9A62; }
  /* a locked tab, hovered: its little lock gets tried */
  .nm .nz-tabs a.is-locked .nz-lock { transform-origin: 50% 80%; }
  .nm .nz-tabs a.is-locked:hover .nz-lock { animation: nm-lock-try .55s var(--nm-ease); }
  @keyframes nm-lock-try { 30% { rotate: -14deg; } 60% { rotate: 9deg; } 85% { rotate: -3deg; } }
  /* a tab that just opened (js: it was locked last time you saw it) */
  .nm .nz-tabs a.nm-opened { animation: nm-opened 1.6s var(--nm-ease) .45s both; }
  @keyframes nm-opened {
    0% { background-color: transparent; }
    30% { background-color: rgba(255, 176, 106, .28); }
    100% { background-color: transparent; }
  }
  .nm .nm-lockpop { position: absolute; z-index: 2; width: 12px; height: 13px; color: #8A879B; pointer-events: none; }
  /* the settings gear turns, the profile nods */
  .nm .nz-ic svg { transition: rotate .7s var(--nm-ease), translate .3s var(--nm-ease); }
  .nm .nz-ic[data-nz=settings]:hover svg { rotate: 60deg; }
  .nm .nz-ic[data-nz=profile]:hover svg { translate: 0 -1.5px; }
  .nm .nz-ic { transition: scale .14s var(--nm-ease), background-color .2s var(--nm-ease); }

  /* ---------- 3 · Brand: the logo writes itself once a session; the mascot mark nuzzles on hover ---------- */
  .nm.nm-write .brand img[src$="logo.svg"] {
    -webkit-mask-image: linear-gradient(90deg, #000 42%, transparent 58%); mask-image: linear-gradient(90deg, #000 42%, transparent 58%);
    -webkit-mask-size: 260% 100%; mask-size: 260% 100%; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
    animation: nm-write 1.25s .2s var(--nm-ease) both;
  }
  .nm.nm-write .brand .mark, .nm.nm-write .brand .mascot-mark { animation: nm-mark-in .7s var(--nm-spring) both; }
  @keyframes nm-write { from { -webkit-mask-position: 100% 0; mask-position: 100% 0; } to { -webkit-mask-position: 0 0; mask-position: 0 0; } }
  @keyframes nm-mark-in { from { opacity: 0; scale: .7; rotate: -12deg; } }
  .nm .brand .mark, .nm .brand .mascot-mark { transform-origin: 50% 85%; }
  .nm .brand:hover .mark, .nm .brand:hover .mascot-mark { animation: nm-nuzzle 1s var(--nm-ease); }
  @keyframes nm-nuzzle { 30% { rotate: -8deg; } 62% { rotate: 4deg; } 84% { rotate: -1.5deg; } }

  /* ---------- 4 · Dialogs: header menus rise from the corner they came from; every dialog leaves gently ---------- */
  .nm .nz-dlg { transform-origin: 88% 0; transition: opacity .26s var(--nm-ease), scale .34s var(--nm-ease), translate .34s var(--nm-ease), overlay .34s allow-discrete, display .34s allow-discrete; }
  .nm .nz-dlg:not([open]) { opacity: 0; scale: .96; translate: 0 -8px; }
  @starting-style { .nm .nz-dlg[open] { opacity: 0; scale: .96; translate: 0 -8px; } }
  .nm .nz-dlg[open] .nz-in > * { animation: nm-up .42s var(--nm-ease) both; }
  .nm .nz-dlg[open] .nz-in > :nth-child(3) { animation-delay: .04s; } .nm .nz-dlg[open] .nz-in > :nth-child(4) { animation-delay: .08s; }
  .nm .nz-dlg[open] .nz-in > :nth-child(5) { animation-delay: .12s; } .nm .nz-dlg[open] .nz-in > :nth-child(n+6) { animation-delay: .16s; }
  .nm .nz-dlg .nz-x { transition: rotate .4s var(--nm-ease), background-color .2s; } .nm .nz-dlg .nz-x:hover { rotate: 90deg; }
  .nm .ng-dlg, .nm dialog#dlg { transition: opacity .22s var(--nm-ease), overlay .22s allow-discrete, display .22s allow-discrete; }
  .nm .ng-dlg:not([open]), .nm dialog#dlg:not([open]) { opacity: 0; }
  .nm .nz-dlg::backdrop, .nm .ng-dlg::backdrop, .nm dialog#dlg::backdrop { transition: opacity .3s var(--nm-ease), overlay .3s allow-discrete, display .3s allow-discrete; }
  .nm .nz-dlg:not([open])::backdrop, .nm .ng-dlg:not([open])::backdrop, .nm dialog#dlg:not([open])::backdrop { opacity: 0; }
  @starting-style { .nm .nz-dlg[open]::backdrop, .nm .ng-dlg[open]::backdrop, .nm dialog#dlg[open]::backdrop { opacity: 0; } }
  @keyframes nm-up { from { opacity: 0; translate: 0 8px; } }

  /* ---------- 5 · Small physical things: presses give, arrows lean, links breathe ---------- */
  .nm .nz-btn, .nm .ng-btn, .nm .qz-again, .nm .tally button { transition: scale .14s var(--nm-ease), background-color .2s var(--nm-ease); }
  .nm :is(.nz-btn, .ng-btn, .nz-ic, .qz-again, .tally button):active:not(:disabled) { scale: .96; }
  .nm .qz-go:active { transform: scale(.97); }
  .nm .btn > svg:last-child:not(:first-child), .nm .qz-go > span[aria-hidden] { display: inline-block; transition: translate .3s var(--nm-ease); }
  .nm .btn:hover > svg:last-child:not(:first-child), .nm .qz-go:hover > span[aria-hidden] { translate: 3px 0; }
  .nm :is(.legal-links, .nz-legal, .ng-fine, .sp-fine, .legal) a { text-underline-offset: 2px; transition: text-underline-offset .25s var(--nm-ease), color .2s; }
  .nm :is(.legal-links, .nz-legal, .ng-fine, .sp-fine, .legal) a:hover { text-underline-offset: 5px; }

  /* ---------- 6 · Dark cards: their light leans toward your pointer (js sets --nm-x / --nm-y) ---------- */
  .nm .games-btn { position: relative; }
  .nm :is(.cat, .qz, .games-btn, .sp-playbill)::after {
    content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; opacity: 0; transition: opacity .6s var(--nm-ease);
    background: radial-gradient(460px circle at var(--nm-x, 50%) var(--nm-y, 30%), rgba(255, 244, 232, .1), transparent 62%);
  }
  .nm :is(.cat, .qz, .games-btn, .sp-playbill).nm-lit::after { opacity: 1; }
  .nm .sp-playbill { position: relative; }

  /* ---------- 7 · Intro ---------- */
  [data-look=gradient].nm .hint::after { transform-origin: 50% 50%; animation: nm-bar .8s .35s var(--nm-ease) both; }
  [data-look=gradient].nm .hint.pop::after { animation: nm-bar-again .7s var(--nm-ease) both; }
  @keyframes nm-bar { from { scale: 0 1; } }
  @keyframes nm-bar-again { from { scale: .2 1; } }

  /* ---------- 8 · Quiz Me: the right answer catches the light once; the pack tally ticks ---------- */
  .nm :is(.qz-opt.is-right, .sig-choice.is-right, .smarts-opt.is-key) { position: relative; overflow: hidden; }
  .nm :is(.qz-opt.is-right, .sig-choice.is-right, .smarts-opt.is-key)::after {
    content: ""; position: absolute; inset: 0; pointer-events: none; border-radius: inherit;
    background: linear-gradient(105deg, transparent 32%, rgba(255, 255, 255, .5) 50%, transparent 68%); translate: -110% 0;
    animation: nm-shine 1s .12s var(--nm-ease) forwards;
  }
  @keyframes nm-shine { to { translate: 110% 0; } }
  .nm .tally b { display: inline-block; }

  /* ---------- 9 · Pet Portrait ---------- */
  /* the chip bar lifts off the page once you scroll */
  @supports (animation-timeline: scroll()) {
    .nm .chipbar, .nm .run-bar { animation: nm-stuck linear both; animation-timeline: scroll(root); animation-range: 0 64px; }
  }
  @keyframes nm-stuck { to { box-shadow: 0 12px 24px -20px rgba(59, 42, 94, .45); } }
  /* the pet on its own card breathes */
  .nm .pc-face { transform-origin: 50% 92%; animation: nm-breathe 5.2s ease-in-out infinite; }
  @keyframes nm-breathe { 50% { scale: 1.012 1.024; } }
  .nm .pet-mini.add .nuz-ic { transition: rotate .5s var(--nm-ease); } .nm .pet-mini.add:hover .nuz-ic { rotate: 90deg; }
  .nm .op-mini { transition: rotate .45s var(--nm-ease), translate .45s var(--nm-ease), box-shadow .45s var(--nm-ease); }
  .nm .op-card:hover .op-mini { rotate: 3deg; translate: 0 -3px; box-shadow: 0 0 0 1px var(--border, #DDD9E6), 0 14px 22px -10px rgba(59, 42, 94, .45); }
  /* done: the new title gets highlighted like a note in a margin */
  .nm .done .added strong {
    background: linear-gradient(color-mix(in srgb, var(--mod, #F2B58A) 26%, transparent), color-mix(in srgb, var(--mod, #F2B58A) 26%, transparent)) no-repeat 0 88% / 0% 42%;
    animation: nm-mark .9s .55s var(--nm-ease) forwards;
  }
  @keyframes nm-mark { to { background-size: 100% 42%; } }
  /* the one-pager: tape presses on, the medals swing on their ribbons, the hat drops onto the head, the name settles */
  .nm .sheet .tape { animation: nm-tape .5s .2s var(--nm-ease) both; }
  @keyframes nm-tape { from { opacity: 0; scale: 1.25; } }
  .nm .sheet .medal svg { transform-origin: 50% 0; animation: nm-swing 1.8s var(--nm-ease) both; }
  .nm .sheet .medal:nth-child(1) svg { animation-delay: .35s; } .nm .sheet .medal:nth-child(2) svg { animation-delay: .5s; } .nm .sheet .medal:nth-child(3) svg { animation-delay: .65s; }
  @keyframes nm-swing { 0% { rotate: -16deg; opacity: 0; } 12% { opacity: 1; } 32% { rotate: 10deg; } 54% { rotate: -5deg; } 74% { rotate: 2deg; } 100% { rotate: 0deg; } }
  .nm .sheet-face > img.gear-hat { animation: nm-hat .75s .55s var(--nm-spring) both; }
  .nm .sheet-face > img.gear-item { animation: nm-item .6s .8s var(--nm-spring) both; }
  @keyframes nm-hat { 0% { opacity: 0; translate: 0 -70%; } 55% { opacity: 1; translate: 0 4%; scale: 1.08 .9; } 100% { translate: 0 0; } }
  @keyframes nm-item { from { opacity: 0; translate: 30% 10%; rotate: 14deg; } }
  .nm .sheet-name, .nm .sp-type { animation: nm-settle 1s .2s var(--nm-ease) both; }
  @keyframes nm-settle { from { opacity: 0; letter-spacing: .1em; filter: blur(5px); } }

  /* ---------- 10 · Personality: dust drifts in the spotlight; the velvet moves a little ---------- */
  .nm .sp-light::before, .nm .sp-light::after { content: ""; position: absolute; inset: -30% 0 0; pointer-events: none; }
  .nm .sp-light::before {
    background-image: radial-gradient(circle at 14% 18%, rgba(255, 248, 230, .9) 0 1px, transparent 1.8px), radial-gradient(circle at 63% 42%, rgba(255, 248, 230, .7) 0 1.2px, transparent 2px),
      radial-gradient(circle at 38% 71%, rgba(255, 248, 230, .8) 0 .9px, transparent 1.6px), radial-gradient(circle at 86% 9%, rgba(255, 248, 230, .6) 0 1.3px, transparent 2.1px),
      radial-gradient(circle at 52% 93%, rgba(255, 248, 230, .7) 0 1px, transparent 1.7px);
    background-size: 170px 210px; opacity: .55; animation: nm-motes 26s linear infinite;
  }
  .nm .sp-light::after {
    background-image: radial-gradient(circle at 30% 30%, rgba(255, 248, 230, .8) 0 1.6px, transparent 2.6px), radial-gradient(circle at 75% 65%, rgba(255, 248, 230, .6) 0 1.4px, transparent 2.4px),
      radial-gradient(circle at 12% 84%, rgba(255, 248, 230, .5) 0 1.8px, transparent 2.8px);
    background-size: 260px 300px; opacity: .4; filter: blur(.6px); animation: nm-motes-b 38s linear infinite;
  }
  @keyframes nm-motes { to { background-position: 40px -210px; } }
  @keyframes nm-motes-b { to { background-position: -60px -300px; } }
  .nm .sp-curtain { animation: nm-velvet 7s ease-in-out infinite alternate; }
  .nm .sp-curtain.r { animation-delay: -3.5s; }
  @keyframes nm-velvet { to { background-position: 7px 0; } }

  /* ---------- 11 · How old, really?: the ×7 rule gets crossed out while you watch; the stage you're in pings ---------- */
  .nm .ls-hy-card s {
    text-decoration-color: transparent;
    background: linear-gradient(var(--orange-accent, #E07B39), var(--orange-accent, #E07B39)) no-repeat 0 58% / 0% 2px;
    animation: nm-strike .55s 1.05s var(--nm-ease) forwards;
  }
  @keyframes nm-strike { to { background-size: 100% 2px; } }
  .nm .ls-map li.here::after { content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; animation: nm-ping 1.3s .8s ease-out both; }
  @keyframes nm-ping { from { box-shadow: 0 0 0 0 color-mix(in srgb, var(--c, #93B7DB) 90%, transparent); } to { box-shadow: 0 0 0 11px transparent; } }

  /* ---------- 12 · Zoomies: the name zooms in, the picked pet hops, the rosette swings on its pin ---------- */
  .nm .zm-over:not([hidden]) .zm-title em { display: inline-block; animation: nm-zoom-in .75s .22s var(--nm-ease) both; }
  @keyframes nm-zoom-in { from { opacity: 0; translate: 26px 0; transform: skewX(-16deg); } }
  .nm .zm-card[aria-pressed="true"] img { animation: nm-hop .55s var(--nm-spring); }
  @keyframes nm-hop { 40% { translate: 0 -12%; } 70% { translate: 0 1%; } }
  .nm .zm-over:not([hidden]) .zm-ros i { transform-origin: 50% 0; animation: nm-swing 1.8s .45s var(--nm-ease) both; }
  .nm .zm-over:not([hidden]) .g-btn:not(.is-quiet) { animation: nm-ready 2.8s 1.2s ease-in-out infinite; }
  @keyframes nm-ready { 50% { box-shadow: 0 0 0 7px rgba(224, 123, 57, .13), 0 8px 22px rgba(224, 123, 57, .3); } }

  /* ---------- 13 · Reviews: paws fill in a wave, the check draws itself ---------- */
  .nm .ng-paws input:checked + label svg, .nm .ng-paws label:has(~ input:checked) svg { animation: nm-paw .42s var(--nm-spring) var(--nm-d, 0s) both; }
  .nm .ng-paws label:nth-of-type(2) { --nm-d: .04s; } .nm .ng-paws label:nth-of-type(3) { --nm-d: .08s; }
  .nm .ng-paws label:nth-of-type(4) { --nm-d: .12s; } .nm .ng-paws label:nth-of-type(5) { --nm-d: .16s; }
  @keyframes nm-paw { 45% { scale: 1.22; rotate: -8deg; } }
  .nm .ng-dlg[open] .ng-ok path, .nm .ng-ask .ng-ok path, .nm dialog#dlg[open] .ok-btn path { stroke-dasharray: 23; animation: nm-draw .5s .4s var(--nm-ease) both; }
  @keyframes nm-draw { from { stroke-dashoffset: 23; } }

  /* ---------- 14 · Reading: legal pages get a progress line; long pages fade up as you scroll (js) ---------- */
  .nm .nm-read { position: fixed; left: 0; right: 0; top: 0; z-index: 70; height: 3px; transform-origin: 0 50%; scale: 0 1; pointer-events: none;
    background: linear-gradient(90deg, #FF8914, #6E56A8 55%, #4766F0); }
  .nm .nm-rv { opacity: 0; }
}

@media print {
  .nm .nm-rv { opacity: 1 !important; }
  .nm .brand img { -webkit-mask-image: none !important; mask-image: none !important; }
  .nm .nm-read { display: none; }
  .nm .sheet *, .nm .sheet { animation: none !important; }
}
