/* ---- Design tokens ------------------------------------------------------
   Change these to re-theme the whole page (colors, radius, fonts). */
:root {
  --radius: 1rem;
  --background: oklch(0.11 0.005 270);
  --foreground: oklch(0.96 0.005 270);
  --muted-foreground: oklch(0.68 0.008 270);
  --border: oklch(0.30 0.008 270 / 55%);

  --gradient-primary: linear-gradient(135deg, oklch(0.96 0.005 270), oklch(0.6 0.01 260));

  --font-display: "Space Grotesk", ui-sans-serif, system-ui, sans-serif;
  --font-sans: "Inter", ui-sans-serif, system-ui, sans-serif;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  min-height: 100vh;
  background: var(--background);
  color: var(--foreground);
  font-family: var(--font-sans);
}

/* ---- Larger custom cursor ------------------------------------------------
   The default OS arrow reads tiny against this UI, so swap in a bigger
   version (~44px vs the usual ~24-32px). Only meaningful on mice/trackpads —
   touch devices don't render a cursor at all, so this is harmless there. */
@media (hover: hover) and (pointer: fine) {
  html {
    cursor: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='44' height='44' viewBox='0 0 44 44'><path d='M6 4 L6 32 L13 25.5 L18 36 L24 33 L19 22.5 L29 22.5 Z' fill='white' stroke='black' stroke-width='1.6' stroke-linejoin='round' stroke-linecap='round'/></svg>")
      6 4,
      auto;
  }

  a,
  button,
  .social-link,
  .click-meh,
  .music-toggle {
    cursor: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='44' height='44' viewBox='0 0 44 44'><path d='M6 4 L6 32 L13 25.5 L18 36 L24 33 L19 22.5 L29 22.5 Z' fill='white' stroke='black' stroke-width='1.6' stroke-linejoin='round' stroke-linecap='round'/></svg>")
      6 4,
      pointer;
  }
}

h1,
h2,
h3 {
  font-family: var(--font-display);
  letter-spacing: -0.02em;
  margin: 0;
}

/* ---- Page / background --------------------------------------------- */
.page {
  position: relative;
  z-index: 0; /* establishes a stacking context so the layers below stack predictably */
  min-height: 100vh;
  overflow: hidden;
}

.bg-image {
  position: absolute;
  inset: 0;
  z-index: 1;
  transform: scale(1.1);
  background-image: var(--bg-image-url);
  background-size: cover;
  background-position: center;
  /* Defaults match the original fixed look; script.js overrides these per
     profile (backgroundBrightness / backgroundBlur / backgroundGrayscale). */
  filter: grayscale(var(--bg-grayscale, 100%)) blur(var(--bg-blur, 18px)) brightness(var(--bg-brightness, 0.85))
    contrast(1.05);
}

.bg-vignette {
  position: absolute;
  inset: 0;
  z-index: 2;
  /* Defaults match the original fixed look; script.js overrides these per
     profile (vignetteStrength). */
  background: radial-gradient(ellipse at center, oklch(0 0 0 / var(--vignette-inner, 30%)), oklch(0 0 0 / var(--vignette-outer, 75%)) 90%);
}

/* ---- Background particles (canvas-based: snow / confetti / network) ---- */
.particles-canvas {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  display: block;
}

/* ---- "Click Meh :p" gate -------------------------------------------------
   Sits above the background/snow (which stay visible through it) and
   below nothing else. Clicking it starts the music + reveals the card,
   then fades itself out. */
.click-meh {
  position: fixed;
  inset: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 0;
  margin: 0;
  padding: 1.5rem;
  background: transparent;
  appearance: none;
  -webkit-tap-highlight-color: transparent;
  transition: opacity 0.6s ease;
}

.click-meh-text {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.5rem, 6vw, 2.5rem);
  color: var(--foreground);
  letter-spacing: 0.02em;
  text-shadow: 0 0 30px oklch(1 0 0 / 25%);
  animation: click-meh-flash 2.6s ease-in-out infinite;
}

@keyframes click-meh-flash {
  0%,
  100% {
    opacity: 0.35;
    transform: scale(0.97);
  }
  50% {
    opacity: 1;
    transform: scale(1.04);
  }
}

.click-meh.hidden {
  opacity: 0;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .click-meh-text {
    animation: none;
    opacity: 0.85;
  }
}

/* ---- Layout ------------------------------------------------------------ */
.wrap {
  position: relative;
  z-index: 4;
  margin: 0 auto;
  display: flex;
  min-height: 100vh;
  max-width: 42rem;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 2.5rem 1.25rem;
}

.card {
  position: relative;
  width: 100%;
  overflow: hidden;
  border-radius: 1.5rem;
  padding: 2rem;
  box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
  background: linear-gradient(180deg, oklch(1 0 0 / 5%), oklch(1 0 0 / 2%));
  backdrop-filter: blur(18px);
  border: 1px solid oklch(1 0 0 / 10%);

  /* Hidden until the "Click Meh :p" gate is clicked (see .card.revealed
     and .card.intro below, and --intro-ms which is set from the profile's
     introFadeMs). */
  opacity: 0;
  transform: translateY(26px) scale(0.965);
  filter: blur(8px);
}

/* Static end-state, applied the moment the gate is clicked. .card.intro
   (added at the same time, removed once the animation finishes — see
   script.js) plays the actual rise keyframes on top of this; once intro
   is removed these static values keep the card looking exactly the same
   with no jump, which is what lets .levitating (added right after) start
   cleanly from the same transform instead of snapping back to hidden. */
.card.revealed {
  opacity: 1;
  transform: translateY(0) scale(1);
  filter: blur(0);
}

.card.intro {
  animation: rise var(--intro-ms, 4.5s) cubic-bezier(0.22, 1, 0.36, 1) both;
}

@keyframes rise {
  0% {
    opacity: 0;
    transform: translateY(26px) scale(0.965);
    filter: blur(8px);
  }
  55% {
    opacity: 0.85;
    filter: blur(1px);
  }
  100% {
    opacity: 1;
    transform: translateY(0) scale(1);
    filter: blur(0);
  }
}

/* Gentle up/down levitation once the card has finished revealing.
   Desktop/pointer devices only — see the mobile section below, which
   turns this off on small/touch screens. */
.card.levitating {
  animation: levitate 6s ease-in-out infinite;
}

@keyframes levitate {
  0%,
  100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-10px);
  }
}

/* ---- Profile header ---------------------------------------------------- */
.profile-top {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.avatar-ring {
  position: relative;
}

.avatar-ring::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 9999px;
  animation: pulse-ring 2.6s ease-out infinite;
}

@keyframes pulse-ring {
  0% {
    box-shadow: 0 0 0 0 oklch(1 0 0 / 30%);
  }
  70% {
    box-shadow: 0 0 0 20px oklch(1 0 0 / 0%);
  }
  100% {
    box-shadow: 0 0 0 0 oklch(1 0 0 / 0%);
  }
}

.avatar {
  position: relative;
  height: 8rem;
  width: 8rem;
  border-radius: 9999px;
  border: 4px solid var(--background);
  object-fit: cover;
  box-shadow: 0 0 30px oklch(0.85 0.01 270 / 25%);
}

.status-dot {
  position: absolute;
  bottom: 0.375rem;
  right: 0.375rem;
  height: 1.25rem;
  width: 1.25rem;
  border-radius: 9999px;
  border: 4px solid var(--background);
  background: var(--accent-color, oklch(0.78 0.14 145));
}

.name {
  margin-top: 1.25rem;
  font-size: 2.25rem;
  font-weight: 700;
  background: var(--gradient-primary);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.handle {
  margin: 0.25rem 0 0;
  font-size: 0.875rem;
  color: var(--muted-foreground);
}

.bio {
  margin: 1rem 0 0;
  max-width: 28rem;
  min-height: 1.4em;
  font-size: 0.875rem;
  line-height: 1.6;
  color: oklch(0.96 0.005 270 / 85%);
}

/* Blinking "|" cursor for the typewriter effect in .bio */
.typewriter-cursor {
  display: inline-block;
  margin-left: 1px;
  animation: cursor-blink 1s step-start infinite;
}

@keyframes cursor-blink {
  0%,
  50% {
    opacity: 1;
  }
  50.01%,
  100% {
    opacity: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .typewriter-cursor {
    animation: none;
  }
}

.badges {
  margin-top: 1rem;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem;
}

.badge {
  border-radius: 9999px;
  border: 1px solid oklch(1 0 0 / 10%);
  background: oklch(1 0 0 / 5%);
  padding: 0.25rem 0.75rem;
  font-size: 0.6875rem;
  font-weight: 500;
  color: oklch(0.96 0.005 270 / 80%);
}

/* ---- Social links -------------------------------------------------- */
.socials {
  list-style: none;
  margin: 2rem 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.625rem;
}

@media (min-width: 640px) {
  .socials {
    grid-template-columns: 1fr 1fr;
  }
}

.social-link {
  display: flex;
  align-items: center;
  gap: 1rem;
  border-radius: 1rem;
  border: 1px solid oklch(1 0 0 / 10%);
  background: oklch(1 0 0 / 3%);
  padding: 0.75rem 1rem;
  text-decoration: none;
  color: inherit;
  transition: transform 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}

@media (hover: hover) and (pointer: fine) {
  .social-link:hover {
    transform: translateY(-2px);
    border-color: oklch(1 0 0 / 25%);
    background: oklch(1 0 0 / 7%);
  }

  .social-link:hover .social-icon {
    transform: scale(1.1);
  }

  .social-link:hover .social-arrow {
    transform: translate(2px, -2px);
    color: var(--foreground);
  }
}

.social-icon {
  display: flex;
  height: 2.5rem;
  width: 2.5rem;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  border-radius: 0.75rem;
  transition: transform 0.15s ease;
}

.social-text {
  display: flex;
  flex: 1;
  flex-direction: column;
  text-align: left;
  min-width: 0;
}

.social-name {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--foreground);
}

.social-handle {
  font-size: 0.75rem;
  color: var(--muted-foreground);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.social-arrow {
  color: var(--muted-foreground);
  flex-shrink: 0;
  transition: transform 0.15s ease, color 0.15s ease;
}

/* ---- Footer ------------------------------------------------------------ */
.footer {
  margin-top: 1.5rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-top: 1px solid oklch(1 0 0 / 10%);
  padding-top: 1rem;
  font-size: 0.75rem;
  color: var(--muted-foreground);
}

/* ---- Music widget (floating disc player) --------------------------------
   Hidden until the "Click Meh :p" gate reveals the card (script.js adds
   .revealed to both at the same time). Drag the disc to scrub the track —
   releasing it with enough spin gives a short, gentle coast back to normal
   playback rather than a slingshot (see the physics constants in script.js).
*/
.music-widget {
  position: fixed;
  z-index: 6;
  right: 1rem;
  bottom: 1rem;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: 280px;
  padding: 0.75rem;
  border-radius: 1.25rem;
  background: linear-gradient(180deg, oklch(1 0 0 / 5%), oklch(1 0 0 / 2%));
  backdrop-filter: blur(18px);
  border: 1px solid oklch(1 0 0 / 10%);
  box-shadow: 0 20px 45px rgba(0, 0, 0, 0.45);

  /* Hidden until the "Click Meh :p" gate is clicked — tweens in with the
     exact same "rise" keyframes (and --intro-ms timing) as the card, see
     .music-widget.intro / .music-widget.revealed below and script.js. */
  opacity: 0;
  transform: translateY(26px) scale(0.965);
  filter: blur(8px);
}

/* Static end-state, same pattern as .card.revealed: .intro plays the actual
   rise keyframes, and once it finishes (removed in script.js) this holds
   the same end values so nothing jumps. */
.music-widget.revealed {
  opacity: 1;
  transform: translateY(0) scale(1);
  filter: blur(0);
}

.music-widget.intro {
  animation: rise var(--intro-ms, 4.5s) cubic-bezier(0.22, 1, 0.36, 1) both;
}

.disc {
  position: relative;
  flex-shrink: 0;
  height: 4rem;
  width: 4rem;
  border-radius: 50%;
  cursor: grab;
  touch-action: none;
  background: repeating-radial-gradient(circle at center, oklch(0.14 0.005 270) 0 2px, oklch(0.19 0.006 270) 2px 4px);
  box-shadow: 0 6px 20px oklch(0 0 0 / 55%), inset 0 0 0 1px oklch(1 0 0 / 8%);
}

.disc:active {
  cursor: grabbing;
}

.disc-sheen,
.disc-hub,
.disc-pin,
.disc-tick {
  position: absolute;
  pointer-events: none;
}

.disc-sheen {
  inset: 0;
  border-radius: 50%;
  background: conic-gradient(from 0deg, oklch(1 0 0 / 0%), oklch(1 0 0 / 12%), oklch(1 0 0 / 0%) 40%, oklch(1 0 0 / 8%) 70%, oklch(1 0 0 / 0%));
  mix-blend-mode: screen;
}

.disc-hub {
  left: 50%;
  top: 50%;
  height: 1.75rem;
  width: 1.75rem;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, oklch(0.55 0.008 260), oklch(0.22 0.006 270));
  box-shadow: inset 0 0 0 1px oklch(1 0 0 / 15%);
}

.disc-pin {
  left: 50%;
  top: 50%;
  height: 0.375rem;
  width: 0.375rem;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: var(--background);
}

.disc-tick {
  left: 50%;
  top: 0.25rem;
  height: 0.5rem;
  width: 2px;
  transform: translateX(-50%);
  border-radius: 2px;
  background: oklch(1 0 0 / 55%);
}

.music-body {
  display: flex;
  min-width: 0;
  flex: 1;
  flex-direction: column;
}

.music-live {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.625rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted-foreground);
}

.music-dot {
  height: 0.375rem;
  width: 0.375rem;
  border-radius: 50%;
  background: var(--accent-color, oklch(0.78 0.14 145));
}

.music-title {
  margin-top: 0.125rem;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--foreground);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.music-artist {
  font-size: 0.75rem;
  color: var(--muted-foreground);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.music-track {
  margin-top: 0.5rem;
  height: 0.25rem;
  width: 100%;
  border-radius: 9999px;
  overflow: hidden;
  background: oklch(1 0 0 / 10%);
}

.music-fill {
  height: 100%;
  width: 0%;
  border-radius: 9999px;
  background: var(--gradient-primary);
}

.music-times {
  margin-top: 0.25rem;
  display: flex;
  justify-content: space-between;
  font-size: 0.625rem;
  color: var(--muted-foreground);
  font-variant-numeric: tabular-nums;
}

.music-toggle {
  display: flex;
  height: 2.25rem;
  width: 2.25rem;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  border: 1px solid oklch(1 0 0 / 10%);
  background: oklch(1 0 0 / 5%);
  color: oklch(0.96 0.005 270 / 85%);
  transition: border-color 0.15s ease, background 0.15s ease;
}

@media (hover: hover) and (pointer: fine) {
  .music-toggle:hover {
    border-color: oklch(1 0 0 / 25%);
    background: oklch(1 0 0 / 10%);
  }
}

@media (max-width: 480px) {
  /* .wrap normally reserves a full 100vh (to vertically center the lone
     .card in it), which pushed the widget below a whole extra screen's
     worth of empty space once it left the fixed corner — effectively
     invisible without scrolling. Letting .page do the vertical centering
     instead (as a flex column over both .wrap and the widget) and giving
     .wrap its natural height means the card + widget center as one group,
     with the widget landing directly under the card. */
  .page {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    overflow: visible;
  }

  .wrap {
    min-height: 0;
  }

  .music-widget {
    /* Off the fixed corner, into normal document flow — it already sits
       right after the card in index.html, so this just lets it land there
       visually too, centered, instead of overlapping content off to the
       side on a small screen. */
    position: static;
    width: min(280px, calc(100vw - 2rem));
    margin: 1rem auto 1.5rem;
  }
}

/* ---- Mobile -------------------------------------------------------------
   Slightly tighter spacing/type sizes so the card doesn't overwhelm small
   screens, and the levitation float is turned off (see script.js, which
   also skips adding the .levitating class on these screens — this query
   is just a backstop). */
@media (max-width: 480px) {
  .wrap {
    padding: 1.5rem 0.85rem;
  }

  .card {
    padding: 1.5rem 1.25rem;
    border-radius: 1.25rem;
  }

  .card.levitating {
    animation: none;
  }

  .avatar {
    height: 6rem;
    width: 6rem;
  }

  .name {
    font-size: 1.65rem;
    margin-top: 1rem;
  }

  .bio {
    font-size: 0.8125rem;
  }

  .socials {
    margin-top: 1.5rem;
  }

  .social-link {
    padding: 0.625rem 0.875rem;
  }

  .footer {
    flex-wrap: wrap;
    gap: 0.5rem;
  }
}

@media (pointer: coarse) {
  .card.levitating {
    animation: none;
  }
}
