/* Hover animations for the portfolio hub cards; the layers are built by
   assets/js/portfolio-hover.js. Everything inside .ph-stage is in Figma px: the script
   scales the stage onto the card the way CSS fits the card's flat picture. */

.page-portfolio-categories .category-card .ph-art {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: 2.4rem;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.3s ease;
}

.page-portfolio-categories .category-card.ph-on .ph-art {
  opacity: 1;
}

/* The flat picture steps aside once the layers have taken over (UX/UI keeps it: its
   layers are the other screens fading in over it). */
.page-portfolio-categories .category-card.ph-on:not(.category-card--ux-ui-web-design) .bg-img {
  opacity: 0;
  transition: opacity 0.3s ease 0.3s;
}

.ph-stage {
  position: absolute;
  top: 0;
  left: 0;
  transform-origin: 0 0;
}

.ph-stage img,
.ph-stage canvas,
.ph-stage div {
  position: absolute;
  display: block;
  max-width: none;
}

/* Every CSS animation below starts parked; the script ramps its speed with the hover. */
.ph-track,
.ph-sem-text,
.ph-brand-bar,
.ph-brand-disc {
  will-change: transform;
}

/* UX/UI: the screens cross-fade, 1.5s apart (the timing is in the script). */
.category-card--ux-ui-web-design .ph-stage img {
  opacity: 0;
  transition: opacity 0.6s ease;
}

.category-card--ux-ui-web-design .ph-stage img.is-on {
  opacity: 1;
}

/* Mobile and pitch decks: six items (three, twice) on a track that moves one set
   (three slots) per 9s cycle, so it loops. The item in the middle slot is lit; the
   others sit at the opacity Figma gives the side ones. Each item reaches the middle
   once per cycle, 3s after the one before it, so one keyframe set phased by delay
   lights each as it passes: items 1 and 4 at 0s, 0 and 3 at 3s, 2 and 5 at 6s. */
.ph-mobile-row {
  top: 183px;
  left: 0;
  width: 464px;
  height: 666px;
}

.ph-mobile-track {
  top: 0;
  left: -1218px;
  animation: ph-mobile 9s linear infinite;
}

.ph-mobile-track img {
  border-radius: 32px;
  animation: ph-lit-mobile 9s ease-in-out infinite;
}

.ph-pitch-col {
  top: 0;
  left: 376px;
  width: 388px;
  height: 354px;
}

.ph-pitch-track {
  top: -863px;
  left: 0;
  animation: ph-pitch 9s linear infinite;
}

.ph-pitch-track img {
  border-radius: 24px;
  animation: ph-lit-pitch 9s ease-in-out infinite;
}

.ph-track img:nth-child(3n + 1) {
  animation-delay: -6s;
}

.ph-track img:nth-child(3n + 3) {
  animation-delay: -3s;
}

@keyframes ph-mobile {
  to { transform: translateX(972px); }
}

@keyframes ph-pitch {
  to { transform: translateY(699px); }
}

@keyframes ph-lit-mobile {
  0%, 100% { opacity: 1; }
  33.33%, 66.67% { opacity: 0.16; }
}

@keyframes ph-lit-pitch {
  0%, 100% { opacity: 1; }
  33.33%, 66.67% { opacity: 0.64; }
}

/* SEM: Figma's two ribbons, as text, running in opposite directions. Each holds five
   copies of its five words; moving by one copy (20%) loops seamlessly. */
.ph-sem-ribbon {
  width: 2512px;
  height: 71.6px;
  transform-origin: 50% 50%;
}

.ph-sem-copper {
  background: linear-gradient(180deg, #ffd6b1 0%, #d19966 50.521%, #e5b080 100%);
}

.ph-sem-dark {
  background: linear-gradient(180deg, #303030 0%, #323232 52.604%, #111 100%);
}

.ph-stage .ph-sem-text {
  top: 16px;
  left: 1024px;
  display: flex;
  color: #fff;
  font-family: "DM Sans", sans-serif;
  font-size: 36px;
  line-height: 1.1;
  font-variation-settings: "opsz" 14;
  white-space: nowrap;
  transform: translateX(-40%);
}

.ph-sem-set {
  display: flex;
  gap: 24px;
  padding-right: 24px;
}

.ph-sem-copper .ph-sem-text {
  animation: ph-sem-right 7s linear infinite;
}

.ph-sem-dark .ph-sem-text {
  animation: ph-sem-left 6s linear infinite;
}

@keyframes ph-sem-right {
  from { transform: translateX(-40%); }
  to { transform: translateX(-20%); }
}

@keyframes ph-sem-left {
  from { transform: translateX(-40%); }
  to { transform: translateX(-60%); }
}

/* SEO: each layer follows the pointer by its depth (--d); the script sets --mx/--my
   from -1 to 1 across the card. */
.ph-par {
  inset: 0;
  transform: translate3d(calc(var(--mx, 0) * var(--d) * -14px), calc(var(--my, 0) * var(--d) * -10px), 0);
  transition: transform 0.9s cubic-bezier(0.2, 0.7, 0.2, 1);
}

.ph-seo-crystal {
  inset: 0;
  transform: rotate(calc(var(--mx, 0) * 5deg));
  transform-origin: 258px 90px;
  transition: transform 0.9s cubic-bezier(0.2, 0.7, 0.2, 1);
}

/* Brand: the bar and the glass disc turn about their vertical axes. Their outline
   narrows as |cos| + (thickness / length) * |sin|, so neither goes paper-thin edge on,
   and they darken a little as their shaded side comes round. */
.ph-brand-bar {
  animation: ph-spin-bar 3.2s linear infinite;
}

.ph-brand-disc {
  animation: ph-spin-disc 5s linear infinite;
}

@keyframes ph-spin-bar {
  0%, 100% { transform: scaleX(1); filter: brightness(1); }
  8.33%, 91.67% { transform: scaleX(1.013); filter: brightness(0.993); }
  16.67%, 83.33% { transform: scaleX(0.956); filter: brightness(0.971); }
  25%, 75% { transform: scaleX(0.834); filter: brightness(0.936); }
  33.33%, 66.67% { transform: scaleX(0.656); filter: brightness(0.89); }
  41.67%, 58.33% { transform: scaleX(0.433); filter: brightness(0.837); }
  50% { transform: scaleX(0.18); filter: brightness(0.78); }
}

@keyframes ph-spin-disc {
  0%, 100% { transform: scaleX(1); filter: brightness(1); }
  8.33%, 91.67% { transform: scaleX(1.044); filter: brightness(0.993); }
  16.67%, 83.33% { transform: scaleX(1.016); filter: brightness(0.971); }
  25%, 75% { transform: scaleX(0.919); filter: brightness(0.936); }
  33.33%, 66.67% { transform: scaleX(0.76); filter: brightness(0.89); }
  41.67%, 58.33% { transform: scaleX(0.549); filter: brightness(0.837); }
  50% { transform: scaleX(0.3); filter: brightness(0.78); }
}
