/* ===== ProfileCard (React Bits, vanilla port) =====
   Ported from React Bits <https://reactbits.dev>, MIT + Commons Clause,
   Copyright (c) 2026 David Haz. The licence permits use as part of a website;
   it does not permit selling or redistributing the component itself.

   Same treatment as css/option-wheel.css: upstream ships a React component
   plus its own stylesheet, and this is the stylesheet half. Three deliberate
   departures from upstream:

   1. The variable defaults live on .pc-card-wrapper, not :root. Upstream can
      own :root because the card is the whole demo; here :root already carries
      this site's design tokens and the card has no business adding fifteen
      more to it. The JS writes the pointer variables onto the wrapper anyway,
      so they inherit down from exactly where they are set.
   2. The palette is retuned from upstream's blue/violet to this site's warm
      amber. The iridescent "sunpillar" ramp keeps its hue spread — that
      spread IS the holographic effect — but is pulled toward the warm half of
      the wheel so it reads as the same family as the accent.
   3. Upstream's `glow-bg` animation is dropped. It animates --bgrotate, an
      unregistered custom property, which no browser interpolates and which
      nothing else in the file reads: a no-op, not a missing feature. */

.pc-card-wrapper {
  /* Driven every frame by js/profile-card.js */
  --pointer-x: 50%;
  --pointer-y: 50%;
  --pointer-from-center: 0;
  --pointer-from-top: 0.5;
  --pointer-from-left: 0.5;
  --background-x: 50%;
  --background-y: 50%;
  --rotate-x: 0deg;
  --rotate-y: 0deg;
  --card-opacity: 0;

  /* Set per-instance from the JS options */
  --grain: none;
  --icon: none;
  --behind-glow-color: rgba(219, 107, 43, 0.62);
  --behind-glow-size: 50%;
  /* Kept deliberately dark. .pc-shine composites with color-dodge, which is
     base / (1 - blend): the brighter the base, the sooner it clips to white.
     The first cut of this gradient sat at roughly 2.3x upstream's luminance
     and the whole card blew out to white the moment it went active. This
     lands near upstream's level while staying in the amber family, with a
     violet shadow end because that hue split is what reads as holographic. */
  --inner-gradient: linear-gradient(145deg, rgba(219, 107, 43, 0.30) 0%, rgba(78, 46, 120, 0.22) 100%);

  /* Warm-biased iridescence: amber to gold to rose to violet, so the sheen
     still separates into bands without pulling the card out of the site's
     colour family. */
  --sunpillar-1: hsl(18, 100%, 70%);
  --sunpillar-2: hsl(40, 100%, 70%);
  --sunpillar-3: hsl(62, 90%, 72%);
  --sunpillar-4: hsl(340, 85%, 74%);
  --sunpillar-5: hsl(292, 80%, 74%);
  --sunpillar-6: hsl(8, 95%, 72%);
  --sunpillar-clr-1: var(--sunpillar-1);
  --sunpillar-clr-2: var(--sunpillar-2);
  --sunpillar-clr-3: var(--sunpillar-3);
  --sunpillar-clr-4: var(--sunpillar-4);
  --sunpillar-clr-5: var(--sunpillar-5);
  --sunpillar-clr-6: var(--sunpillar-6);

  --card-radius: 26px;
  /* Width is derived from the height so the aspect ratio stays intact and the
     wrapper hugs the card. That matters: .pc-behind is inset:0 on this box,
     so a wrapper wider than the card would smear the glow across the whole
     column instead of tracking the card. */
  --pc-card-h: clamp(360px, 54svh, 460px);

  width: calc(var(--pc-card-h) * 0.718);
  margin: 0 auto;
  perspective: 500px;
  transform: translate3d(0, 0, 0.1px);
  position: relative;
  touch-action: none;
}

.pc-behind {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: radial-gradient(
    circle at var(--pointer-x) var(--pointer-y),
    var(--behind-glow-color) 0%,
    transparent var(--behind-glow-size)
  );
  filter: blur(50px) saturate(1.1);
  opacity: calc(0.8 * var(--card-opacity));
  transition: opacity 200ms ease;
}

.pc-card-wrapper:hover,
.pc-card-wrapper.active {
  --card-opacity: 1;
}

.pc-card-shell {
  position: relative;
  z-index: 1;
}

.pc-card {
  height: var(--pc-card-h);
  /* ===== Il testo scala con la card, e questa e' la correzione chiave =====
     Le misure qui dentro erano in pixel fissi: sul telefono la card si
     rimpicciolisce del 30% e il testo restava identico. Risultato: "Luca
     Curseri" scivolava dalla parete vuota giu' sulla testa, "Web Dev x AI"
     passava dal 66% al 95% della larghezza e finiva sugli occhiali, e la
     barra in basso non conteneva piu' il pulsante, che veniva tagliato.

     Legando la misura di base all'altezza della card, tutto quello che e'
     scritto in em la segue: la stessa proporzione a qualunque dimensione, e
     quindi la stessa impaginazione che su desktop funziona gia'.

     Il divisore e' scelto perche' NON cambi niente su desktop: li' la card
     e' alta 460px, e 460/28.75 fa esattamente i 16px che il testo aveva. */
  font-size: calc(var(--pc-card-h) / 28.75);
  display: grid;
  aspect-ratio: 0.718;
  border-radius: var(--card-radius);
  position: relative;
  background-blend-mode: color-dodge, normal, normal, normal;
  box-shadow: rgba(0, 0, 0, 0.8) calc((var(--pointer-from-left) * 10px) - 3px)
    calc((var(--pointer-from-top) * 20px) - 6px) 20px -5px;
  transition: transform 1s var(--ease);
  transform: translateZ(0) rotateX(0deg) rotateY(0deg);
  background: rgba(0, 0, 0, 0.9);
  backface-visibility: hidden;
  overflow: hidden;
  /* One explicit full-bleed cell. Upstream leaves the grid implicit and
     places every layer at `grid-area: 1/-1`, relying on a negative line in a
     grid that has no explicit columns; here that resolved to an auto track
     sized to content (276px) and parked against the right edge, leaving 54px
     of the card's own black background showing down the left side. Naming the
     track removes the ambiguity instead of working around it. */
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr);
}

.pc-card.active {
  transition: none;
  transform: translateZ(0) rotateX(var(--rotate-y)) rotateY(var(--rotate-x));
}

.pc-card-shell.entering .pc-card {
  transition: transform 180ms ease-out;
}

/* The component's layout mechanism: every layer stacks in that one cell. */
.pc-card * {
  display: grid;
  grid-area: 1 / 1;
  border-radius: var(--card-radius);
  pointer-events: none;
}

.pc-inside {
  inset: 0;
  position: absolute;
  background-image: var(--inner-gradient);
  background-color: rgba(0, 0, 0, 0.9);
  transform: none;
}

.pc-shine {
  /* --icon masks this layer: the iridescence shows through the pattern's
     bright areas only. The -webkit- longhands are for Safari versions that
     ship masking without `mask-mode` — the pattern is drawn to read the same
     under alpha masking, so they need no separate artwork. */
  mask-image: var(--icon);
  mask-mode: luminance;
  mask-repeat: repeat;
  mask-size: 150%;
  mask-position: top calc(200% - (var(--background-y) * 5)) left calc(100% - var(--background-x));
  -webkit-mask-image: var(--icon);
  -webkit-mask-repeat: repeat;
  -webkit-mask-size: 150%;
  -webkit-mask-position: top calc(200% - (var(--background-y) * 5)) left calc(100% - var(--background-x));
  transition: filter 0.8s ease;
  filter: brightness(0.66) contrast(1.33) saturate(0.33) opacity(0.5);
  animation: pc-holo-bg 18s linear infinite;
  mix-blend-mode: color-dodge;
}

.pc-shine,
.pc-shine::after {
  --space: 5%;
  --angle: -45deg;
  transform: translate3d(0, 0, 1px);
  overflow: hidden;
  z-index: 3;
  background: transparent;
  background-size: cover;
  background-position: center;
  background-image:
    repeating-linear-gradient(
      0deg,
      var(--sunpillar-clr-1) calc(var(--space) * 1),
      var(--sunpillar-clr-2) calc(var(--space) * 2),
      var(--sunpillar-clr-3) calc(var(--space) * 3),
      var(--sunpillar-clr-4) calc(var(--space) * 4),
      var(--sunpillar-clr-5) calc(var(--space) * 5),
      var(--sunpillar-clr-6) calc(var(--space) * 6),
      var(--sunpillar-clr-1) calc(var(--space) * 7)
    ),
    repeating-linear-gradient(
      var(--angle),
      #14100e 0%,
      hsl(28, 12%, 60%) 3.8%,
      hsl(28, 34%, 68%) 4.5%,
      hsl(28, 12%, 60%) 5.2%,
      #14100e 10%,
      #14100e 12%
    ),
    radial-gradient(
      farthest-corner circle at var(--pointer-x) var(--pointer-y),
      hsla(0, 0%, 0%, 0.1) 12%,
      hsla(0, 0%, 0%, 0.15) 20%,
      hsla(0, 0%, 0%, 0.25) 120%
    );
  background-position:
    0 var(--background-y),
    var(--background-x) var(--background-y),
    center;
  background-blend-mode: color, hard-light;
  background-size:
    500% 500%,
    300% 300%,
    200% 200%;
  background-repeat: repeat;
}

.pc-shine::before,
.pc-shine::after {
  content: '';
  background-position: center;
  background-size: cover;
  grid-area: 1/1;
  opacity: 0;
  transition: opacity 0.8s ease;
}

/* Upstream lights the glyph layer on hover: ::before/::after fade in and the
   filter drops its opacity(0.5), so every coding symbol flares at once and the
   18s drift freezes while the pointer is on the card. Deliberately not done
   here — the symbols keep their resting look and keep drifting no matter where
   the cursor is. The card's tilt and its behind-glow still respond as usual;
   only this layer sits the hover out, which is why the two ::before/::after
   gradients below stay defined but never rise above opacity 0. */

.pc-shine::before {
  background-image:
    linear-gradient(
      45deg,
      var(--sunpillar-4),
      var(--sunpillar-5),
      var(--sunpillar-6),
      var(--sunpillar-1),
      var(--sunpillar-2),
      var(--sunpillar-3)
    ),
    radial-gradient(circle at var(--pointer-x) var(--pointer-y), hsl(0, 0%, 70%) 0%, hsla(0, 0%, 30%, 0.2) 90%),
    var(--grain);
  background-size:
    250% 250%,
    100% 100%,
    220px 220px;
  background-position:
    var(--pointer-x) var(--pointer-y),
    center,
    calc(var(--pointer-x) * 0.01) calc(var(--pointer-y) * 0.01);
  background-blend-mode: color-dodge;
  /* Upstream drives these up to brightness(2)/contrast(3) at centre. Halved
     here: the amber base is warmer than upstream's cool one, so the same
     numbers clip. */
  /* Saturation is the lever that keeps this in the site's palette: upstream
     runs it up to 1.5 and the glyphs go full green/cyan/magenta rainbow, which
     fights an amber page. Held low, the same ramp reads as warm iridescence. */
  filter: brightness(calc(1.42 - var(--pointer-from-center) * 0.42)) contrast(calc(var(--pointer-from-center) * 0.6 + 1.38))
    saturate(calc(0.28 + var(--pointer-from-center) * 0.32));
  mix-blend-mode: luminosity;
}

.pc-shine::after {
  background-position:
    0 var(--background-y),
    calc(var(--background-x) * 0.4) calc(var(--background-y) * 0.5),
    center;
  background-size:
    200% 300%,
    700% 700%,
    100% 100%;
  mix-blend-mode: difference;
  filter: brightness(0.8) contrast(1.5);
}

.pc-glare {
  transform: translate3d(0, 0, 1.1px);
  overflow: hidden;
  background-image: radial-gradient(
    farthest-corner circle at var(--pointer-x) var(--pointer-y),
    hsl(28, 32%, 58%) 12%,
    hsla(24, 45%, 18%, 0.8) 90%
  );
  mix-blend-mode: overlay;
  filter: brightness(0.6) contrast(1.1);
  z-index: 4;
}

.pc-avatar-content {
  mix-blend-mode: luminosity;
  overflow: visible;
  backface-visibility: hidden;
}

.pc-avatar-content .avatar {
  width: 100%;
  position: absolute;
  left: 50%;
  transform-origin: 50% 100%;
  transform: translateX(calc(-50% + (var(--pointer-from-left) - 0.5) * 6px)) translateZ(0)
    scaleY(calc(1 + (var(--pointer-from-top) - 0.5) * 0.02)) scaleX(calc(1 + (var(--pointer-from-left) - 0.5) * 0.01));
  bottom: -1px;
  backface-visibility: hidden;
  will-change: transform;
  transition: transform 120ms ease-out;
}

.pc-user-info {
  position: absolute;
  --ui-inset: 1.125em;   /* erano 18px fissi */
  --ui-radius-bias: 6px;
  bottom: var(--ui-inset);
  left: var(--ui-inset);
  right: var(--ui-inset);
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.625em;
  background: rgba(255, 255, 255, 0.08);
  backdrop-filter: blur(30px);
  -webkit-backdrop-filter: blur(30px);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: calc(max(0px, var(--card-radius) - var(--ui-inset) + var(--ui-radius-bias)));
  padding: 0.625em 0.75em;
  pointer-events: auto;
}

.pc-user-details {
  display: flex;
  align-items: center;
  gap: 10px;
}

.pc-mini-avatar {
  width: 2.5em;
  height: 2.5em;
  border-radius: 50%;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.14);
  flex-shrink: 0;
  background: rgba(219, 107, 43, 0.18);
}

.pc-mini-avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 50%;
}

.pc-user-text {
  display: flex;
  align-items: flex-start;
  flex-direction: column;
  gap: 0.3125em;
  /* Puo' stringersi: se lo spazio manca, a cedere e' il testo — che al
     massimo si accorcia — non il pulsante, che verrebbe tagliato. */
  min-width: 0;
}

.pc-handle {
  font-family: var(--font-mono);
  font-size: max(11px, 0.8125em);
  font-weight: 500;
  color: rgba(255, 255, 255, 0.9);
  line-height: 1;
  /* Se non ci sta, si accorcia con i puntini invece di spingere fuori il
     pulsante accanto. */
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pc-status {
  font-size: max(9px, 0.75em);
  color: rgba(255, 255, 255, 0.62);
  line-height: 1;
}

.pc-contact-btn {
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.04);
  border-radius: 0.5em;
  padding: 0.625em 0.875em;
  font-family: inherit;
  font-size: max(10px, 0.75em);
  font-weight: 600;
  color: rgba(255, 255, 255, 0.92);
  cursor: pointer;
  white-space: nowrap;
  transition: border-color 0.2s var(--ease), transform 0.2s var(--ease), background 0.2s var(--ease);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  pointer-events: auto;
}

.pc-contact-btn:hover {
  border-color: var(--accent);
  background: rgba(219, 107, 43, 0.22);
  transform: translateY(-1px);
}

.pc-content:not(.pc-avatar-content) {
  max-height: 100%;
  overflow: hidden;
  text-align: center;
  position: relative;
  transform: translate3d(
    calc(var(--pointer-from-left) * -6px + 3px),
    calc(var(--pointer-from-top) * -6px + 3px),
    0.1px
  );
  z-index: 5;
  mix-blend-mode: luminosity;
}

.pc-details {
  width: 100%;
  position: absolute;
  /* Ancorato in cima invece che a 2.4em, e la distanza diventa padding. Il
     testo resta esattamente dove stava; cambia che la velatura qui sotto puo'
     partire dal bordo vero della card invece che da meta' strada, dove si
     sarebbe vista come una fascia incollata. */
  top: 0;
  padding: 2.4em 0 1.4em;
  display: flex;
  flex-direction: column;

  /* ===== La velatura =====
     "Le scritte si vedono poco": vero, e non per come sono scritte. Il titolo
     e il ruolo sono riempiti con un gradiente che va dal bianco all'ambra, e
     l'ambra atterra su una foto calda — colore chiaro su colore chiaro. Da
     qui in giu' il contrasto non si recupera ritoccando il testo, si recupera
     dandogli un fondo.

     Nera e sfumata a niente: dove c'e' scritto scurisce quanto basta a far
     staccare le lettere, e sotto sparisce senza lasciare un bordo. Vale anche
     su desktop, dove il titolo cade sulla parete chiara. */
  background: linear-gradient(180deg,
    rgba(0, 0, 0, 0.46) 0%,
    rgba(0, 0, 0, 0.34) 46%,
    rgba(0, 0, 0, 0.12) 78%,
    transparent 100%);
  /* Segue l'angolo della card in alto, o la velatura sborderebbe dai vertici
     arrotondati sopra la foto. */
  border-radius: var(--card-radius) var(--card-radius) 0 0;
  pointer-events: none;
}

.pc-details h3 {
  font-family: var(--font-serif);
  font-weight: 500;
  margin: 0;
  /* Era min(5svh, 2.5em): legata all'ALTEZZA DELLO SCHERMO invece che alla
     card. Su un telefono alto e una card piccola le due cose divergono, ed
     e' cosi' che il titolo finiva sul viso. Ora segue solo la card. */
  font-size: 2.5em;
  line-height: 1.05;
  background-image: linear-gradient(to bottom, #fff, #c98a5f);
  background-size: 1em 1.6em;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  -webkit-background-clip: text;
}

.pc-details p {
  font-family: var(--font-mono);
  font-weight: 500;
  position: relative;
  top: -6px;
  white-space: nowrap;
  /* Segue la card, ma non sotto una soglia leggibile. Senza il max() su
     uno schermo corto veniva 9px: proporzionato e inutilizzabile. */
  font-size: max(11px, 0.8125em);   /* erano 13px fissi */
  letter-spacing: 0.06em;
  margin: 0 auto;
  width: min-content;
  background-image: linear-gradient(to bottom, #fff, #b36a3c);
  background-size: 1em 1.5em;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  -webkit-background-clip: text;
}

@keyframes pc-holo-bg {
  0% {
    background-position:
      0 var(--background-y),
      0 0,
      center;
  }
  100% {
    background-position:
      0 var(--background-y),
      90% 90%,
      center;
  }
}

/* js/profile-card.js skips the tilt entirely under reduced motion; this stops
   the ambient holo drift and the avatar parallax easing as well. */
@media (prefers-reduced-motion: reduce) {
  .pc-shine { animation: none; }
  .pc-card,
  .pc-avatar-content .avatar,
  .pc-behind { transition: none; }
}

@media (max-width: 980px) {
  .pc-card-wrapper { --pc-card-h: clamp(320px, 46svh, 420px); }
}

@media (max-width: 560px) {
  .pc-card-wrapper {
    --pc-card-h: clamp(300px, 42svh, 380px);
    --card-radius: 22px;
  }
  /* Le misure fisse che stavano qui — inset, padding, avatar, handle,
     status, pulsante — sono sparite: ora tutto e' in em e segue la card da
     solo, a qualunque dimensione. Erano tarate su una card da 300-380px,
     mentre css/responsive.css la porta a 280-420: e' da quel disallineamento
     che nasceva il pulsante tagliato. Un elenco di numeri in meno da tenere
     allineato a mano. */
  /* Era top: 1.8em. Da quando .pc-details e ancorata in cima e la distanza
     dal bordo la fa il padding — cosi la velatura puo partire dal bordo vero
     — questa deve regolare il PADDING: lasciata come top si sommava, e il
     titolo scendeva di 32px finendo di nuovo sulla testa. */
  .pc-details { padding-top: 1.8em; }

  /* Via la miniatura tonda dalla barra. Su un telefono la barra ha 180px
     scarsi per tre cose, e questa ne prende 33 per mostrare — in piccolo e
     ritagliata — la stessa persona che sta li' sopra a tutta card. Toglierla
     e' quel che fa stare "@lucacurseri" e "Contattami" per intero, senza
     puntini e senza tagli. Su desktop resta: li' lo spazio c'e'. */
  .pc-mini-avatar { display: none; }
}
