/* Kristen Calvin: the motion layer.
   Loaded after site.css. To switch all of it off, delete the one <link> to this file and the one <script> for motion.js in index.html.
   Rules: movement uses only transform and opacity (the "Next up" glow also fades a shadow on one small label); every animation runs once
   except the tiny "Today" dot; people who set "reduce motion" on their device get none of it (the site.css rule at the top already
   handles the CSS part, and motion.js checks the same setting). */

/* 1. The hero: the name and the buttons rise in, one after another. CSS only. */
@keyframes mo-rise { from { opacity: 0; transform: translateY(18px); } }
.hero-copy > * { animation: mo-rise .85s cubic-bezier(.2, .7, .2, 1) backwards; }
.hero-copy > :nth-child(1) { animation-delay: .10s; }
.hero-copy > :nth-child(2) { animation-delay: .22s; }
.hero-copy > :nth-child(3) { animation-delay: .38s; }
.hero-copy > :nth-child(4) { animation-delay: .52s; }
.hero-copy > :nth-child(5) { animation-delay: .66s; }

/* 2. The poster wall: each past poster rests with a slight tilt, like a flyer pinned to a board, and straightens and lifts when you point at it. */
.wall li:nth-child(6n + 1) { --mo-r: -1.2deg; }
.wall li:nth-child(6n + 2) { --mo-r: .9deg; }
.wall li:nth-child(6n + 3) { --mo-r: -.6deg; }
.wall li:nth-child(6n + 4) { --mo-r: 1.3deg; }
.wall li:nth-child(6n + 5) { --mo-r: -.9deg; }
.wall li:nth-child(6n + 6) { --mo-r: .7deg; }
.wall .pbtn {
  transform: rotate(var(--mo-r, 0deg));
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--text) 16%, transparent), 0 12px 18px -12px rgba(0, 0, 0, .7);
  transition: transform .4s cubic-bezier(.2, .7, .2, 1), box-shadow .4s ease;
}
.wall .pbtn:hover, .wall .pbtn:focus-visible {
  transform: rotate(0deg) translateY(-6px);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--text) 24%, transparent), 0 22px 28px -14px rgba(0, 0, 0, .8);
}
.wall .pbtn:hover img { transform: none; }   /* the lift replaces the old zoom, so the two do not stack */

/* 3. "Today" on a show card gets a small live dot. This is the only animation that repeats, and it is one dot. */
.chip.mo-live { display: inline-flex; align-items: center; gap: 7px; }
.chip.mo-live::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: currentColor; animation: mo-pulse 1.8s ease-in-out infinite; }
.chip.mo-live.mo-paused::before { animation-play-state: paused; }
@keyframes mo-pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: .35; transform: scale(.65); } }

/* 4. The big poster and photo viewer fades in, and each Next or Previous eases the new picture in. */
@keyframes mo-fade { from { opacity: 0; } }
@keyframes mo-pop { from { opacity: 0; transform: scale(.965) translateY(8px); } }
.lb { animation: mo-fade .22s ease backwards; }
.lb img { animation: mo-pop .34s cubic-bezier(.2, .7, .2, 1) backwards; }

/* 5. The roles: a dark veil over each chapter's picture, lifted in two steps when the chapter scrolls into view (motion.js adds and removes it).
      It exists only while motion is allowed, so nothing is ever left dimmed. */
.mo-veil { position: absolute; inset: 0; z-index: 2; background: var(--ground); opacity: .8; pointer-events: none; }

/* 6. "Next up": the label on the next confirmed show keeps a soft lit glow once it has come on. */
.chip.mo-lit { box-shadow: 0 0 14px -2px color-mix(in srgb, var(--accent) 60%, transparent); }

/* 7. Posters: the first picture in the viewer grows out of the poster (motion.js), so the plain pop steps aside for that one picture.
      The ghost is a copy of the picture that shrinks back into place on close. */
.lb img.mo-from { animation: none; }
.lb.mo-grow { background: transparent; }   /* while the picture grows, only the backdrop fades; the picture itself stays solid */
.lb.mo-grow::before { content: ""; position: fixed; inset: 0; z-index: -1; background: rgba(6, 5, 8, .92); animation: mo-fade .24s ease backwards; }
.lb.mo-grow p, .lb.mo-grow .lb-bar { animation: mo-fade .3s ease .12s backwards; }
.mo-ghost { position: fixed; z-index: 70; margin: 0; max-width: none; object-fit: contain; border-radius: 2px; box-shadow: 0 20px 60px rgba(0, 0, 0, .6); pointer-events: none; }

/* 8. Listen: one gold bar glides between rows. Once it is placed, the row's own gold edge steps aside so there is never a double bar. */
.tracks.mo-slide { position: relative; }
.tracks.mo-slide .track.on { border-left-color: transparent; }
.tracks .mo-bar { position: absolute; left: 0; top: 0; width: 3px; background: var(--accent); transform-origin: 0 0; list-style: none; pointer-events: none; }

/* 9. A small lit bulb beside the mailing-list thank-you. It warms up in two beats (on, dip, on) and then holds.
      Without motion it is simply lit. */
.bulb { display: inline-block; vertical-align: -.14em; margin-right: .42em; line-height: 0; filter: drop-shadow(0 0 7px rgba(244, 215, 142, .7)); animation: mo-warm 1.3s linear .2s backwards; }
.bulb svg { display: block; width: .66em; height: 1em; overflow: visible; }
.bulb .b-glass { fill: #F4D78E; stroke: var(--text); stroke-width: 1.2; }
.bulb .b-fil { fill: none; stroke: #A8761C; stroke-width: 1.2; stroke-linecap: round; stroke-linejoin: round; }
.bulb .b-base { fill: var(--muted); }
.bulb.big { display: block; margin: 0 0 18px; font-size: 64px; }
@keyframes mo-warm {
  0% { opacity: .3; filter: drop-shadow(0 0 0 rgba(244, 215, 142, 0)); }
  26% { opacity: 1; filter: drop-shadow(0 0 14px rgba(244, 215, 142, .95)); }
  40% { opacity: .42; filter: drop-shadow(0 0 3px rgba(244, 215, 142, .3)); }
  56% { opacity: 1; filter: drop-shadow(0 0 14px rgba(244, 215, 142, .95)); }
  100% { opacity: 1; filter: drop-shadow(0 0 7px rgba(244, 215, 142, .7)); }
}

/* 10. Moving between pages (Home, Photos, Headshots, Resume): the old page fades into the new one. The browser does this itself;
       a browser that does not know the rule just changes pages as it always has. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
  ::view-transition-old(root), ::view-transition-new(root) { animation-duration: .26s; animation-timing-function: ease; }
}

/* 11. Kristen's signature. Under the mailing list at the foot of the page her name signs itself once, as it scrolls into view.
       The picture is an animated SVG that plays the moment it loads, so the script adds it only when it is on screen.
       The thank-you page signs under its message the same way. Without motion it is simply the finished logo. */
.mo-sign { position: relative; width: min(420px, 100%); margin-top: clamp(28px, 4vw, 48px); aspect-ratio: 2660 / 912; }
.mo-sign img { position: absolute; inset: 0 auto 0 -4.9%; display: block; width: 100%; height: 100%; }   /* -4.9% lines the script up with the text above it */
/* Where it sits: on wide screens in the left column under "Say hello", beside the form; on phones after the form. */
.contact-grid.mo-grid { display: grid; grid-template-columns: minmax(0, 1fr); align-items: start; }
.contact-grid.mo-grid .contact-r { width: 100%; max-width: 520px; }
.contact-grid.mo-grid .mo-sign { margin-top: 0; }
@media (min-width: 900px) {
  .contact-grid.mo-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 520px); grid-template-areas: "l r" "sign r"; column-gap: clamp(32px, 5vw, 72px); row-gap: 0; }
  .contact-grid.mo-grid .contact-l { grid-area: l; }
  .contact-grid.mo-grid .contact-r { grid-area: r; }
  .contact-grid.mo-grid .mo-sign { grid-area: sign; margin-top: clamp(28px, 4vw, 48px); }
}
.mo-sign-ty { display: block; width: min(420px, 82vw); height: auto; margin: 0 0 30px calc(min(420px, 82vw) * -.049); aspect-ratio: 2660 / 912; }

/* 12. The Pozitronics sign. Pick The Pozitronics in the Listen or the show filter and their neon name switches on, like a real sign:
       a few false starts, then it holds. Pick another filter and it goes dark. Wide screens put it in the empty corner of the
       heading, so nothing moves; narrow screens open a space for it under the heading. It is decoration only (hidden from screen readers,
       the filter button already says the name). Without motion it is simply lit. */
.mo-neon { position: relative; display: grid; grid-template-rows: 0fr; margin: 0; pointer-events: none; }
.mo-neon.is-on { grid-template-rows: 1fr; margin: -4px 0 28px; }
.mo-neon-in { position: relative; min-height: 0; overflow: hidden; width: min(340px, 84%); opacity: 0; }
.mo-neon.is-on .mo-neon-in { opacity: 1; }
.mo-neon-in img { display: block; width: 100%; height: auto; }
.mo-neon-off { opacity: .6; }
.mo-neon-on { position: absolute; left: 0; top: 0; opacity: 0; filter: drop-shadow(0 0 10px rgba(255, 205, 70, .5)); }
.mo-neon.is-on .mo-neon-on { opacity: 1; }
@media (min-width: 960px) {
  .mo-neon-host { position: relative; }
  .mo-neon { position: absolute; top: 0; right: 0; display: block; width: min(440px, 36vw); margin: 0; }
  .mo-neon.is-on { margin: 0; }
  .mo-neon-in { width: 100%; overflow: visible; }
}
@media (prefers-reduced-motion: no-preference) {
  .mo-neon { transition: grid-template-rows .45s ease, margin .45s ease; }
  .mo-neon-in { transition: opacity .3s ease; }
  .mo-neon.is-lit .mo-neon-on { animation: mo-strike 2.6s linear backwards; }
}
@media (prefers-reduced-motion: no-preference) and (min-width: 960px) { .mo-neon { transition: none; } }
@keyframes mo-strike {
  0%, 6% { opacity: 0; }
  7% { opacity: .85; }
  10% { opacity: .05; }
  17% { opacity: 0; }
  18% { opacity: .7; }
  21% { opacity: .08; }
  35% { opacity: .08; }
  36% { opacity: .95; }
  40% { opacity: .3; }
  44% { opacity: 1; }
  52% { opacity: .55; }
  55% { opacity: 1; }
  72% { opacity: 1; }
  73% { opacity: .82; }
  75%, 100% { opacity: 1; }
}

/* 13. The logo in the header, in place of the plain name. On the home page it signs itself once per visit (the picture is an
       animated SVG that plays as it loads); on the other pages, and on later visits to the home page, it is the finished logo.
       Without motion it is always the finished logo. The soft shadow keeps the thin script readable over the photo. */
.mo-brand-logo { --h: clamp(62px, 6.4vw, 84px); display: block; width: auto; height: var(--h); margin-left: calc(var(--h) * -.169); filter: drop-shadow(0 1px 8px rgba(29, 10, 21, .55)); }
@media (max-width: 919px) { .mo-brand-logo { --h: clamp(48px, 14.5vw, 62px); } header.nav { column-gap: 10px; } }   /* a tighter gap keeps the logo and MENU on one row, even on a 320px phone */
