/* ============================================================
   Abilities — fanned 3D flip cards on a perspective grid floor
   (pure DOM/CSS 3D, no WebGL)

   Resting card = front image aspect (684×939, portrait). On flip the
   card grows to a LANDSCAPE shape and the back image is rotated −90°
   (CCW) to read upright + fill it (the 1440×2400 files hold landscape
   content stored portrait). Left card on top; hover tints/lifts in
   place; click opens one large; outside/Esc closes.

   NOTE (WIP): grid floor is a plain white grid with no edge fade for
   easier tuning. Re-add the radial mask once the angle/size is dialled.

   Tunable knobs live on .abilities__deck — see the table below.
   ============================================================ */

#abilities { background: var(--bg); color: var(--fg); }

.abilities {
  --floor-tilt: 60deg;              /* shared by the floor + the card shadows */
  --title-gap: clamp(3.5rem, 5vh, 8rem);
  position: relative;
  overflow: hidden;                 /* clip the wide floor */
  min-height: 100vh;
  display: grid;
  align-content: center;
  gap: var(--title-gap);            /* gap between the title block and the deck */
  padding: var(--space-lg) var(--section-pad);
}

/* small hint under the title — pulled up tight so it reads as part of the
   title block, leaving the full --title-gap before the deck */
.abilities__hint {
  margin: calc(-1 * var(--title-gap) + 0.75rem) 0 0;
  font-size: var(--step-0);
  color: var(--fg-faint);
  text-align: center;
}

/* ---- subtle repeating dot grid (backmost motif, behind everything) ----
   | Variable    | Controls                                         |
   |-------------|--------------------------------------------------|
   | --dot-gap   | spacing between dots                              |
   | --dot-size  | dot radius                                        |
   | --dot-color | dot colour (alpha = subtlety)                     |
   | --dot-rx    | mask ellipse radius X (horizontal reach)          |
   | --dot-ry    | mask ellipse radius Y (vertical reach)            |
   | --dot-solid | radius kept fully opaque before the fade begins   | */
.abilities::before {
  content: "";
  --dot-gap: 26px;
  --dot-size: 1.5px;
  --dot-color: rgba(255, 255, 255, 0.06);
  --dot-rx: 55%;
  --dot-ry: 32%;
  --dot-solid: 20%;
  position: absolute;
  inset: 0;
  z-index: 0;                        /* above the section bg, behind the deck */
  pointer-events: none;
  background-image: radial-gradient(circle, var(--dot-color) var(--dot-size), transparent calc(var(--dot-size) + 0.5px));
  background-size: var(--dot-gap) var(--dot-gap);
  /* confine the dots to a horizontal ellipse centred on the deck */
  -webkit-mask-image: radial-gradient(ellipse var(--dot-rx) var(--dot-ry) at 50% 50%, #000 var(--dot-solid), transparent 100%);
  mask-image: radial-gradient(ellipse var(--dot-rx) var(--dot-ry) at 50% 50%, #000 var(--dot-solid), transparent 100%);
}

/* ---- perspective grid floor (plain white, no fade — WIP) ---- */
.abilities__floor {
  --floor-cell: 140px;               /* tile size on screen; --floor-tilt inherited from .abilities */
  --floor-fade-solid: 25%;          /* inner radius kept fully opaque */
  --floor-fade-end: 35%;            /* outer radius where it's fully gone */
  --floor-fade-cx: 50%;             /* mask centre X (in the floor's local box) */
  --floor-fade-cy: 50%;            /* mask centre Y — 100% = near/bottom edge */
  --floor-fade-rx: 60%;             /* mask ellipse radius X */
  --floor-fade-ry: 90%;             /* mask ellipse radius Y */

  position: absolute;
  left: 50%;
  bottom: -6vh;
  width: 300vw;
  height: 130vh;                    /* tall so the grid reaches up behind the cards */
  translate: -50% 0;
  transform-origin: 50% 100%;
  transform: perspective(700px) rotateX(var(--floor-tilt));
  opacity: 0.1;
  background-image: url("../assets/img/gridtile2.png");
  background-repeat: repeat;
  background-size: var(--floor-cell) var(--floor-cell);
  background-position: 50% 100%;    /* anchor tiling at the near edge so it stays put on resize */
  -webkit-mask-image: radial-gradient(ellipse var(--floor-fade-rx) var(--floor-fade-ry) at var(--floor-fade-cx) var(--floor-fade-cy), #000 var(--floor-fade-solid), transparent var(--floor-fade-end));
  mask-image: radial-gradient(ellipse var(--floor-fade-rx) var(--floor-fade-ry) at var(--floor-fade-cx) var(--floor-fade-cy), #000 var(--floor-fade-solid), transparent var(--floor-fade-end));
  pointer-events: none;
  z-index: 0;
}

/* ---- background sine-wave motif (behind the deck, above the floor) ----
   | Variable      | Controls                                    |
   |---------------|---------------------------------------------|
   | --wave-band   | vertical height of the wave band            |
   | --wave-cy     | vertical centre of the band (% of section)  |
   | --wave-speed  | base scroll duration (wave 2 runs slower)   | */
.abilities__waves {
  --wave-band: 320px;
  --wave-cy: 60%;
  --wave-speed: 16s;
  position: absolute;
  left: 0;
  right: 0;
  top: var(--wave-cy);
  height: var(--wave-band);
  translate: 0 -50%;
  z-index: 0;                        /* above the floor, behind the deck (z-index:1) */
  pointer-events: none;
  overflow: hidden;
}
.abilities__wave {
  position: absolute;
  inset: 0;
  background-image: var(--wave-img);
  background-repeat: repeat-x;
  background-position: 0 center;
  background-size: var(--wave-period) 100%;
  animation: abil-wave-scroll var(--wave-speed) linear infinite;
}
/* second wave: slower + opposite direction → phase relative to the first drifts */
.abilities__wave--2 { animation-duration: calc(var(--wave-speed) * 1.6); animation-direction: reverse; }
@keyframes abil-wave-scroll {
  to { background-position-x: var(--wave-period); }
}

/* ---- deck ---- */
.abilities__deck {
  /* | Variable       | Controls                                        |
     |----------------|-------------------------------------------------|
     | --card-w       | resting card width (height from front AR)       |
     | --front-ar     | front image aspect (w/h)                        |
     | --open-w       | opened (landscape) card width                   |
     | --open-ar      | opened card aspect (w/h) = rotated back content |
     | --fan-x        | horizontal step between adjacent cards          |
     | --fan-arc      | how much outer cards drop (arc curvature)       |
     | --fan-spread   | rotation step between adjacent cards (fan angle)|
     | --lift         | hover lift distance (local up)                  |
     | --open-y       | extra vertical nudge of the opened card         | */
  --card-w: clamp(168px, 17vw, 272px);      /* ~20% smaller at rest */
  --front-ar: calc(684 / 939);
  --card-h: calc(var(--card-w) / var(--front-ar));
  --open-w: clamp(576px, 79vw, 1176px);     /* ~20% larger when open */
  --open-ar: calc(2400 / 1440);     /* back content, once rotated → landscape */
  /* cap the opened height to the viewport so it never clips against the
     section's overflow:hidden; width is then derived to preserve --open-ar */
  --open-h: min(calc(var(--open-w) / var(--open-ar)), 74vh);
  --deck-h: calc(var(--card-h) * 1.35);

  --fan-x: clamp(120px, 15vw, 250px);
  --fan-arc: 22px;
  --fan-spread: 12deg;
  --lift: 30px;
  /* the deck is centred in the section together with the title+hint above it,
     so its centre sits ~half-the-top-block below the section centre. Nudge the
     opened card up by that much so it centres on screen instead of clipping the
     bottom. ~5.5rem ≈ title + hint height; --title-gap is the dominant term.
     (add your own offset by lowering/raising this value) */
  --open-y: calc((var(--title-gap) + 5.5rem) / -2);

  position: relative;
  z-index: 1;                        /* above the floor */
  height: var(--deck-h);
  perspective: 1700px;
  perspective-origin: 50% 42%;
}

.abil-card {
  --i0: calc(var(--i) - 1.5);        /* -1.5 … 1.5 */
  position: absolute;
  top: 0;
  left: 50%;
  width: var(--card-w);
  height: var(--card-h);
  padding: 0;
  background: none;
  z-index: calc(10 - var(--i));      /* left card stacked on top */
  transform-origin: 50% 50%;
  transform:
    translateX(-50%)
    translateX(calc(var(--i0) * var(--fan-x)))
    translateY(calc(var(--i0) * var(--i0) * var(--fan-arc)))
    rotate(calc(var(--i0) * var(--fan-spread)));
  transition: transform 0.55s var(--ease-out), width 0.6s var(--ease-out), height 0.6s var(--ease-out), opacity 0.4s ease, filter 0.4s ease;
  cursor: pointer;
}

/* fake floor shadow: a wide radial-gradient ellipse living INSIDE the
   floor. The floor is already tilted (perspective + rotateX) and is not
   preserve-3d, so its children are flattened onto that plane — the shadow
   lies flat on the grid with no tilt of its own. Positioned from the
   floor's near (bottom) edge, since the floor is the coordinate space now. */
.abil-shadow {
  --shadow-w: clamp(480px, 80vw, 1400px);
  --shadow-h: 300px;                 /* ellipse height on the floor plane */
  --shadow-up: 44vh;                 /* how far up the floor the ellipse sits (under the fan) */
  position: absolute;
  left: 50%;
  bottom: var(--shadow-up);
  width: var(--shadow-w);
  height: var(--shadow-h);
  transform: translate(-50%, 50%);   /* centre the ellipse on that point (floor supplies the tilt) */
  background: radial-gradient(ellipse at center, rgba(0, 0, 0, 0.9) 0%, rgba(0, 0, 0, 0.5) 40%, transparent 70%);
  filter: blur(14px);
  pointer-events: none;
  transition: opacity 0.4s ease;
}

.abil-card__inner {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  transition: transform 0.7s var(--ease-out);
}

.abil-card__face {
  position: absolute;
  inset: 0;
  border-radius: var(--r-md);
  overflow: hidden;
  border: 1px solid var(--border);
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  background: #0b0c09;
}
.abil-card__face img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* back = flipped face; image rotated −90° (CCW), sized via container
   units so the swapped box fills the face exactly after rotation */
.abil-card__back { transform: rotateY(180deg); container-type: size; }
.abil-card__back img {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 100cqh;                    /* swapped: img width  = face height */
  height: 100cqw;                   /* swapped: img height = face width  */
  transform: translate(-50%, -50%) rotate(-90deg);
}

/* hover tint glow rising from the base */
.abil-card__front::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(130% 100% at 50% 100%, rgba(156, 227, 37, 0.32), transparent 68%);
  opacity: 0;
  transition: opacity 0.3s ease;
  pointer-events: none;
}

/* ---- hover (no z-index change → card keeps its order) ---- */
.abil-card:not(.is-open):hover .abil-card__inner { transform: translateY(calc(-1 * var(--lift))); }
.abil-card:not(.is-open):hover .abil-card__front { border-color: var(--accent); box-shadow: 0 0 30px rgba(156, 227, 37, 0.4); }
.abil-card:not(.is-open):hover .abil-card__front::after { opacity: 1; }

/* ---- open: grow to landscape, centred in the deck, flipped ---- */
.abilities__deck.has-open .abil-card:not(.is-open) { opacity: 0.25; filter: blur(2px); pointer-events: none; }
.abil-card.is-open {
  z-index: 30;
  width: calc(var(--open-h) * var(--open-ar));   /* derive from capped height → keeps AR + fits screen */
  height: var(--open-h);
  transform: translateX(-50%) translateY(calc((var(--deck-h) - var(--open-h)) / 2 + var(--open-y)));
}
.abilities:has(.abilities__deck.has-open) .abil-shadow { opacity: 0; }
.abil-card.is-open .abil-card__inner { transform: rotateY(180deg); }

/* dim (not hide) the section title while a card is open, to push focus to it */
.abilities .section-title { transition: opacity 0.45s ease; }
.abilities:has(.abilities__deck.has-open) .section-title { opacity: 0.15; }

@media (prefers-reduced-motion: reduce) {
  .abil-card__inner, .abil-card { transition: none; }
  .abilities__wave { animation: none; }
}
