/* Components. Built only from tokens; motion states are toggled by js/motion.js. */

/* ---------- Buttons & links ---------- */
.btn {
  display: inline-flex; align-items: center; gap: var(--s-3);
  min-height: 48px; padding: 0 var(--s-5); border-radius: var(--r-pill);
  background: var(--c-primary); color: var(--c-on-primary); border: 1px solid var(--c-primary);
  font-size: var(--t-small); font-weight: var(--w-medium); cursor: pointer;
  transition: background var(--d-base) var(--ease-out), border-color var(--d-base) var(--ease-out), color var(--d-base) var(--ease-out);
}
.btn:hover { background: var(--c-primary-hover); border-color: var(--c-primary-hover); }
.btn--secondary { background: var(--c-secondary); color: var(--c-on-secondary); border-color: var(--c-secondary); }
.btn--secondary:hover { background: var(--c-secondary-hover); border-color: var(--c-secondary-hover); }
.btn--ghost { background: transparent; color: var(--c-primary); border-color: var(--c-line); }
.btn--ghost:hover { background: transparent; border-color: var(--c-primary); }
.btn .arrow { transition: transform var(--d-base) var(--ease-out); }
.btn:hover .arrow { transform: translateX(4px); }

/* Underlined link — the line draws in from the left on hover */
.link {
  background: linear-gradient(currentColor, currentColor) 0 100% / 100% 1px no-repeat;
  transition: background-size var(--d-base) var(--ease-out);
}
.link:hover { background-size: 0% 1px; background-position: 100% 100%; }

/* Letter-spacing widen — only for a few chosen links (Maria Vasilyeva reference) */
.widen {
  display: inline-block;
  transition: letter-spacing var(--d-hover-widen) var(--ease-out), margin-right var(--d-hover-widen) var(--ease-out);
}
.widen:hover, .widen:focus-visible { letter-spacing: 0.16em; margin-right: -0.16em; }

/* Rolling text — two stacked copies; markup: <span class="roll" data-text="Work"><span>Work</span></span> */
.roll { display: inline-block; position: relative; overflow: hidden; vertical-align: top; }
.roll > span { display: inline-block; transition: transform var(--d-slow) var(--ease-out); }
.roll::after {
  content: attr(data-text); position: absolute; left: 0; top: 100%;
  transition: transform var(--d-slow) var(--ease-out);
}
a:hover .roll > span, a:focus-visible .roll > span, .roll:hover > span { transform: translateY(-100%); }
a:hover .roll::after, a:focus-visible .roll::after, .roll:hover::after { transform: translateY(-100%); }

/* ---------- Pills (skills) ---------- */
.pills { display: flex; flex-wrap: wrap; gap: var(--s-2); padding: 0; margin: 0; list-style: none; }
.pill {
  display: inline-flex; align-items: center; min-height: 30px; padding: 0 var(--s-3);
  border: var(--hairline); border-radius: var(--r-pill);
  font-size: 0.8125rem; color: var(--c-ink-2); background: var(--c-surface); white-space: nowrap;
}

/* ---------- Meta rows (year · client · industry) ---------- */
.meta { display: grid; border-top: var(--hairline); }
.meta__row {
  display: grid; grid-template-columns: minmax(7rem, 1fr) 2fr; gap: var(--gutter);
  padding: var(--s-3) 0; border-bottom: var(--hairline); align-items: baseline;
}
.meta__row dt { font-family: var(--font-mono); font-size: var(--t-label); letter-spacing: var(--tr-label); text-transform: uppercase; color: var(--c-ink-3); }
.meta__row dd { font-size: var(--t-small); }

/* ---------- Project card (home / lists) ----------
   Media keeps its own aspect ratio — never cropped, because most images carry UI text or headlines.
   Only a pure photo with nothing readable near the edges may opt in to cropping with .is-crop + an aspect-ratio. */
.card { display: block; position: relative; }
.card__media { position: relative; border-radius: var(--r-media); overflow: hidden; background: var(--c-sunk); padding: 3px; }
.card__media img, .card__media video { width: 100%; height: auto; border-radius: var(--r-media); }
.card__media.is-crop img, .card__media.is-crop video { height: 100%; object-fit: cover; }
.card__caption { display: flex; justify-content: space-between; gap: var(--s-4); padding-top: var(--s-3); }
.card__title { font-size: var(--t-small); font-weight: var(--w-medium); }
.card__tag { color: var(--c-ink-3); font-size: var(--t-small); }

/* Running line on hover (Dopamine Studio reference): a short segment travels around the edge */
@property --angle { syntax: "<angle>"; inherits: false; initial-value: 0deg; }
@keyframes orbit { to { --angle: 360deg; } }
.card__media::before {
  content: ""; position: absolute; inset: 0; border-radius: inherit; padding: 1.5px; z-index: 1; pointer-events: none;
  background: conic-gradient(from var(--angle), transparent 0 62%, var(--c-primary) 74% 86%, transparent 94%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  opacity: 0; transition: opacity var(--d-base) var(--ease-out);
  animation: orbit 2.8s linear infinite paused;
}
@media (hover: hover) and (pointer: fine) {
  .card:hover .card__media::before, .card:focus-visible .card__media::before { opacity: 1; animation-play-state: running; }
}
@media (prefers-reduced-motion: reduce) {
  .card__media::before { animation: none; background: var(--c-primary); }
}

/* ---------- Stats (case-study results) ---------- */
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); border-top: var(--hairline); }
.stat { padding: var(--s-5) var(--s-5) var(--s-6) 0; border-bottom: var(--hairline); display: grid; gap: var(--s-6); }
.stat__value { font-size: var(--t-h1); line-height: 1; letter-spacing: var(--tr-tight); font-weight: var(--w-regular); }
.stat__label { color: var(--c-ink-2); font-size: var(--t-small); max-width: 26ch; }

/* ---------- Highlight band (key results on the project colour) ---------- */
.band { background: var(--p-bg); color: var(--p-fg); border-radius: var(--r-md); padding: var(--s-8) var(--margin); }
.band .t-label { color: color-mix(in srgb, var(--p-fg) 70%, transparent); }
.band .stats, .band .stat { border-color: color-mix(in srgb, var(--p-fg) 25%, transparent); }
.band .stat__label { color: color-mix(in srgb, var(--p-fg) 80%, transparent); }

/* ---------- Floating nav pill ---------- */
.navpill {
  position: fixed; left: 50%; bottom: var(--s-5); transform: translateX(-50%); z-index: 50;
  display: flex; align-items: center; gap: var(--s-1); padding: var(--s-1);
  background: color-mix(in srgb, var(--c-surface) 82%, transparent);
  backdrop-filter: blur(14px) saturate(1.2); -webkit-backdrop-filter: blur(14px) saturate(1.2);
  border: var(--hairline); border-radius: var(--r-pill); box-shadow: 0 6px 24px rgb(22 21 20 / 0.08);
}
.navpill a { padding: var(--s-2) var(--s-4); border-radius: var(--r-pill); font-size: var(--t-small); }
.navpill a[aria-current="page"] { background: var(--c-primary); color: var(--c-on-primary); }

/* ---------- Reveal states (js adds .is-in) ---------- */
.js .reveal { opacity: 0; transform: translateY(var(--reveal-shift)); }
.js .reveal.is-in {
  opacity: 1; transform: none;
  transition: opacity var(--d-reveal) var(--ease-out), transform var(--d-reveal) var(--ease-out);
  transition-delay: calc(var(--i, 0) * var(--stagger));
}

/* Headings: each line rises from behind a mask (js wraps lines) */
/* The mask gets extra room above/below (accents, descenders) and to the right (italic overhang), cancelled by
   negative margins so the layout doesn't move — otherwise tall or slanted glyphs get clipped. */
.lines .line {
  display: inline-block; vertical-align: top; overflow: hidden;
  padding: 0.14em 0.08em 0.2em 0; margin: -0.14em -0.08em -0.2em 0;
}
.lines .line > span { display: inline-block; }
.js .lines .line > span { transform: translateY(105%); }
.js .lines.is-in .line > span {
  transform: none; transition: transform var(--d-reveal) var(--ease-out);
  transition-delay: calc(var(--i, 0) * var(--stagger));
}

/* Key statement: words go faint → solid as they pass the reading line (js sets --p per word) */
.statement .w { opacity: calc(var(--word-dim) + (1 - var(--word-dim)) * var(--p, 0)); transition: opacity 120ms linear; }
.no-js .statement .w { opacity: 1; }
.statement u { text-decoration-thickness: 1px; text-underline-offset: 0.14em; }

/* Image wipe: opens bottom → top while the photo settles from a slight zoom.
   A page-coloured curtain shrinks upwards (the element itself is never clipped, so it can be observed). */
.wipe { position: relative; overflow: hidden; border-radius: var(--r-media); background: var(--c-sunk); }
.wipe img, .wipe video { width: 100%; height: auto; }   /* natural ratio — never cropped */
.js .wipe::after {
  content: ""; position: absolute; inset: -1px; background: var(--wipe-cover, var(--c-page));
  transform-origin: 50% 0; pointer-events: none;
}
.js .wipe img, .js .wipe video { transform: scale(1.12); }
.js .wipe.is-in::after { transform: scaleY(0); transition: transform 1.3s var(--ease-in-out); }
.js .wipe.is-in img, .js .wipe.is-in video { transform: scale(1); transition: transform 2s var(--ease-out); }

@media (prefers-reduced-motion: reduce) {
  .js .reveal, .js .lines .line > span, .js .wipe img, .js .wipe video { opacity: 1; transform: none; }
  .js .wipe::after { display: none; }
}
