/* ==========================================================================
   components.css — buttons, carousel, filters, project grid, hover effects
   ========================================================================== */

/* ---------- Buttons ---------- */
.btn {
  position: relative;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  font-family: var(--font-display);
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  padding: 0.7em 1.4em;
  border-radius: 999px;
  border: 1px solid var(--ink);
  transition:
    background-color var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    transform 400ms var(--ease-spring);
}
.btn:active { transform: scale(0.97); }

.btn--primary { background: var(--ink); color: var(--paper); }
.btn--primary:hover { background: var(--accent); border-color: var(--accent); }

.btn--ghost { background: transparent; color: var(--ink); }
.btn--ghost:hover { background: var(--ink); color: var(--paper); }

.btn--cv {
  font-size: 0.8125rem;
  padding: 0.55em 1.1em;
  background: var(--ink);
  color: var(--paper);
}
.btn--cv:hover { background: var(--accent); border-color: var(--accent); }

/* ---------- Carousel ---------- */
.carousel {
  position: relative;
  border-radius: var(--radius);
}
.carousel__viewport {
  overflow: hidden;
  border-radius: var(--radius);
  cursor: grab;
  touch-action: pan-y;
}
.carousel.is-dragging .carousel__viewport { cursor: grabbing; }

.carousel__track {
  display: flex;
  will-change: transform;
}
.carousel__slide {
  position: relative;
  flex: 0 0 100%;
  min-width: 0;
  aspect-ratio: 4 / 3;
  background: #e6e1d6;
  user-select: none;
}
.carousel__slide img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
}
.carousel__link { display: block; height: 100%; }

.carousel__caption {
  position: absolute;
  left: var(--s-4);
  bottom: var(--s-4);
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-2) var(--s-4);
  background: var(--paper);
  border-radius: 999px;
  font-family: var(--font-display);
  font-size: 0.875rem;
  font-weight: 600;
  letter-spacing: -0.01em;
}
.carousel__tag {
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
}

.carousel { perspective: 1100px; }
.carousel__stage {
  position: relative;
  will-change: transform;
}

/* Arrows overlay each end of the stage, vertically centered.
   Positioned via top calc (no transform) so the magnetic hover in motion.js
   can own the transform without jumping. */
.carousel__arrow {
  position: absolute;
  top: calc(50% - 1.375rem);
  z-index: 2;
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  color: var(--ink);
  background: var(--paper-80);
  backdrop-filter: blur(6px);
  border: 1px solid var(--line);
  border-radius: 50%;
  cursor: pointer;
  transition:
    background-color var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out);
}
.carousel__arrow--prev { left: var(--s-3); }
.carousel__arrow--next { right: var(--s-3); }
.carousel__arrow:hover {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--paper);
}
.carousel__counter {
  margin-top: var(--s-3);
  text-align: right;
  font-family: var(--font-display);
  font-size: 0.8125rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  color: var(--ink-50);
  font-variant-numeric: tabular-nums;
}

/* ---------- Filters ---------- */
.filters {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-5);
  margin-bottom: var(--s-7);
}
.filters__btn {
  position: relative;
  padding-block: var(--s-2);
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--ink-50);
  transition: color var(--dur-fast) var(--ease-out);
}
.filters__btn::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1.5px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform var(--dur-med) var(--ease-out);
}
.filters__btn:hover { color: var(--ink); }
.filters__btn.is-active { color: var(--ink); }
.filters__btn.is-active::after {
  transform: scaleX(1);
  transform-origin: left;
}

/* ---------- Project grid ---------- */
.work__grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: clamp(var(--s-5), 3vw, var(--s-7)) clamp(var(--s-4), 2.5vw, var(--s-6));
  align-items: end;
}

.project { min-width: 0; }
.span-4  { grid-column: span 4; }
.span-5  { grid-column: span 5; }
.span-6  { grid-column: span 6; }
.span-7  { grid-column: span 7; }
.span-12 { grid-column: span 12; }

.project__card { display: block; }

.project__media {
  position: relative;
  aspect-ratio: var(--ratio, 4/3);
  overflow: hidden;
  border-radius: var(--radius);
  background: #e6e1d6;
  transform-origin: center;
}
.project__media img,
.project__media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition:
    transform var(--dur-med) var(--ease-out),
    filter var(--dur-med) var(--ease-out),
    opacity var(--dur-med) var(--ease-out);
  will-change: transform;
}

.project__meta {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-4);
  padding-top: var(--s-3);
}
.project__title {
  font-family: var(--font-display);
  font-size: clamp(1.0625rem, 1.6vw, 1.25rem);
  font-weight: 600;
  letter-spacing: -0.015em;
  transition: color var(--dur-fast) var(--ease-out);
}
.project__card:hover .project__title { color: var(--accent); }
.project__info {
  font-size: 0.8125rem;
  color: var(--ink-50);
  white-space: nowrap;
}

/* Filtering states */
.project.is-filtered-out { display: none; }
.project.is-entering .project__card { animation: project-in 575ms var(--ease-out) both; }
@keyframes project-in {
  from { opacity: 0; transform: translateY(20px) scale(0.985); }
  to   { opacity: 1; transform: none; }
}

/* ==========================================================================
   Per-project hover behaviors — configured via data-hover on .project
   (desktop hover-capable devices only; see media query at bottom)
   ========================================================================== */
@media (hover: hover) and (pointer: fine) {

  /* zoom — image scales up inside the frame (thmbtng zoom value) */
  .project[data-hover="zoom"] .project__card:hover img { transform: scale(1.1); }

  /* scale — whole card breathes */
  .project[data-hover="scale"] .project__media {
    transition: transform var(--dur-med) var(--ease-out);
  }
  .project[data-hover="scale"] .project__card:hover .project__media { transform: scale(0.975); }
  .project[data-hover="scale"] .project__card:hover img { transform: scale(1.05); }

  /* tilt — 3D tilt follows the cursor (values driven from JS) */
  .project[data-hover="tilt"] .project__media {
    transform: perspective(900px)
      rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg));
    transition: transform 185ms linear;
  }

  /* follow — image drifts toward the cursor (values driven from JS) */
  .project[data-hover="follow"] img {
    transform: translate(var(--follow-x, 0), var(--follow-y, 0)) scale(1.06);
    transition: transform 230ms var(--ease-out);
  }

  /* blur — image starts soft and focuses on hover */
  .project[data-hover="blur"] img { filter: blur(6px) saturate(0.85); }
  .project[data-hover="blur"] .project__card:hover img { filter: blur(0) saturate(1); }

  /* reveal — cover wipes away to expose the artwork */
  .project[data-hover="reveal"] .project__media::after {
    content: "";
    position: absolute;
    inset: 0;
    background: var(--ink);
    transform: translateY(0);
    transition: transform 630ms var(--ease-out);
  }
  .project[data-hover="reveal"] .project__card:hover .project__media::after {
    transform: translateY(-101%);
  }

  /* rotate — slight editorial twist */
  .project[data-hover="rotate"] .project__media {
    transition: transform var(--dur-med) var(--ease-out);
  }
  .project[data-hover="rotate"] .project__card:hover .project__media {
    transform: rotate(-1.5deg) scale(1.015);
  }
}

/* Touch devices: disable transitions that only make sense with hover */
@media (hover: none) {
  .project__media img { transition: opacity var(--dur-med) var(--ease-out); }
  .project[data-hover="blur"] img { filter: none; }
}

/* ---------- Responsive grid ---------- */
@media (max-width: 64em) {
  .span-4, .span-5, .span-6, .span-7 { grid-column: span 6; }
  .span-12 { grid-column: span 12; }
}
@media (max-width: 40em) {
  .work__grid { align-items: start; }
  .span-4, .span-5, .span-6, .span-7, .span-12 { grid-column: span 12; }
  .project__meta { flex-direction: column; gap: var(--s-1); }
}

/* ---------- WhatsApp bubble (style after shuka.design's contact bubble:
   90px circle, bottom-right, inset ring, scale on hover) ---------- */
.wa-bubble[hidden] { display: none; } /* author display beats the UA hidden rule */
.wa-bubble {
  position: fixed;
  right: 40px;
  bottom: 40px;
  z-index: 95;
  display: grid;
  place-items: center;
  width: 90px;
  height: 90px;
  border-radius: 50%;
  background: var(--paper);
  color: var(--ink);
  box-shadow:
    inset 0 0 2px 0 rgb(192 192 192),
    0 10px 30px rgba(25, 22, 19, 0.14);
  transition:
    transform 400ms var(--ease-spring),
    box-shadow 400ms var(--ease-out);
}
.wa-bubble svg { width: 38px; height: 38px; }
.wa-bubble:hover {
  transform: scale(1.08);
  box-shadow:
    inset 0 0 2px 0 rgb(192 192 192),
    0 16px 40px rgba(25, 22, 19, 0.2);
}
.wa-bubble:active { transform: scale(0.96); }
@media (max-width: 48em) {
  .wa-bubble { width: 64px; height: 64px; right: 24px; bottom: 24px; }
  .wa-bubble svg { width: 28px; height: 28px; }
}

/* ---------- Discipline ticker (the page's single marquee) ---------- */
.ticker {
  overflow: hidden;
  border-block: 1px solid var(--line);
  padding-block: var(--s-5);
}
.ticker__track {
  display: flex;
  width: max-content;
  animation: ticker-scroll 37s linear infinite;
}
.ticker:hover .ticker__track { animation-play-state: paused; }
.ticker__seq {
  font-family: var(--font-display);
  font-size: clamp(1.25rem, 2.4vw, 2rem);
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--ink-50);
  white-space: nowrap;
}
.ticker__seq i {
  font-style: normal;
  color: var(--accent);
  margin-inline: var(--s-5);
}
@keyframes ticker-scroll {
  to { transform: translateX(-50%); }
}

/* About sits directly under the ticker — avoid a double hairline */
.about { border-top: 0; }

/* ---------- Scroll-driven image drift (pure CSS, progressive enhancement) ---------- */
@keyframes img-drift {
  from { transform: translateY(-5%) scale(1.12); }
  to   { transform: translateY(5%)  scale(1.12); }
}
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .about__portrait img,
    .carousel__slide img {
      animation: img-drift linear both;
      animation-timeline: view();
      animation-range: entry 0% exit 100%;
    }
  }
}

/* ---------- tasteskill.dev button signatures (adapted) ---------- */

/* sheen-return — light sweep crosses the button, holds, returns. */
.btn::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, transparent 25%, rgba(244, 242, 237, 0.35) 50%, transparent 75%);
  transform: translateX(-125%);
  pointer-events: none;
}
.btn--ghost::after {
  background: linear-gradient(100deg, transparent 25%, rgba(25, 22, 19, 0.09) 50%, transparent 75%);
}
@keyframes sheen-return {
  0%   { transform: translateX(-125%); }
  42%  { transform: translateX(125%); }
  58%  { transform: translateX(125%); }
  100% { transform: translateX(-125%); }
}

/* icon-nudge — playful spring wiggle on the CV download icon */
@keyframes icon-nudge {
  0%, 100% { transform: translate(0) rotate(0); }
  35%      { transform: translate(1px, -1px) rotate(-4deg); }
  65%      { transform: translate(-1px) rotate(3deg); }
}

@media (prefers-reduced-motion: no-preference) {
  .btn:hover::after { animation: sheen-return 1.2s cubic-bezier(0.33, 1, 0.68, 1) forwards; }
  .btn--cv:hover svg { animation: icon-nudge 0.63s var(--ease-spring); }
}

/* ---------- Reference-site hover behaviors (adapted from their production CSS) ---------- */

/* Rafa Frantic figcaption overlay: fades in over the media, his exact
   timing (opacity .3s linear) and backdrop blur(5px) */
.project__view {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  padding: 8px 15px; /* rafa figcaption literal */
  background: rgba(25, 22, 19, 0.55);
  -webkit-backdrop-filter: blur(5px);
  backdrop-filter: blur(5px);
  color: var(--paper);
  font-family: var(--font-display);
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  opacity: 0;
  transition: opacity 0.35s linear;
  pointer-events: none;
}

/* THMBTNG hover-image swap: alternate "detail" image fades in over the
   base image (their .hover-image pattern, opacity .3s) */
.project__alt {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition:
    opacity 0.35s,
    transform var(--dur-med) var(--ease-out);
}

/* reveal cards already own a full-frame hover behavior — no overlay there */
.project[data-hover="reveal"] .project__view,
.project[data-hover="glitch"] .project__view,
.project[data-hover="distortion"] .project__view { display: none; }

@media (hover: hover) and (pointer: fine) {
  .project__card:hover .project__view,
  .project__card:hover .project__alt { opacity: 1; }
}

/* ---------- Filter blocks — thmbtng child literal: small block fades in
   before the active/hovered category label (transition:opacity .3s) ---------- */
.filters__btn::before {
  content: "";
  display: inline-block;
  width: 0.5em;
  height: 0.5em;
  margin-right: 0.45em;
  background: var(--accent);
  opacity: 0;
  transition: opacity 0.35s;
}
.filters__btn:hover::before,
.filters__btn.is-active::before { opacity: 1; }

/* ---------- Remaining hover behaviors from the brief (configurable per project) ---------- */
@media (hover: hover) and (pointer: fine) {

  /* distortion — liquid skew wobble while hovered */
  @keyframes distort-wobble {
    0%, 100% { transform: scale(1.05) skewX(0deg) scaleY(1); }
    33%      { transform: scale(1.05) skewX(-2.5deg) scaleY(1.03); }
    66%      { transform: scale(1.05) skewX(2deg) scaleY(0.98); }
  }
  .project[data-hover="distortion"] .project__card:hover img {
    animation: distort-wobble 1.6s ease-in-out infinite;
  }

  /* glitch — two clip-path slice bursts with hue split, then settles */
  @keyframes glitch-shift {
    0%, 100% { transform: translate(0); clip-path: inset(0 0 0 0); filter: none; }
    20% { transform: translate(-4px, 2px); clip-path: inset(12% 0 64% 0); filter: hue-rotate(40deg) saturate(1.7); }
    40% { transform: translate(4px, -2px); clip-path: inset(56% 0 10% 0); filter: none; }
    60% { transform: translate(-3px, -1px); clip-path: inset(30% 0 40% 0); filter: hue-rotate(-30deg); }
    80% { transform: translate(3px, 1px); clip-path: inset(68% 0 6% 0); filter: saturate(0.4); }
  }
  .project[data-hover="glitch"] .project__card:hover img {
    animation: glitch-shift 0.575s steps(2, end) 2;
  }
}
