/* ===== Strumenti: the skills marquee =====

   Base markup (index.html) is a plain wrapped row of pills — nothing here
   depends on JS to be readable. js/skills-marquee.js upgrades it where
   motion is allowed: the row goes from wrap to a single line, doubles for a
   seamless loop, and a fixed glass lens (js/glass-surface.js) sits over the
   middle of the strip so each name bends through real refraction as it
   passes under it, the way a magnifying glass would if the strip crawled
   past one instead. */

/* Base padding/z-index comes from the shared rule in css/style.css
   (.features, .projects, .stats, .about, .skills) — one number, one place. */

.skills-marquee {
  position: relative;
  width: 100%;
  max-width: 900px;
  margin-inline: auto;
  /* .scene-inner is a flex column and stretches this to its own width by
     default, exactly like every other block that lives inside it — but a
     flex item's auto min-width floors it at its CONTENT's size unless told
     otherwise, and this one's content is deliberately wider than the box:
     .skills-track holds two copies of the list side by side for the loop,
     easily past 900px. Without this, that content-based floor won over the
     stretch and the marquee rendered at its own max-content width (clipped
     visually by overflow:hidden below, but still wider than .scene-inner,
     which is what pushed the PANEL into horizontal overflow on a narrower
     desktop). min-width: 0 is the standard release valve for exactly this —
     a flex/grid child whose internal content must never dictate the box's
     own size. */
  min-width: 0;
}

/* ===== Base: every logo, wrapped, all at once =====
   What ships with JS off, and — because js/skills-marquee.js checks the same
   media query and simply does nothing when it's set — what stays on screen
   under prefers-reduced-motion too. Neither is a stripped-down consolation
   version: it is the same information, just not moving.

   Bare marks, no chip behind them — a logo strip reads as a logo strip
   precisely because nothing else is competing with the marks for attention.
   The name underneath each one is what keeps a mark someone doesn't
   recognise from being wasted: React's atom needs no caption to a developer
   and gets one anyway, for the reader who isn't one. */
.skills-list {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: flex-start;
  gap: var(--skills-gap, 34px);
  list-style: none;
}

.skills-list li {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 9px;
  width: 64px;
}

.skill-icon {
  width: 42px;
  height: 42px;
  border-radius: 10px;
  flex-shrink: 0;
}

.skill-name {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-50);
  white-space: nowrap;
}

/* ===== Live: one line, doubled, crawling =====
   .skills-marquee--live is added by js/skills-marquee.js the moment it
   decides to upgrade the row, and everything below is scoped to it — so a
   reader with reduced motion, or a page JS never got to run on, never sees
   half-built track/lens markup with nothing driving it. */
.skills-marquee--live {
  overflow: hidden;
  /* The strip fades at both edges rather than cutting mid-word: a name is
     never seen to appear or vanish out of nothing, only to arrive already
     faint and leave the same way — which is what makes the loop point
     invisible even though it very much exists. */
  -webkit-mask-image: linear-gradient(90deg,
    transparent 0, #000 48px, #000 calc(100% - 48px), transparent 100%);
          mask-image: linear-gradient(90deg,
    transparent 0, #000 48px, #000 calc(100% - 48px), transparent 100%);
}

.skills-marquee--live .skills-list {
  flex-wrap: nowrap;
}

.skills-track {
  display: flex;
  width: max-content;
  gap: var(--skills-gap, 34px);
  /* --skills-shift and --skills-duration are measured off the track's own
     rendered width by js/skills-marquee.js — never guessed — so the loop is
     pixel-exact regardless of how many tools are listed or how their names
     set, and the crawl speed (px/second) stays the same reading pace whether
     the list is 5 names long or 15. */
  animation: skills-scroll var(--skills-duration, 24s) linear infinite;
}
/* Hovering the strip is a request to stop it, not to speed anything up —
   the reader gets to look at whatever is currently under the lens for as
   long as they like. Touch has no hover, so a phone just keeps crawling;
   see js/skills-marquee.js for why that is the right default there too. */
.skills-marquee--live:hover .skills-track,
.skills-marquee--live:focus-within .skills-track { animation-play-state: paused; }

@keyframes skills-scroll {
  to { transform: translateX(calc(-1 * var(--skills-shift, 50%))); }
}

/* ===== The lens =====
   Fixed over the middle of the strip, never moving — the logos travel, the
   glass does not. Sized to frame roughly one logo column (icon + its
   caption) at a time, so what bends under it at any instant reads as "the
   mark currently under the glass" rather than as a window onto some other
   scale entirely. Height comes straight from the column it frames — the
   icon, the gap above the caption, and the caption's own line — so a wider
   icon or a longer caption anywhere never has to be matched by hand here. */
.skills-lens {
  position: absolute;
  top: 50%;
  left: 50%;
  translate: -50% -50%;
  z-index: 2;
  /* One continuous formula rather than a breakpoint jump: at 30vw this
     already lands at its 108px floor by ~360px of width and its 170px
     ceiling by ~570px, which covers a phone through a wide desktop without
     needing a second rule to patch either end. */
  width: clamp(108px, 30vw, 170px);
  height: calc(42px + 9px + 15px + 16px);
  border-radius: 16px;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .skills-marquee--live .skills-track { animation: none; }
}
