/* ============================================================
   Will Sledge — Portfolio
   ============================================================ */

:root {
  --bg: #0a0a0a;
  --bg-elevated: #161616;
  --bg-card: #1c1c1c;
  --fg: #f5f5f5;
  --fg-muted: #a3a3a3;
  --fg-faint: #6b6b6b;
  --accent: #ffffff;
  --accent-2: #9a9a9a;
  --line: rgba(245, 245, 245, 0.10);
  --line-strong: rgba(245, 245, 245, 0.22);
  --font-display: "Space Grotesk", "Helvetica Neue", Arial, sans-serif;
  --font-body: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --maxw: 1240px;
  --pad: clamp(1.25rem, 4vw, 3rem);
}

* { box-sizing: border-box; }
html { scroll-behavior: auto; } /* Lenis drives smooth scrolling in JS */

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }

section { scroll-margin-top: 90px; }

/* ---------- texture layers ---------- */
.grain {
  position: fixed; inset: 0; pointer-events: none; z-index: 200;
  opacity: 0.05; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='120'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  background-size: 160px 160px;
}

/* ---------- preloader ----------
   A short branded loading moment before the page reveals. The
   6s "failsafe" animation is a pure-CSS backstop: if JS ever fails
   to clear this element, it still won't leave the page permanently
   blocked behind it. */
.preloader {
  position: fixed; inset: 0; z-index: 500;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 1.4rem; background: var(--bg);
  animation: preloader-failsafe 0s 6s forwards;
}
.preloader-mark img { width: clamp(84px, 11vw, 120px); height: auto; display: block; }
.preloader-bar {
  width: clamp(140px, 20vw, 200px); height: 1px; background: var(--line);
  overflow: hidden; position: relative;
}
.preloader-bar-fill {
  position: absolute; inset: 0; width: 0%; background: var(--fg);
}
@keyframes preloader-failsafe {
  to { opacity: 0; visibility: hidden; pointer-events: none; }
}
@media (prefers-reduced-motion: reduce) {
  .preloader { display: none; }
}

.cursor-glow {
  position: fixed; top: 0; left: 0; width: 480px; height: 480px;
  border-radius: 50%; pointer-events: none; z-index: 1;
  background: radial-gradient(circle, rgba(255,255,255,0.09) 0%, rgba(255,255,255,0) 70%);
  transform: translate(-50%, -50%);
  transition: opacity 0.3s ease;
  opacity: 0;
}

/* ---------- header ---------- */
.site-header {
  position: fixed; top: 0; left: 0; right: 0; z-index: 100;
  display: flex; align-items: center; justify-content: space-between;
  padding: 1.1rem var(--pad);
  background: linear-gradient(to bottom, rgba(11,10,13,0.9), rgba(11,10,13,0));
  backdrop-filter: blur(6px);
}

.brand { display: block; }
.brand img { height: 30px; width: auto; display: block; }

.main-nav { display: flex; align-items: center; gap: 2rem; }
.main-nav a {
  font-size: 0.92rem; color: var(--fg-muted);
  transition: color 0.2s ease;
  position: relative;
}
.main-nav a:hover { color: var(--fg); }
.main-nav a.nav-cta {
  color: var(--bg); background: var(--fg);
  padding: 0.5rem 1.1rem; border-radius: 999px;
  font-weight: 500;
}
.main-nav a.nav-cta:hover { background: var(--fg-muted); color: var(--bg); }

.nav-toggle {
  display: none; flex-direction: column; gap: 5px;
  background: none; border: none; cursor: pointer; padding: 0.5rem;
}
.nav-toggle span { width: 22px; height: 2px; background: var(--fg); display: block; }

/* ---------- ambient audio widget ----------
   Nested at the right end of the nav (after Contact), same flex row —
   no change to .site-header's own layout needed. A small dot is the
   permanent, always-reachable control (so a first-time visitor can
   actually find and start it); the fuller 4-bar EQ only appears once
   BOTH a track is playing AND the cursor is near the widget (see the
   "Ambient audio" block in main.js) — invisible the rest of the time,
   same restraint as everywhere else on the site. The EQ bars are
   driven by a real Web Audio AnalyserNode reading the actual playing
   track, not a canned animation loop. */
.audio-widget { display: flex; align-items: center; }
.audio-btn {
  position: relative; width: 32px; height: 32px; border-radius: 50%;
  border: 1px solid var(--line-strong); background: none; cursor: pointer; padding: 0;
  display: flex; align-items: center; justify-content: center;
  color: var(--fg-muted);
  transition: border-color 0.25s ease, color 0.25s ease;
}
.audio-btn:hover { border-color: var(--fg); color: var(--fg); }
.audio-dot {
  width: 6px; height: 6px; border-radius: 50%; background: currentColor;
  transition: opacity 0.25s ease;
}
.audio-eq {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center; gap: 3px;
  opacity: 0; transition: opacity 0.3s ease;
  pointer-events: none;
}
.audio-widget.is-playing.is-near .audio-eq { opacity: 1; }
.audio-widget.is-playing.is-near .audio-dot { opacity: 0; }
.audio-eq span {
  display: block; width: 2.5px; height: 13px; background: var(--fg);
  border-radius: 1px;
  transform: scaleY(0.15); transform-origin: bottom;
  transition: transform 0.09s ease;
}

/* ---------- buttons ---------- */
.btn {
  display: inline-block; padding: 0.85rem 1.7rem; border-radius: 999px;
  font-size: 0.95rem; font-weight: 500; transition: all 0.25s ease;
  border: 1px solid transparent;
}
.btn-primary { background: var(--accent); color: #0a0a0a; }
.btn-primary:hover { background: #d4d4d4; transform: translateY(-2px); }
.btn-ghost { border-color: var(--line-strong); color: var(--fg); }
.btn-ghost:hover { border-color: var(--accent); color: var(--accent); transform: translateY(-2px); }

/* ---------- hero ---------- */
.hero {
  position: relative; min-height: 100svh;
  display: flex; flex-direction: column; justify-content: center;
  padding: 7rem var(--pad) 4rem;
  overflow: hidden;
}

/* Deep-space backdrop — replaces the old photo + line-grid + color blobs
   entirely. Three stacked, independently-drifting layers of tiny inline-SVG
   dot fields (dense/dim distant dust, an ordinary mid-field, and a sparse
   layer of brighter, softly-glowing foreground stars) give every visitor a
   real starfield with zero JS or image requests. This is the permanent
   base — .hero-canvas (the WebGL wormhole tunnel, below) composites on top
   of it for capable devices rather than replacing it, so nobody ever sees
   a bare background either way. Reduced-motion visitors get the same
   field held still (see the prefers-reduced-motion block near the bottom
   of this file). */
.hero-starfield { position: absolute; inset: 0; z-index: -1; background: var(--bg); overflow: hidden; }
.hero-starfield::after {
  /* Same soft vignette the old photo backdrop used, so the hero's edges
     stay dark and the readable copy over it keeps its contrast. */
  content: "";
  position: absolute; inset: -10%;
  background: radial-gradient(ellipse 70% 60% at 50% 40%, rgba(10,10,10,0) 0%, rgba(10,10,10,0.55) 78%, rgba(10,10,10,0.85) 100%);
  z-index: 3;
}
.star-layer {
  position: absolute; inset: -10%;
  background-repeat: repeat;
}
.star-layer--dust {
  background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%22520%22%20height%3D%22520%22%3E%3Ccircle%20cx%3D%2269.9%22%20cy%3D%22440.7%22%20r%3D%220.77%22%20fill%3D%22%23fff%22%20opacity%3D%220.18%22/%3E%20%3Ccircle%20cx%3D%22257.6%22%20cy%3D%22233.7%22%20r%3D%220.71%22%20fill%3D%22%23fff%22%20opacity%3D%220.34%22/%3E%20%3Ccircle%20cx%3D%2248.8%22%20cy%3D%2214.7%22%20r%3D%220.81%22%20fill%3D%22%23fff%22%20opacity%3D%220.23%22/%3E%20%3Ccircle%20cx%3D%22396.4%22%20cy%3D%221.1%22%20r%3D%220.59%22%20fill%3D%22%23fff%22%20opacity%3D%220.32%22/%3E%20%3Ccircle%20cx%3D%22119.0%22%20cy%3D%22491.5%22%20r%3D%220.85%22%20fill%3D%22%23fff%22%20opacity%3D%220.11%22/%3E%20%3Ccircle%20cx%3D%2213.2%22%20cy%3D%22281.5%22%20r%3D%220.87%22%20fill%3D%22%23fff%22%20opacity%3D%220.21%22/%3E%20%3Ccircle%20cx%3D%22112.6%22%20cy%3D%22219.5%22%20r%3D%220.37%22%20fill%3D%22%23fff%22%20opacity%3D%220.17%22/%3E%20%3Ccircle%20cx%3D%22227.7%22%20cy%3D%22257.8%22%20r%3D%220.48%22%20fill%3D%22%23fff%22%20opacity%3D%220.17%22/%3E%20%3Ccircle%20cx%3D%22113.8%22%20cy%3D%22239.0%22%20r%3D%220.51%22%20fill%3D%22%23fff%22%20opacity%3D%220.11%22/%3E%20%3Ccircle%20cx%3D%22435.5%22%20cy%3D%22289.4%22%20r%3D%220.7%22%20fill%3D%22%23fff%22%20opacity%3D%220.16%22/%3E%20%3Ccircle%20cx%3D%22516.1%22%20cy%3D%22447.2%22%20r%3D%220.42%22%20fill%3D%22%23fff%22%20opacity%3D%220.2%22/%3E%20%3Ccircle%20cx%3D%22375.2%22%20cy%3D%22369.8%22%20r%3D%220.87%22%20fill%3D%22%23fff%22%20opacity%3D%220.23%22/%3E%20%3Ccircle%20cx%3D%22431.6%22%20cy%3D%22348.6%22%20r%3D%220.52%22%20fill%3D%22%23fff%22%20opacity%3D%220.28%22/%3E%20%3Ccircle%20cx%3D%22458.9%22%20cy%3D%22440.0%22%20r%3D%220.63%22%20fill%3D%22%23fff%22%20opacity%3D%220.28%22/%3E%20%3Ccircle%20cx%3D%2218.0%22%20cy%3D%22126.2%22%20r%3D%220.79%22%20fill%3D%22%23fff%22%20opacity%3D%220.22%22/%3E%20%3Ccircle%20cx%3D%2290.0%22%20cy%3D%22285.4%22%20r%3D%220.74%22%20fill%3D%22%23fff%22%20opacity%3D%220.3%22/%3E%20%3Ccircle%20cx%3D%22194.8%22%20cy%3D%22228.3%22%20r%3D%220.63%22%20fill%3D%22%23fff%22%20opacity%3D%220.33%22/%3E%20%3Ccircle%20cx%3D%22270.9%22%20cy%3D%22204.5%22%20r%3D%220.62%22%20fill%3D%22%23fff%22%20opacity%3D%220.11%22/%3E%20%3Ccircle%20cx%3D%2222.6%22%20cy%3D%22365.8%22%20r%3D%220.89%22%20fill%3D%22%23fff%22%20opacity%3D%220.28%22/%3E%20%3Ccircle%20cx%3D%22204.7%22%20cy%3D%2288.6%22%20r%3D%220.63%22%20fill%3D%22%23fff%22%20opacity%3D%220.39%22/%3E%20%3Ccircle%20cx%3D%22400.7%22%20cy%3D%22280.6%22%20r%3D%220.82%22%20fill%3D%22%23fff%22%20opacity%3D%220.17%22/%3E%20%3Ccircle%20cx%3D%22267.2%22%20cy%3D%22495.3%22%20r%3D%220.67%22%20fill%3D%22%23fff%22%20opacity%3D%220.24%22/%3E%20%3Ccircle%20cx%3D%22140.0%22%20cy%3D%22285.0%22%20r%3D%220.88%22%20fill%3D%22%23fff%22%20opacity%3D%220.1%22/%3E%20%3Ccircle%20cx%3D%22407.5%22%20cy%3D%22426.7%22%20r%3D%220.84%22%20fill%3D%22%23fff%22%20opacity%3D%220.32%22/%3E%20%3Ccircle%20cx%3D%22420.8%22%20cy%3D%22269.7%22%20r%3D%220.66%22%20fill%3D%22%23fff%22%20opacity%3D%220.23%22/%3E%20%3Ccircle%20cx%3D%2229.2%22%20cy%3D%22452.4%22%20r%3D%220.66%22%20fill%3D%22%23fff%22%20opacity%3D%220.16%22/%3E%20%3Ccircle%20cx%3D%22262.5%22%20cy%3D%22252.2%22%20r%3D%220.55%22%20fill%3D%22%23fff%22%20opacity%3D%220.2%22/%3E%20%3Ccircle%20cx%3D%22280.0%22%20cy%3D%22324.2%22%20r%3D%220.69%22%20fill%3D%22%23fff%22%20opacity%3D%220.24%22/%3E%20%3Ccircle%20cx%3D%2214.5%22%20cy%3D%22119.4%22%20r%3D%220.45%22%20fill%3D%22%23fff%22%20opacity%3D%220.28%22/%3E%20%3Ccircle%20cx%3D%22447.7%22%20cy%3D%22415.2%22%20r%3D%220.79%22%20fill%3D%22%23fff%22%20opacity%3D%220.34%22/%3E%20%3Ccircle%20cx%3D%22132.8%22%20cy%3D%22437.7%22%20r%3D%220.72%22%20fill%3D%22%23fff%22%20opacity%3D%220.12%22/%3E%20%3Ccircle%20cx%3D%228.7%22%20cy%3D%227.6%22%20r%3D%220.77%22%20fill%3D%22%23fff%22%20opacity%3D%220.17%22/%3E%20%3Ccircle%20cx%3D%2256.9%22%20cy%3D%22324.9%22%20r%3D%220.54%22%20fill%3D%22%23fff%22%20opacity%3D%220.12%22/%3E%20%3Ccircle%20cx%3D%2283.0%22%20cy%3D%22274.2%22%20r%3D%220.44%22%20fill%3D%22%23fff%22%20opacity%3D%220.18%22/%3E%20%3Ccircle%20cx%3D%22370.0%22%20cy%3D%22236.4%22%20r%3D%220.53%22%20fill%3D%22%23fff%22%20opacity%3D%220.24%22/%3E%20%3Ccircle%20cx%3D%2212.3%22%20cy%3D%22201.0%22%20r%3D%220.58%22%20fill%3D%22%23fff%22%20opacity%3D%220.16%22/%3E%20%3Ccircle%20cx%3D%2256.6%22%20cy%3D%22467.9%22%20r%3D%220.63%22%20fill%3D%22%23fff%22%20opacity%3D%220.16%22/%3E%20%3Ccircle%20cx%3D%22314.9%22%20cy%3D%22424.9%22%20r%3D%220.36%22%20fill%3D%22%23fff%22%20opacity%3D%220.11%22/%3E%20%3Ccircle%20cx%3D%2276.2%22%20cy%3D%22373.8%22%20r%3D%220.44%22%20fill%3D%22%23fff%22%20opacity%3D%220.31%22/%3E%20%3Ccircle%20cx%3D%22352.7%22%20cy%3D%22283.2%22%20r%3D%220.47%22%20fill%3D%22%23fff%22%20opacity%3D%220.39%22/%3E%20%3Ccircle%20cx%3D%22414.9%22%20cy%3D%22268.6%22%20r%3D%220.47%22%20fill%3D%22%23fff%22%20opacity%3D%220.29%22/%3E%20%3Ccircle%20cx%3D%22205.3%22%20cy%3D%22299.4%22%20r%3D%220.53%22%20fill%3D%22%23fff%22%20opacity%3D%220.29%22/%3E%20%3Ccircle%20cx%3D%2230.6%22%20cy%3D%22155.3%22%20r%3D%220.88%22%20fill%3D%22%23fff%22%20opacity%3D%220.36%22/%3E%20%3Ccircle%20cx%3D%22159.3%22%20cy%3D%22446.4%22%20r%3D%220.52%22%20fill%3D%22%23fff%22%20opacity%3D%220.38%22/%3E%20%3Ccircle%20cx%3D%22386.8%22%20cy%3D%22216.4%22%20r%3D%220.49%22%20fill%3D%22%23fff%22%20opacity%3D%220.1%22/%3E%20%3Ccircle%20cx%3D%22456.9%22%20cy%3D%2219.7%22%20r%3D%220.8%22%20fill%3D%22%23fff%22%20opacity%3D%220.39%22/%3E%20%3Ccircle%20cx%3D%22296.5%22%20cy%3D%2289.2%22%20r%3D%220.83%22%20fill%3D%22%23fff%22%20opacity%3D%220.39%22/%3E%20%3Ccircle%20cx%3D%22366.1%22%20cy%3D%22264.6%22%20r%3D%220.56%22%20fill%3D%22%23fff%22%20opacity%3D%220.2%22/%3E%20%3Ccircle%20cx%3D%22107.0%22%20cy%3D%22350.6%22%20r%3D%220.59%22%20fill%3D%22%23fff%22%20opacity%3D%220.16%22/%3E%20%3Ccircle%20cx%3D%2254.3%22%20cy%3D%22346.3%22%20r%3D%220.51%22%20fill%3D%22%23fff%22%20opacity%3D%220.25%22/%3E%20%3Ccircle%20cx%3D%22169.2%22%20cy%3D%22453.2%22%20r%3D%220.84%22%20fill%3D%22%23fff%22%20opacity%3D%220.11%22/%3E%20%3Ccircle%20cx%3D%22104.4%22%20cy%3D%22170.4%22%20r%3D%220.89%22%20fill%3D%22%23fff%22%20opacity%3D%220.33%22/%3E%20%3Ccircle%20cx%3D%22176.3%22%20cy%3D%22110.8%22%20r%3D%220.72%22%20fill%3D%22%23fff%22%20opacity%3D%220.35%22/%3E%20%3Ccircle%20cx%3D%22484.7%22%20cy%3D%22178.8%22%20r%3D%220.84%22%20fill%3D%22%23fff%22%20opacity%3D%220.31%22/%3E%20%3Ccircle%20cx%3D%22251.9%22%20cy%3D%22512.5%22%20r%3D%220.48%22%20fill%3D%22%23fff%22%20opacity%3D%220.32%22/%3E%20%3Ccircle%20cx%3D%2244.0%22%20cy%3D%2288.2%22%20r%3D%220.85%22%20fill%3D%22%23fff%22%20opacity%3D%220.16%22/%3E%20%3Ccircle%20cx%3D%22394.7%22%20cy%3D%22312.1%22%20r%3D%220.81%22%20fill%3D%22%23fff%22%20opacity%3D%220.21%22/%3E%20%3Ccircle%20cx%3D%22176.9%22%20cy%3D%22151.4%22%20r%3D%220.83%22%20fill%3D%22%23fff%22%20opacity%3D%220.28%22/%3E%20%3Ccircle%20cx%3D%22496.2%22%20cy%3D%22461.4%22%20r%3D%220.42%22%20fill%3D%22%23fff%22%20opacity%3D%220.27%22/%3E%20%3Ccircle%20cx%3D%2254.2%22%20cy%3D%2220.4%22%20r%3D%220.39%22%20fill%3D%22%23fff%22%20opacity%3D%220.36%22/%3E%20%3Ccircle%20cx%3D%22409.8%22%20cy%3D%22430.8%22%20r%3D%220.54%22%20fill%3D%22%23fff%22%20opacity%3D%220.28%22/%3E%20%3Ccircle%20cx%3D%22406.6%22%20cy%3D%22196.6%22%20r%3D%220.66%22%20fill%3D%22%23fff%22%20opacity%3D%220.17%22/%3E%20%3Ccircle%20cx%3D%2242.5%22%20cy%3D%22138.7%22%20r%3D%220.84%22%20fill%3D%22%23fff%22%20opacity%3D%220.27%22/%3E%20%3Ccircle%20cx%3D%22481.0%22%20cy%3D%22238.0%22%20r%3D%220.5%22%20fill%3D%22%23fff%22%20opacity%3D%220.34%22/%3E%20%3Ccircle%20cx%3D%22430.4%22%20cy%3D%226.4%22%20r%3D%220.72%22%20fill%3D%22%23fff%22%20opacity%3D%220.13%22/%3E%20%3Ccircle%20cx%3D%2259.9%22%20cy%3D%22460.2%22%20r%3D%220.37%22%20fill%3D%22%23fff%22%20opacity%3D%220.17%22/%3E%20%3Ccircle%20cx%3D%22513.8%22%20cy%3D%22218.9%22%20r%3D%220.41%22%20fill%3D%22%23fff%22%20opacity%3D%220.15%22/%3E%20%3Ccircle%20cx%3D%22125.5%22%20cy%3D%22386.9%22%20r%3D%220.41%22%20fill%3D%22%23fff%22%20opacity%3D%220.37%22/%3E%20%3Ccircle%20cx%3D%22196.7%22%20cy%3D%22504.5%22%20r%3D%220.85%22%20fill%3D%22%23fff%22%20opacity%3D%220.19%22/%3E%20%3Ccircle%20cx%3D%22131.8%22%20cy%3D%22248.0%22%20r%3D%220.41%22%20fill%3D%22%23fff%22%20opacity%3D%220.3%22/%3E%20%3Ccircle%20cx%3D%2220.6%22%20cy%3D%225.5%22%20r%3D%220.89%22%20fill%3D%22%23fff%22%20opacity%3D%220.19%22/%3E%20%3Ccircle%20cx%3D%22310.2%22%20cy%3D%22233.9%22%20r%3D%220.52%22%20fill%3D%22%23fff%22%20opacity%3D%220.12%22/%3E%20%3Ccircle%20cx%3D%22475.0%22%20cy%3D%22504.3%22%20r%3D%220.88%22%20fill%3D%22%23fff%22%20opacity%3D%220.13%22/%3E%20%3Ccircle%20cx%3D%22111.9%22%20cy%3D%22321.3%22%20r%3D%220.89%22%20fill%3D%22%23fff%22%20opacity%3D%220.26%22/%3E%20%3Ccircle%20cx%3D%22357.9%22%20cy%3D%22344.2%22%20r%3D%220.49%22%20fill%3D%22%23fff%22%20opacity%3D%220.26%22/%3E%20%3Ccircle%20cx%3D%22159.8%22%20cy%3D%22128.1%22%20r%3D%220.39%22%20fill%3D%22%23fff%22%20opacity%3D%220.18%22/%3E%20%3Ccircle%20cx%3D%22511.4%22%20cy%3D%22232.9%22%20r%3D%220.71%22%20fill%3D%22%23fff%22%20opacity%3D%220.29%22/%3E%20%3Ccircle%20cx%3D%22489.2%22%20cy%3D%22203.0%22%20r%3D%220.52%22%20fill%3D%22%23fff%22%20opacity%3D%220.2%22/%3E%20%3Ccircle%20cx%3D%22164.7%22%20cy%3D%22440.5%22%20r%3D%220.84%22%20fill%3D%22%23fff%22%20opacity%3D%220.19%22/%3E%20%3Ccircle%20cx%3D%22173.9%22%20cy%3D%22283.0%22%20r%3D%220.67%22%20fill%3D%22%23fff%22%20opacity%3D%220.28%22/%3E%20%3Ccircle%20cx%3D%22127.5%22%20cy%3D%2210.6%22%20r%3D%220.48%22%20fill%3D%22%23fff%22%20opacity%3D%220.12%22/%3E%20%3Ccircle%20cx%3D%22286.6%22%20cy%3D%2236.9%22%20r%3D%220.39%22%20fill%3D%22%23fff%22%20opacity%3D%220.29%22/%3E%20%3Ccircle%20cx%3D%22151.2%22%20cy%3D%22411.9%22%20r%3D%220.62%22%20fill%3D%22%23fff%22%20opacity%3D%220.36%22/%3E%20%3Ccircle%20cx%3D%2280.2%22%20cy%3D%22260.7%22%20r%3D%220.79%22%20fill%3D%22%23fff%22%20opacity%3D%220.12%22/%3E%20%3Ccircle%20cx%3D%22493.6%22%20cy%3D%2290.1%22%20r%3D%220.78%22%20fill%3D%22%23fff%22%20opacity%3D%220.4%22/%3E%20%3Ccircle%20cx%3D%22427.2%22%20cy%3D%22166.3%22%20r%3D%220.41%22%20fill%3D%22%23fff%22%20opacity%3D%220.25%22/%3E%20%3Ccircle%20cx%3D%22478.1%22%20cy%3D%22152.6%22%20r%3D%220.84%22%20fill%3D%22%23fff%22%20opacity%3D%220.14%22/%3E%20%3Ccircle%20cx%3D%22473.5%22%20cy%3D%2216.5%22%20r%3D%220.52%22%20fill%3D%22%23fff%22%20opacity%3D%220.37%22/%3E%20%3Ccircle%20cx%3D%22418.0%22%20cy%3D%22471.7%22%20r%3D%220.81%22%20fill%3D%22%23fff%22%20opacity%3D%220.32%22/%3E%20%3Ccircle%20cx%3D%22358.6%22%20cy%3D%2292.6%22%20r%3D%220.59%22%20fill%3D%22%23fff%22%20opacity%3D%220.15%22/%3E%20%3Ccircle%20cx%3D%22371.7%22%20cy%3D%22347.2%22%20r%3D%220.49%22%20fill%3D%22%23fff%22%20opacity%3D%220.12%22/%3E%20%3Ccircle%20cx%3D%22501.0%22%20cy%3D%22420.3%22%20r%3D%220.65%22%20fill%3D%22%23fff%22%20opacity%3D%220.26%22/%3E%20%3Ccircle%20cx%3D%22442.7%22%20cy%3D%22235.7%22%20r%3D%220.57%22%20fill%3D%22%23fff%22%20opacity%3D%220.2%22/%3E%20%3Ccircle%20cx%3D%22134.1%22%20cy%3D%2212.7%22%20r%3D%220.71%22%20fill%3D%22%23fff%22%20opacity%3D%220.23%22/%3E%20%3Ccircle%20cx%3D%22296.7%22%20cy%3D%2232.4%22%20r%3D%220.55%22%20fill%3D%22%23fff%22%20opacity%3D%220.14%22/%3E%20%3Ccircle%20cx%3D%2265.1%22%20cy%3D%22134.7%22%20r%3D%220.81%22%20fill%3D%22%23fff%22%20opacity%3D%220.22%22/%3E%20%3Ccircle%20cx%3D%22208.6%22%20cy%3D%22318.5%22%20r%3D%220.48%22%20fill%3D%22%23fff%22%20opacity%3D%220.1%22/%3E%20%3Ccircle%20cx%3D%22274.9%22%20cy%3D%22260.5%22%20r%3D%220.71%22%20fill%3D%22%23fff%22%20opacity%3D%220.23%22/%3E%20%3Ccircle%20cx%3D%22357.0%22%20cy%3D%22380.3%22%20r%3D%220.48%22%20fill%3D%22%23fff%22%20opacity%3D%220.25%22/%3E%20%3Ccircle%20cx%3D%22249.0%22%20cy%3D%22117.0%22%20r%3D%220.58%22%20fill%3D%22%23fff%22%20opacity%3D%220.27%22/%3E%20%3Ccircle%20cx%3D%22471.6%22%20cy%3D%22477.2%22%20r%3D%220.5%22%20fill%3D%22%23fff%22%20opacity%3D%220.29%22/%3E%20%3Ccircle%20cx%3D%2225.1%22%20cy%3D%2237.2%22%20r%3D%220.63%22%20fill%3D%22%23fff%22%20opacity%3D%220.36%22/%3E%20%3Ccircle%20cx%3D%2282.9%22%20cy%3D%22398.3%22%20r%3D%220.84%22%20fill%3D%22%23fff%22%20opacity%3D%220.19%22/%3E%20%3Ccircle%20cx%3D%22360.1%22%20cy%3D%22441.5%22%20r%3D%220.55%22%20fill%3D%22%23fff%22%20opacity%3D%220.31%22/%3E%20%3Ccircle%20cx%3D%22382.9%22%20cy%3D%22309.2%22%20r%3D%220.82%22%20fill%3D%22%23fff%22%20opacity%3D%220.37%22/%3E%20%3Ccircle%20cx%3D%22499.2%22%20cy%3D%22297.0%22%20r%3D%220.45%22%20fill%3D%22%23fff%22%20opacity%3D%220.18%22/%3E%20%3Ccircle%20cx%3D%22113.2%22%20cy%3D%22296.1%22%20r%3D%220.77%22%20fill%3D%22%23fff%22%20opacity%3D%220.12%22/%3E%20%3Ccircle%20cx%3D%22354.5%22%20cy%3D%22372.9%22%20r%3D%220.54%22%20fill%3D%22%23fff%22%20opacity%3D%220.25%22/%3E%20%3Ccircle%20cx%3D%2285.7%22%20cy%3D%22379.5%22%20r%3D%220.37%22%20fill%3D%22%23fff%22%20opacity%3D%220.39%22/%3E%20%3Ccircle%20cx%3D%22420.1%22%20cy%3D%22326.8%22%20r%3D%220.5%22%20fill%3D%22%23fff%22%20opacity%3D%220.37%22/%3E%20%3Ccircle%20cx%3D%22498.9%22%20cy%3D%2272.3%22%20r%3D%220.78%22%20fill%3D%22%23fff%22%20opacity%3D%220.35%22/%3E%20%3Ccircle%20cx%3D%22343.1%22%20cy%3D%22364.2%22%20r%3D%220.59%22%20fill%3D%22%23fff%22%20opacity%3D%220.38%22/%3E%20%3Ccircle%20cx%3D%22505.0%22%20cy%3D%22198.8%22%20r%3D%220.79%22%20fill%3D%22%23fff%22%20opacity%3D%220.23%22/%3E%20%3Ccircle%20cx%3D%2285.7%22%20cy%3D%22169.2%22%20r%3D%220.42%22%20fill%3D%22%23fff%22%20opacity%3D%220.37%22/%3E%20%3Ccircle%20cx%3D%22498.9%22%20cy%3D%2262.0%22%20r%3D%220.68%22%20fill%3D%22%23fff%22%20opacity%3D%220.22%22/%3E%20%3Ccircle%20cx%3D%2261.4%22%20cy%3D%22153.6%22%20r%3D%220.49%22%20fill%3D%22%23fff%22%20opacity%3D%220.32%22/%3E%20%3Ccircle%20cx%3D%222.1%22%20cy%3D%2298.7%22%20r%3D%220.59%22%20fill%3D%22%23fff%22%20opacity%3D%220.11%22/%3E%20%3Ccircle%20cx%3D%22326.3%22%20cy%3D%22314.9%22%20r%3D%220.81%22%20fill%3D%22%23fff%22%20opacity%3D%220.16%22/%3E%20%3Ccircle%20cx%3D%22148.1%22%20cy%3D%22282.0%22%20r%3D%220.5%22%20fill%3D%22%23fff%22%20opacity%3D%220.28%22/%3E%20%3Ccircle%20cx%3D%22130.5%22%20cy%3D%22355.4%22%20r%3D%220.79%22%20fill%3D%22%23fff%22%20opacity%3D%220.34%22/%3E%20%3Ccircle%20cx%3D%22506.3%22%20cy%3D%22283.6%22%20r%3D%220.62%22%20fill%3D%22%23fff%22%20opacity%3D%220.36%22/%3E%20%3Ccircle%20cx%3D%22399.9%22%20cy%3D%22296.7%22%20r%3D%220.56%22%20fill%3D%22%23fff%22%20opacity%3D%220.19%22/%3E%20%3Ccircle%20cx%3D%2256.2%22%20cy%3D%22419.9%22%20r%3D%220.41%22%20fill%3D%22%23fff%22%20opacity%3D%220.32%22/%3E%20%3Ccircle%20cx%3D%22283.5%22%20cy%3D%22501.8%22%20r%3D%220.77%22%20fill%3D%22%23fff%22%20opacity%3D%220.39%22/%3E%20%3Ccircle%20cx%3D%2271.0%22%20cy%3D%22260.2%22%20r%3D%220.66%22%20fill%3D%22%23fff%22%20opacity%3D%220.19%22/%3E%20%3Ccircle%20cx%3D%22261.6%22%20cy%3D%22185.5%22%20r%3D%220.64%22%20fill%3D%22%23fff%22%20opacity%3D%220.1%22/%3E%20%3Ccircle%20cx%3D%22230.0%22%20cy%3D%22233.8%22%20r%3D%220.52%22%20fill%3D%22%23fff%22%20opacity%3D%220.22%22/%3E%20%3Ccircle%20cx%3D%22407.2%22%20cy%3D%22355.4%22%20r%3D%220.62%22%20fill%3D%22%23fff%22%20opacity%3D%220.29%22/%3E%20%3Ccircle%20cx%3D%22196.3%22%20cy%3D%22106.0%22%20r%3D%220.35%22%20fill%3D%22%23fff%22%20opacity%3D%220.18%22/%3E%20%3Ccircle%20cx%3D%22311.0%22%20cy%3D%22458.5%22%20r%3D%220.81%22%20fill%3D%22%23fff%22%20opacity%3D%220.25%22/%3E%20%3Ccircle%20cx%3D%22513.2%22%20cy%3D%22240.0%22%20r%3D%220.81%22%20fill%3D%22%23fff%22%20opacity%3D%220.22%22/%3E%20%3Ccircle%20cx%3D%22387.2%22%20cy%3D%22513.5%22%20r%3D%220.52%22%20fill%3D%22%23fff%22%20opacity%3D%220.15%22/%3E%20%3Ccircle%20cx%3D%22322.4%22%20cy%3D%22276.1%22%20r%3D%220.55%22%20fill%3D%22%23fff%22%20opacity%3D%220.1%22/%3E%20%3Ccircle%20cx%3D%22202.4%22%20cy%3D%22221.5%22%20r%3D%220.57%22%20fill%3D%22%23fff%22%20opacity%3D%220.36%22/%3E%20%3Ccircle%20cx%3D%22303.9%22%20cy%3D%22381.6%22%20r%3D%220.84%22%20fill%3D%22%23fff%22%20opacity%3D%220.32%22/%3E%20%3Ccircle%20cx%3D%22256.2%22%20cy%3D%22387.8%22%20r%3D%220.7%22%20fill%3D%22%23fff%22%20opacity%3D%220.29%22/%3E%20%3Ccircle%20cx%3D%22327.4%22%20cy%3D%22211.6%22%20r%3D%220.7%22%20fill%3D%22%23fff%22%20opacity%3D%220.29%22/%3E%20%3Ccircle%20cx%3D%22487.3%22%20cy%3D%22406.9%22%20r%3D%220.82%22%20fill%3D%22%23fff%22%20opacity%3D%220.33%22/%3E%20%3Ccircle%20cx%3D%22424.0%22%20cy%3D%22314.8%22%20r%3D%220.54%22%20fill%3D%22%23fff%22%20opacity%3D%220.18%22/%3E%20%3Ccircle%20cx%3D%22368.2%22%20cy%3D%22454.4%22%20r%3D%220.65%22%20fill%3D%22%23fff%22%20opacity%3D%220.15%22/%3E%3C/svg%3E");
  background-size: 520px 520px;
  animation: star-drift-a 150s linear infinite;
}
.star-layer--mid {
  background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%22420%22%20height%3D%22420%22%3E%3Ccircle%20cx%3D%22401.5%22%20cy%3D%22398.1%22%20r%3D%220.65%22%20fill%3D%22%23fff%22%20opacity%3D%220.38%22/%3E%20%3Ccircle%20cx%3D%22350.9%22%20cy%3D%22309.1%22%20r%3D%221.14%22%20fill%3D%22%23fff%22%20opacity%3D%220.47%22/%3E%20%3Ccircle%20cx%3D%22254.5%22%20cy%3D%22254.9%22%20r%3D%221.06%22%20fill%3D%22%23fff%22%20opacity%3D%220.41%22/%3E%20%3Ccircle%20cx%3D%22180.9%22%20cy%3D%22165.3%22%20r%3D%221.18%22%20fill%3D%22%23fff%22%20opacity%3D%220.75%22/%3E%20%3Ccircle%20cx%3D%22398.7%22%20cy%3D%22228.6%22%20r%3D%220.96%22%20fill%3D%22%23fff%22%20opacity%3D%220.46%22/%3E%20%3Ccircle%20cx%3D%2215.1%22%20cy%3D%2211.5%22%20r%3D%220.97%22%20fill%3D%22%23fff%22%20opacity%3D%220.48%22/%3E%20%3Ccircle%20cx%3D%22159.6%22%20cy%3D%22374.6%22%20r%3D%221.02%22%20fill%3D%22%23fff%22%20opacity%3D%220.57%22/%3E%20%3Ccircle%20cx%3D%2299.2%22%20cy%3D%2210.0%22%20r%3D%220.86%22%20fill%3D%22%23fff%22%20opacity%3D%220.4%22/%3E%20%3Ccircle%20cx%3D%22214.3%22%20cy%3D%22419.4%22%20r%3D%221.14%22%20fill%3D%22%23fff%22%20opacity%3D%220.42%22/%3E%20%3Ccircle%20cx%3D%22375.3%22%20cy%3D%22334.6%22%20r%3D%221.19%22%20fill%3D%22%23fff%22%20opacity%3D%220.71%22/%3E%20%3Ccircle%20cx%3D%22320.4%22%20cy%3D%22331.7%22%20r%3D%220.88%22%20fill%3D%22%23fff%22%20opacity%3D%220.74%22/%3E%20%3Ccircle%20cx%3D%22404.0%22%20cy%3D%2267.7%22%20r%3D%221.2%22%20fill%3D%22%23fff%22%20opacity%3D%220.64%22/%3E%20%3Ccircle%20cx%3D%22193.8%22%20cy%3D%22222.7%22%20r%3D%220.99%22%20fill%3D%22%23fff%22%20opacity%3D%220.72%22/%3E%20%3Ccircle%20cx%3D%22210.4%22%20cy%3D%22349.2%22%20r%3D%220.88%22%20fill%3D%22%23fff%22%20opacity%3D%220.7%22/%3E%20%3Ccircle%20cx%3D%22377.9%22%20cy%3D%22193.6%22%20r%3D%221.05%22%20fill%3D%22%23fff%22%20opacity%3D%220.72%22/%3E%20%3Ccircle%20cx%3D%22304.0%22%20cy%3D%22204.4%22%20r%3D%220.78%22%20fill%3D%22%23fff%22%20opacity%3D%220.48%22/%3E%20%3Ccircle%20cx%3D%22293.8%22%20cy%3D%2269.7%22%20r%3D%221.33%22%20fill%3D%22%23fff%22%20opacity%3D%220.46%22/%3E%20%3Ccircle%20cx%3D%22382.8%22%20cy%3D%22130.0%22%20r%3D%221.37%22%20fill%3D%22%23fff%22%20opacity%3D%220.63%22/%3E%20%3Ccircle%20cx%3D%22211.8%22%20cy%3D%22217.5%22%20r%3D%221.12%22%20fill%3D%22%23fff%22%20opacity%3D%220.59%22/%3E%20%3Ccircle%20cx%3D%22131.0%22%20cy%3D%2287.3%22%20r%3D%221.01%22%20fill%3D%22%23fff%22%20opacity%3D%220.72%22/%3E%20%3Ccircle%20cx%3D%22261.8%22%20cy%3D%2231.7%22%20r%3D%221.26%22%20fill%3D%22%23fff%22%20opacity%3D%220.64%22/%3E%20%3Ccircle%20cx%3D%22381.2%22%20cy%3D%2280.4%22%20r%3D%221.2%22%20fill%3D%22%23fff%22%20opacity%3D%220.37%22/%3E%20%3Ccircle%20cx%3D%22274.2%22%20cy%3D%22114.7%22%20r%3D%220.78%22%20fill%3D%22%23fff%22%20opacity%3D%220.7%22/%3E%20%3Ccircle%20cx%3D%2244.6%22%20cy%3D%22219.4%22%20r%3D%221.28%22%20fill%3D%22%23fff%22%20opacity%3D%220.45%22/%3E%20%3Ccircle%20cx%3D%2288.4%22%20cy%3D%22369.8%22%20r%3D%220.94%22%20fill%3D%22%23fff%22%20opacity%3D%220.64%22/%3E%20%3Ccircle%20cx%3D%2213.4%22%20cy%3D%22152.2%22%20r%3D%220.74%22%20fill%3D%22%23fff%22%20opacity%3D%220.62%22/%3E%20%3Ccircle%20cx%3D%2234.8%22%20cy%3D%22400.9%22%20r%3D%220.62%22%20fill%3D%22%23fff%22%20opacity%3D%220.64%22/%3E%20%3Ccircle%20cx%3D%228.9%22%20cy%3D%22107.4%22%20r%3D%221.25%22%20fill%3D%22%23fff%22%20opacity%3D%220.41%22/%3E%20%3Ccircle%20cx%3D%2277.2%22%20cy%3D%22290.4%22%20r%3D%220.91%22%20fill%3D%22%23fff%22%20opacity%3D%220.37%22/%3E%20%3Ccircle%20cx%3D%22415.8%22%20cy%3D%2263.6%22%20r%3D%220.63%22%20fill%3D%22%23fff%22%20opacity%3D%220.49%22/%3E%20%3Ccircle%20cx%3D%22258.4%22%20cy%3D%22311.8%22%20r%3D%220.69%22%20fill%3D%22%23fff%22%20opacity%3D%220.48%22/%3E%20%3Ccircle%20cx%3D%2212.9%22%20cy%3D%22188.4%22%20r%3D%221.21%22%20fill%3D%22%23fff%22%20opacity%3D%220.65%22/%3E%20%3Ccircle%20cx%3D%22378.8%22%20cy%3D%22317.4%22%20r%3D%221.29%22%20fill%3D%22%23fff%22%20opacity%3D%220.63%22/%3E%20%3Ccircle%20cx%3D%22198.6%22%20cy%3D%2294.7%22%20r%3D%221.13%22%20fill%3D%22%23fff%22%20opacity%3D%220.48%22/%3E%20%3Ccircle%20cx%3D%2242.9%22%20cy%3D%22188.1%22%20r%3D%221.3%22%20fill%3D%22%23fff%22%20opacity%3D%220.4%22/%3E%20%3Ccircle%20cx%3D%22245.7%22%20cy%3D%22165.0%22%20r%3D%221.01%22%20fill%3D%22%23fff%22%20opacity%3D%220.41%22/%3E%20%3Ccircle%20cx%3D%22403.1%22%20cy%3D%22108.8%22%20r%3D%221.08%22%20fill%3D%22%23fff%22%20opacity%3D%220.52%22/%3E%20%3Ccircle%20cx%3D%227.6%22%20cy%3D%22234.3%22%20r%3D%220.71%22%20fill%3D%22%23fff%22%20opacity%3D%220.37%22/%3E%20%3Ccircle%20cx%3D%2214.1%22%20cy%3D%2267.7%22%20r%3D%220.68%22%20fill%3D%22%23fff%22%20opacity%3D%220.6%22/%3E%20%3Ccircle%20cx%3D%22213.5%22%20cy%3D%22413.1%22%20r%3D%221.35%22%20fill%3D%22%23fff%22%20opacity%3D%220.75%22/%3E%20%3Ccircle%20cx%3D%2297.6%22%20cy%3D%22186.8%22%20r%3D%220.8%22%20fill%3D%22%23fff%22%20opacity%3D%220.59%22/%3E%20%3Ccircle%20cx%3D%22262.1%22%20cy%3D%22336.1%22%20r%3D%221.17%22%20fill%3D%22%23fff%22%20opacity%3D%220.45%22/%3E%20%3Ccircle%20cx%3D%22177.7%22%20cy%3D%22221.0%22%20r%3D%220.6%22%20fill%3D%22%23fff%22%20opacity%3D%220.36%22/%3E%20%3Ccircle%20cx%3D%22171.7%22%20cy%3D%2246.7%22%20r%3D%221.18%22%20fill%3D%22%23fff%22%20opacity%3D%220.45%22/%3E%20%3Ccircle%20cx%3D%2241.9%22%20cy%3D%2276.3%22%20r%3D%220.79%22%20fill%3D%22%23fff%22%20opacity%3D%220.44%22/%3E%20%3Ccircle%20cx%3D%22218.7%22%20cy%3D%22195.0%22%20r%3D%220.85%22%20fill%3D%22%23fff%22%20opacity%3D%220.61%22/%3E%20%3Ccircle%20cx%3D%2289.2%22%20cy%3D%22380.8%22%20r%3D%221.37%22%20fill%3D%22%23fff%22%20opacity%3D%220.64%22/%3E%20%3Ccircle%20cx%3D%22182.2%22%20cy%3D%22214.8%22%20r%3D%221.06%22%20fill%3D%22%23fff%22%20opacity%3D%220.37%22/%3E%20%3Ccircle%20cx%3D%22175.6%22%20cy%3D%22220.5%22%20r%3D%220.74%22%20fill%3D%22%23fff%22%20opacity%3D%220.39%22/%3E%20%3Ccircle%20cx%3D%22337.1%22%20cy%3D%22153.8%22%20r%3D%221.02%22%20fill%3D%22%23fff%22%20opacity%3D%220.72%22/%3E%20%3Ccircle%20cx%3D%22256.4%22%20cy%3D%22121.6%22%20r%3D%221.39%22%20fill%3D%22%23fff%22%20opacity%3D%220.5%22/%3E%20%3Ccircle%20cx%3D%228.0%22%20cy%3D%22287.8%22%20r%3D%220.68%22%20fill%3D%22%23fff%22%20opacity%3D%220.47%22/%3E%20%3Ccircle%20cx%3D%22353.1%22%20cy%3D%22282.5%22%20r%3D%220.61%22%20fill%3D%22%23fff%22%20opacity%3D%220.53%22/%3E%20%3Ccircle%20cx%3D%22172.5%22%20cy%3D%22204.1%22%20r%3D%220.77%22%20fill%3D%22%23fff%22%20opacity%3D%220.59%22/%3E%20%3Ccircle%20cx%3D%2231.0%22%20cy%3D%22119.4%22%20r%3D%220.9%22%20fill%3D%22%23fff%22%20opacity%3D%220.72%22/%3E%20%3Ccircle%20cx%3D%2232.2%22%20cy%3D%22317.1%22%20r%3D%220.75%22%20fill%3D%22%23fff%22%20opacity%3D%220.58%22/%3E%20%3Ccircle%20cx%3D%22164.5%22%20cy%3D%22194.6%22%20r%3D%221.2%22%20fill%3D%22%23fff%22%20opacity%3D%220.51%22/%3E%20%3Ccircle%20cx%3D%2251.1%22%20cy%3D%2251.1%22%20r%3D%220.66%22%20fill%3D%22%23fff%22%20opacity%3D%220.69%22/%3E%20%3Ccircle%20cx%3D%22269.2%22%20cy%3D%22403.1%22%20r%3D%221.15%22%20fill%3D%22%23fff%22%20opacity%3D%220.36%22/%3E%20%3Ccircle%20cx%3D%22276.8%22%20cy%3D%22326.4%22%20r%3D%221.18%22%20fill%3D%22%23fff%22%20opacity%3D%220.55%22/%3E%20%3Ccircle%20cx%3D%22150.2%22%20cy%3D%22192.0%22%20r%3D%221.24%22%20fill%3D%22%23fff%22%20opacity%3D%220.46%22/%3E%20%3Ccircle%20cx%3D%22221.0%22%20cy%3D%22200.6%22%20r%3D%221.36%22%20fill%3D%22%23fff%22%20opacity%3D%220.67%22/%3E%20%3Ccircle%20cx%3D%22391.5%22%20cy%3D%22351.1%22%20r%3D%220.84%22%20fill%3D%22%23fff%22%20opacity%3D%220.44%22/%3E%20%3Ccircle%20cx%3D%22205.3%22%20cy%3D%22109.0%22%20r%3D%220.94%22%20fill%3D%22%23fff%22%20opacity%3D%220.62%22/%3E%20%3Ccircle%20cx%3D%22385.8%22%20cy%3D%22246.1%22%20r%3D%221.25%22%20fill%3D%22%23fff%22%20opacity%3D%220.39%22/%3E%20%3Ccircle%20cx%3D%22149.5%22%20cy%3D%22419.1%22%20r%3D%220.72%22%20fill%3D%22%23fff%22%20opacity%3D%220.52%22/%3E%20%3Ccircle%20cx%3D%2228.1%22%20cy%3D%2236.2%22%20r%3D%221.32%22%20fill%3D%22%23fff%22%20opacity%3D%220.75%22/%3E%20%3Ccircle%20cx%3D%22272.2%22%20cy%3D%2254.0%22%20r%3D%220.84%22%20fill%3D%22%23fff%22%20opacity%3D%220.44%22/%3E%20%3Ccircle%20cx%3D%22281.7%22%20cy%3D%22286.1%22%20r%3D%220.95%22%20fill%3D%22%23fff%22%20opacity%3D%220.56%22/%3E%20%3Ccircle%20cx%3D%2247.1%22%20cy%3D%22227.2%22%20r%3D%221.36%22%20fill%3D%22%23fff%22%20opacity%3D%220.65%22/%3E%3C/svg%3E");
  background-size: 420px 420px;
  animation: star-drift-b 95s linear infinite reverse;
}
.star-layer--bright {
  background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%22680%22%20height%3D%22680%22%3E%3Cdefs%3E%3Cfilter%20id%3D%22g%22%20x%3D%22-200%25%22%20y%3D%22-200%25%22%20width%3D%22500%25%22%20height%3D%22500%25%22%3E%3CfeGaussianBlur%20stdDeviation%3D%220.9%22/%3E%3C/filter%3E%3C/defs%3E%3Ccircle%20cx%3D%22199.8%22%20cy%3D%22522.8%22%20r%3D%221.89%22%20fill%3D%22%23fff%22%20opacity%3D%220.71%22%20filter%3D%22url%28%23g%29%22/%3E%20%3Ccircle%20cx%3D%22417.9%22%20cy%3D%2230.6%22%20r%3D%221.75%22%20fill%3D%22%23fff%22%20opacity%3D%220.8%22%20filter%3D%22url%28%23g%29%22/%3E%20%3Ccircle%20cx%3D%22599.0%22%20cy%3D%22666.8%22%20r%3D%221.55%22%20fill%3D%22%23fff%22%20opacity%3D%221.0%22%20filter%3D%22url%28%23g%29%22/%3E%20%3Ccircle%20cx%3D%22210.6%22%20cy%3D%2252.3%22%20r%3D%221.64%22%20fill%3D%22%23fff%22%20opacity%3D%220.71%22%20filter%3D%22url%28%23g%29%22/%3E%20%3Ccircle%20cx%3D%22134.2%22%20cy%3D%22277.4%22%20r%3D%221.65%22%20fill%3D%22%23fff%22%20opacity%3D%220.75%22%20filter%3D%22url%28%23g%29%22/%3E%20%3Ccircle%20cx%3D%2228.9%22%20cy%3D%22590.1%22%20r%3D%221.38%22%20fill%3D%22%23fff%22%20opacity%3D%220.99%22%20filter%3D%22url%28%23g%29%22/%3E%20%3Ccircle%20cx%3D%22609.7%22%20cy%3D%22256.9%22%20r%3D%221.51%22%20fill%3D%22%23fff%22%20opacity%3D%220.86%22%20filter%3D%22url%28%23g%29%22/%3E%20%3Ccircle%20cx%3D%22437.8%22%20cy%3D%22405.0%22%20r%3D%221.6%22%20fill%3D%22%23fff%22%20opacity%3D%220.89%22%20filter%3D%22url%28%23g%29%22/%3E%20%3Ccircle%20cx%3D%22639.6%22%20cy%3D%22344.8%22%20r%3D%221.49%22%20fill%3D%22%23fff%22%20opacity%3D%220.92%22%20filter%3D%22url%28%23g%29%22/%3E%20%3Ccircle%20cx%3D%22161.6%22%20cy%3D%22204.7%22%20r%3D%221.98%22%20fill%3D%22%23fff%22%20opacity%3D%220.86%22%20filter%3D%22url%28%23g%29%22/%3E%20%3Ccircle%20cx%3D%22372.9%22%20cy%3D%227.8%22%20r%3D%221.47%22%20fill%3D%22%23fff%22%20opacity%3D%220.87%22%20filter%3D%22url%28%23g%29%22/%3E%20%3Ccircle%20cx%3D%2213.6%22%20cy%3D%22418.7%22%20r%3D%221.67%22%20fill%3D%22%23fff%22%20opacity%3D%220.72%22%20filter%3D%22url%28%23g%29%22/%3E%20%3Ccircle%20cx%3D%22426.6%22%20cy%3D%22317.1%22%20r%3D%221.71%22%20fill%3D%22%23fff%22%20opacity%3D%220.81%22%20filter%3D%22url%28%23g%29%22/%3E%20%3Ccircle%20cx%3D%22480.7%22%20cy%3D%22501.9%22%20r%3D%221.12%22%20fill%3D%22%23fff%22%20opacity%3D%220.72%22%20filter%3D%22url%28%23g%29%22/%3E%20%3Ccircle%20cx%3D%22459.7%22%20cy%3D%22655.0%22%20r%3D%221.33%22%20fill%3D%22%23fff%22%20opacity%3D%220.84%22%20filter%3D%22url%28%23g%29%22/%3E%20%3Ccircle%20cx%3D%22403.0%22%20cy%3D%22217.6%22%20r%3D%221.43%22%20fill%3D%22%23fff%22%20opacity%3D%220.79%22%20filter%3D%22url%28%23g%29%22/%3E%20%3Ccircle%20cx%3D%22251.0%22%20cy%3D%22405.0%22%20r%3D%221.37%22%20fill%3D%22%23fff%22%20opacity%3D%220.81%22%20filter%3D%22url%28%23g%29%22/%3E%20%3Ccircle%20cx%3D%22525.1%22%20cy%3D%2218.3%22%20r%3D%221.61%22%20fill%3D%22%23fff%22%20opacity%3D%220.92%22%20filter%3D%22url%28%23g%29%22/%3E%3C/svg%3E");
  background-size: 680px 680px;
  animation: star-drift-c 220s linear infinite;
}
@keyframes star-drift-a { from { transform: translate(0, 0); } to { transform: translate(-520px, -260px); } }
@keyframes star-drift-b { from { transform: translate(0, 0); } to { transform: translate(420px, -210px); } }
@keyframes star-drift-c { from { transform: translate(0, 0); } to { transform: translate(-340px, 340px); } }
@media (prefers-reduced-motion: reduce) {
  .star-layer { animation: none; }
}

/* The soft, warm cursor "flashlight" — same technique as .about-spotlight
   (a plain radial-gradient circle, driven by translate3d from
   setupSectionCursor's onTick in main.js), just larger and a touch
   brighter so it reads as actively revealing stars in the dark rather
   than a gentle brightening of already-visible footage. */
.hero-flashlight {
  position: absolute; top: 0; left: 0; z-index: 1;
  width: 460px; height: 460px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255,250,235,0.30) 0%, rgba(255,250,235,0.14) 38%, rgba(255,250,235,0) 70%);
  mix-blend-mode: screen;
  pointer-events: none;
  opacity: 0; transform: translate(-9999px, -9999px);
  transition: opacity 0.3s ease;
}
.hero-flashlight.is-active { opacity: 1; }

.hero-canvas {
  position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%; display: block;
  opacity: 0; transition: opacity 1.4s ease;
  pointer-events: none; /* decorative only — never intercepts clicks or scroll */
}
.hero-canvas.is-active { opacity: 1; }

/* Section cursors — PlayStation-button-inspired shapes standing in for
   the system arrow (see the "Section cursors" block in main.js, and
   .contact-cursor above for the circle, the first of these). Shared
   base: positioned, hidden until JS activates it, always outline-only
   white to match the site's monochrome palette. */
.section-cursor {
  position: absolute; top: 0; left: 0; z-index: 4;
  pointer-events: none;
  opacity: 0; transform: translate(-9999px, -9999px);
  transition: opacity 0.25s ease;
}
.section-cursor.is-active { opacity: 1; }
.section-cursor svg {
  display: block; width: 100%; height: 100%;
  fill: none; stroke: rgba(245, 245, 245, 0.85); stroke-width: 2px;
  stroke-linejoin: round; stroke-linecap: round;
}
.section-cursor--triangle, .section-cursor--x { width: 30px; height: 30px; }
.section-cursor--square {
  width: 24px; height: 24px;
  border: 1.5px solid rgba(245, 245, 245, 0.85);
  background: rgba(245, 245, 245, 0.06);
}

.hero-columns {
  position: relative; z-index: 2; width: 100%;
  display: grid; grid-template-columns: 1fr 1fr; align-items: center;
  gap: clamp(1.5rem, 5vw, 5rem);
  /* Shared 3D space for .hero-inner's own cursor-tilt (see
     updateHeroInnerTilt in main.js) — same role .hero-portrait's own
     perspective plays for .avatar-tilt, just declared one level up
     since .hero-inner (unlike the avatar) needs no separate wrapper. */
  perspective: 1200px;
}

/* transform-style + transition here mirror .avatar-tilt exactly (same
   easing curve) — the left column leans toward the cursor the same
   "anticipation" way the avatar does before it shatters, just at a
   gentler max angle appropriate to a block of readable text rather
   than a small portrait. See updateHeroInnerTilt in main.js. */
.hero-inner {
  justify-self: end; max-width: 620px; text-align: right;
  transform-style: preserve-3d;
  transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}

.eyebrow {
  color: var(--accent); font-size: 0.85rem; letter-spacing: 0.08em;
  text-transform: uppercase; margin: 0 0 1.2rem;
}

.hero-title {
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(3.2rem, 10vw, 7.2rem);
  line-height: 1.08; letter-spacing: -0.02em; margin: 0;
}
.hero-title .line { display: block; }
.hero-title .line + .line { margin-top: -0.42em; }
.hero-title .word {
  display: inline-block;
  transition: transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}
.hero-title .word:hover { transform: translateY(-0.05em) scale(1.015); }

.hero-tagline {
  font-size: clamp(1.05rem, 2vw, 1.3rem); color: var(--fg-muted);
  max-width: 560px; margin: 1.6rem 0 2.2rem;
}

.hero-actions { display: flex; gap: 1rem; flex-wrap: wrap; justify-content: flex-end; }

.hero-portrait {
  justify-self: center;
  display: flex; align-items: center; justify-content: center;
  width: clamp(130px, 12vw, 200px);
  aspect-ratio: 1 / 1;
  opacity: 0.92;
  animation: avatar-float 6s ease-in-out infinite;
  perspective: 380px;
}
.hero-portrait img {
  width: 100%; height: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: 50%;
  display: block;
}
@keyframes avatar-float {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-8px); }
}
@media (prefers-reduced-motion: reduce) {
  .hero-portrait { animation: none; }
}

/* Anticipation tilt (see updateAvatarTilt in main.js) — a separate
   wrapper between .hero-portrait (its own translateY float animation)
   and .avatar-shatter (its own per-frame burst-shake transform), so
   all three transforms compose instead of fighting over the same
   property. Cursor proximity drives rotateX/rotateY via inline style;
   the transition here is what makes that read as a gentle, eased
   "lean toward the cursor" rather than a snap. */
.avatar-tilt {
  width: 100%; height: 100%;
  transform-style: preserve-3d;
  transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}

/* Fragment/reassemble hover — replaces the plain <img> only for
   desktop + fine-pointer + motion-allowed visitors (see main.js).
   A tile grid sliced from the same portrait image; hovering
   scatters the tiles apart with a quick glitch flash, and they
   snap back together on mouse-leave. */
.avatar-shatter {
  position: relative; width: 100%; height: 100%;
  border-radius: 50%; overflow: hidden;
}
.avatar-shatter.is-hovering { overflow: visible; }
.avatar-tile {
  position: absolute;
  background-repeat: no-repeat;
  /* --scale defaults to 1.03, just enough to hide the hairline
     sub-pixel seams between adjacent tiles at rest; while scattered,
     main.js drives it down toward ~0.22 for far-flung fragments so
     they read as fine dust rather than full-size tiles */
  transform: translate(var(--tx, 0), var(--ty, 0)) rotate(var(--rot, 0deg)) scale(var(--scale, 1.03));
  opacity: var(--op, 1);
  transition: transform 0.42s cubic-bezier(0.25, 0.8, 0.35, 1), opacity 0.35s ease;
  transition-delay: var(--delay, 0s);
  will-change: transform;
}
.avatar-shatter:not(.is-hovering) .avatar-tile {
  transform: translate(0, 0) rotate(0deg) scale(1.03);
  opacity: 1;
  transition-delay: 0s;
}
/* The hover-in color/shift transient is driven from main.js as plain inline
   styles each animation frame (in lockstep with the fragment motion), not a
   separate CSS keyframe animation — that ran on its own timeline and could
   visibly drift out of sync with the fragments, part of why the burst read
   as "glitchy" rather than one smooth event. */

.scroll-cue {
  position: absolute; bottom: 2rem; left: 50%; transform: translateX(-50%);
  z-index: 2; width: 26px; height: 42px; border: 2px solid var(--line-strong);
  border-radius: 20px; display: flex; justify-content: center; padding-top: 8px;
}
.scroll-cue span {
  width: 4px; height: 8px; border-radius: 2px; background: var(--accent);
  animation: scrollcue 1.6s ease-in-out infinite;
}
@keyframes scrollcue {
  0% { opacity: 1; transform: translateY(0); }
  100% { opacity: 0; transform: translateY(14px); }
}

/* ---------- section shells ---------- */
.section-kicker {
  color: var(--accent); font-size: 0.82rem; letter-spacing: 0.1em;
  text-transform: uppercase; margin: 0 0 0.9rem; font-weight: 600;
}
.section-kicker.center { text-align: center; }

/* ---------- about ---------- */
.about {
  position: relative; overflow: hidden;
}
.about-stage { position: relative; }
/* Added only for the pinned/scrubbed treatment (desktop + motion allowed —
   see setupAboutReveal in main.js); everyone else keeps this as a plain
   auto-height block, identical to before. */
.about-stage.is-pinned {
  height: 100vh; height: 100svh;
  display: flex; align-items: center;
}
.about-bg {
  position: absolute; inset: 0; z-index: 0;
  overflow: hidden;
  background-image: url('../assets/about/about-bg-poster.jpg');
  background-size: cover; background-position: center 55%;
}
.about-bg-video {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: center 55%;
  opacity: 0; transition: opacity 1.2s ease;
}
.about-bg-video.is-active { opacity: 1; }
/* Extra dim/desaturated veil, only animated by the pinned timeline as its
   closing beat (the scene "comes alive" once the copy has revealed) — sits
   above the video, below the permanent legibility gradient. Inert (opacity
   0, no CSS transition of its own) for everyone else. */
.about-bg-veil {
  position: absolute; inset: 0; z-index: 1;
  background: var(--bg); opacity: 0; pointer-events: none;
}
/* Pre-darkened resting state for the pinned/scrubbed treatment (see
   setupAboutReveal in main.js), expressed in CSS rather than left for JS
   to set — so qualifying visitors see the near-black, textured look from
   the very first paint. Without this, the poster image (and then the
   video once it starts playing) briefly showed at full brightness during
   the window between first paint and setupAboutReveal actually running
   (which waits on the preloader), then snapped dark once JS caught up.
   Mirrors the JS gating (useAboutPin) as closely as a media query can;
   JS's own gsap.set() call sets these same values again once it runs, so
   the two never conflict — it just confirms what's already showing. */
@media (min-width: 900px) and (prefers-reduced-motion: no-preference) {
  .about-bg { filter: saturate(0.18) brightness(0.55) contrast(1.08); transform: scale(1.06); }
  .about-bg-veil { opacity: 0.55; }
}
.about-bg::after {
  content: "";
  position: absolute; inset: 0; z-index: 2;
  background:
    linear-gradient(90deg, rgba(10,10,10,0.92) 0%, rgba(10,10,10,0.6) 38%, rgba(10,10,10,0.25) 62%, rgba(10,10,10,0.45) 100%),
    linear-gradient(180deg, rgba(10,10,10,0.35) 0%, rgba(10,10,10,0.05) 25%, rgba(10,10,10,0.15) 60%, rgba(10,10,10,0.75) 100%);
}
/* Cursor-driven "spotlight" — a soft radial brightening that follows the
   pointer, standing in for the square section-cursor's background
   interaction (see the "Section cursors" block in main.js). Sits above
   the video/veil, below the readable copy grid. A plain radial-gradient
   circle rather than a blurred box: cheaper to animate (no filter
   repaint) and already soft-edged. Positioned/driven exactly like
   .section-cursor and .contact-cursor (top:0/left:0 + JS translate3d),
   so it is invisible (opacity 0, off-screen transform) until JS confirms
   the section-cursor system is actually running. */
.about-spotlight {
  position: absolute; top: 0; left: 0; z-index: 1;
  width: 340px; height: 340px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255,255,255,0.22) 0%, rgba(255,255,255,0.1) 40%, rgba(255,255,255,0) 72%);
  mix-blend-mode: overlay;
  pointer-events: none;
  opacity: 0; transform: translate(-9999px, -9999px);
  transition: opacity 0.3s ease;
}
.about-spotlight.is-active { opacity: 1; }
.about-grid {
  position: relative; z-index: 1;
  max-width: var(--maxw); margin: 0 auto; padding: 7rem var(--pad);
  display: grid; grid-template-columns: 1.5fr 1fr; gap: 3rem; align-items: start;
}
.about-copy h2 .about-title-word,
.about-copy h2 .char { display: inline-block; }
.about-copy h2 {
  font-family: var(--font-display); font-weight: 500;
  font-size: clamp(1.7rem, 3vw, 2.4rem); line-height: 1.2; margin: 0 0 1.4rem;
}
.about-copy p { color: var(--fg-muted); max-width: 620px; }
.skills {
  list-style: none; padding: 0; margin: 1.6rem 0 0; display: flex; gap: 0.7rem; flex-wrap: wrap;
}
.skills li {
  border: 1px solid var(--line-strong); border-radius: 999px;
  padding: 0.45rem 1rem; font-size: 0.85rem; color: var(--fg-muted);
}

.about-stats {
  display: flex; flex-direction: column; gap: 1.6rem;
  border-left: 1px solid var(--line); padding-left: 2rem;
}
.stat-num {
  display: block; font-family: var(--font-display); font-size: clamp(2.8rem, 5vw, 4.2rem);
  color: var(--accent); font-weight: 600; line-height: 1;
}
.stat-label { color: var(--fg-muted); font-size: 0.88rem; }

/* ---------- work / rows & columns reel ----------
   A multi-row bento mosaic (CSS grid, grid-auto-flow: column), each
   .work-tile's column/row span set inline (--cs/--rs, randomized per
   load in main.js) rather than derived from its image's own aspect
   ratio — object-fit: cover fills whichever box a tile lands in.
   grid-auto-flow: column (not "dense") wraps a tile that can't fit the
   remaining rows of the current column to the start of the next one,
   rather than opening an implicit extra row that would overflow this
   section's fixed height.
   On qualifying visitors (see useWorkPin in main.js) .work-stage picks
   up .is-pinned and holds full-height while setupWorkPin() scrubs
   .work-track horizontally against scroll; everyone else gets the
   plain :not(.is-pinned) fallback below — a native, swipeable
   horizontally-scrolling strip, no pin, no scroll-jacking. */
.work { position: relative; overflow: hidden; }

/* Non-pinned fallback (narrow viewport, reduced motion, no GSAP): the
   heading sits as a normal block above the track, revealed once by the
   generic .reveal handling — same as any other single-block section. */
.work-stage:not(.is-pinned) .work-head {
  position: relative; z-index: 1;
  max-width: 680px; margin: 0 auto; padding: 5rem var(--pad) 3rem;
}
/* Pinned desktop path: the heading is folded into workStage's own single
   pin (see setupWorkPin in main.js) as a centered overlay, rather than
   being given a separate pin of its own. It previously had one — a
   short dedicated ScrollTrigger pin immediately before this one — which
   produced a real, visually-confirmed bug: two adjacent
   anticipatePin:true pins caused workStage to pin prematurely, release,
   then re-pin a moment later, flashing blank/black space (and, at some
   scroll speeds, only a sliver of the mosaic) in the gap. Folding the
   heading's reveal into workStage's own onUpdate — driven by that one
   ScrollTrigger's progress, no second pin/spacer involved — removes
   that failure mode entirely while still guaranteeing the heading is
   seen (its opacity is a pure function of scroll position, not a
   real-time tween that a fast flick can outrun). */
.work-stage.is-pinned .work-head {
  position: absolute; inset: 0; z-index: 3;
  display: flex; flex-direction: column; justify-content: center; align-items: center;
  text-align: center;
  max-width: 680px; margin: 0 auto; padding: 0 var(--pad);
  background: var(--bg);
  pointer-events: none;
}
.work-head h2 {
  font-family: var(--font-display); font-weight: 500;
  font-size: clamp(1.7rem, 3vw, 2.4rem); line-height: 1.2; margin: 0;
}

.work-stage { position: relative; padding: 3rem 0 5rem; }
.work-stage.is-pinned {
  height: 100vh; height: 100svh;
  padding: 0; display: flex; align-items: center; overflow: hidden;
}
/* Fallback for narrow viewports, reduced motion, or no GSAP: the track
   itself becomes the scroll container, swipeable like any native
   horizontal strip — no pin-driven transform ever gets applied to it. */
.work-stage:not(.is-pinned) .work-track {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scroll-snap-type: x proximity;
}

.work-track {
  display: grid;
  grid-template-rows: repeat(3, 1fr);
  grid-auto-flow: column;
  grid-auto-columns: clamp(150px, 14vw, 210px);
  gap: 14px;
  height: min(58vh, 560px);
  padding: 0 var(--pad);
  background: var(--bg-elevated);
  will-change: transform;
}
.work-stage.is-pinned .work-track { padding: 0 6vw; }

/* "Fade from black" reveal, mirroring the About section's own bg-video
   treatment (.about-bg-veil / .about-bg's filter, see there) rather
   than inventing a new technique: on the pinned desktop path the
   mosaic starts dim/desaturated with this near-black veil sitting over
   the whole stage, and setupWorkPin's onUpdate (main.js) clears both
   together once the "Selected Work" heading has fully faded in — so
   the heading reads as being genuinely in front of the work, arriving
   before the artwork does, rather than appearing after it like before.
   Inert (opacity 0, no filter) for the non-pinned fallback — everyone
   else just sees the mosaic at full color immediately, same as always. */
.work-veil {
  position: absolute; inset: 0; z-index: 1;
  background: var(--bg); opacity: 0; pointer-events: none;
}
@media (min-width: 900px) and (prefers-reduced-motion: no-preference) {
  .work-veil { opacity: 0.85; }
  .work-track { filter: saturate(0.2) brightness(0.5) contrast(1.05); }
}

.work-tile {
  position: relative; margin: 0;
  grid-column: span var(--cs, 1);
  grid-row: span var(--rs, 1);
  border-radius: 10px; overflow: hidden;
  cursor: pointer;
  background: var(--bg-elevated);
  scroll-snap-align: center;
}
.work-tile img {
  display: block; width: 100%; height: 100%; object-fit: cover;
  transition: transform 0.6s ease;
}
.work-tile:hover img { transform: scale(1.04); }

/* Fades each tile to the page background as it nears the screen edge —
   purely cosmetic (z-index 2, pointer-events none), present regardless
   of whether the section is pinned or scrolling natively. */
.work-edge {
  position: absolute; top: 0; bottom: 0; z-index: 2;
  width: min(14vw, 220px);
  pointer-events: none;
}
.work-edge--left { left: 0; background: linear-gradient(to right, var(--bg) 0%, rgba(10,10,10,0) 100%); }
.work-edge--right { right: 0; background: linear-gradient(to left, var(--bg) 0%, rgba(10,10,10,0) 100%); }

/* Cursor-driven "crosshair" — two thin scanning beams crossing at the
   pointer, standing in for the X section-cursor's background interaction
   (see the "Section cursors" block in main.js). Spans the whole .work
   section (heading included), same as Hero/About's own cursor overlays.
   Inert (opacity 0) until JS confirms the section-cursor system is
   running. */
.work-crosshair {
  position: absolute; inset: 0; z-index: 3;
  overflow: hidden;
  pointer-events: none;
  opacity: 0; transition: opacity 0.3s ease;
}
.work-crosshair.is-active { opacity: 1; }
.work-crosshair-h,
.work-crosshair-v { position: absolute; pointer-events: none; }
.work-crosshair-h {
  left: 0; right: 0; top: 0; height: 1px;
  background: linear-gradient(90deg, rgba(245,245,245,0) 0%, rgba(245,245,245,0.55) 50%, rgba(245,245,245,0) 100%);
  mix-blend-mode: screen;
}
.work-crosshair-v {
  top: 0; bottom: 0; left: 0; width: 1px;
  background: linear-gradient(180deg, rgba(245,245,245,0) 0%, rgba(245,245,245,0.55) 50%, rgba(245,245,245,0) 100%);
  mix-blend-mode: screen;
}

/* ---------- contact ---------- */
.contact { position: relative; padding: 8rem var(--pad); text-align: center; overflow: hidden; }
/* Binary "code rain" background (see the Contact section block in
   main.js) — a plain canvas 2D effect, no WebGL needed. Off by default
   (opacity 0) until JS confirms it's actually running, so reduced-motion
   visitors (or anyone JS fails for) just see the section's flat dark
   background, never a frozen/blank canvas. */
.contact-canvas {
  position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%; display: block;
  opacity: 0; transition: opacity 1.5s ease;
  pointer-events: none;
}
.contact-canvas.is-active { opacity: 1; }
/* Darkens the center column (where the form/copy sits) so the rain stays
   legible behind the text without needing a solid card backdrop, while
   staying more visible toward the section's edges. */
.contact-vignette {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: radial-gradient(ellipse 55% 70% at 50% 42%, rgba(10,10,10,0.82) 0%, rgba(10,10,10,0.55) 45%, rgba(10,10,10,0.1) 78%, rgba(10,10,10,0) 100%);
}
/* Custom cursors, shared rules (see style.css's "section cursors" block
   further down for the shape definitions, and the "Section cursors"
   block in main.js for the behavior). Hides the system cursor by
   default wherever a section has confirmed one of these is running;
   both flip back the moment the pointer reaches a real form control,
   link or button (see .is-over-interactive), so normal affordances are
   never lost. Fine-pointer desktop only — main.js never activates any
   of these for touch, so it's harmless to leave unconditional here. */
.has-custom-cursor { cursor: none; }
.is-over-interactive { cursor: auto; }
.is-over-interactive .contact-cursor,
.is-over-interactive .section-cursor { opacity: 0; }
.contact-cursor {
  position: absolute; top: 0; left: 0; z-index: 4;
  width: 30px; height: 30px; border-radius: 50%;
  border: 1.5px solid rgba(245, 245, 245, 0.85);
  background: rgba(245, 245, 245, 0.06);
  pointer-events: none;
  opacity: 0; transform: translate(-9999px, -9999px);
  transition: opacity 0.25s ease, width 0.2s ease, height 0.2s ease, background 0.2s ease;
}
.contact-cursor.is-active { opacity: 1; }
.contact-inner { position: relative; z-index: 2; max-width: 640px; margin: 0 auto; }
.contact h2 {
  font-family: var(--font-display); font-weight: 500;
  font-size: clamp(1.9rem, 4vw, 3rem); margin: 0 0 1.8rem;
}
.contact-form {
  text-align: left; max-width: 480px; margin: 0 auto; display: flex;
  flex-direction: column; gap: 1.2rem;
}
.form-row { display: flex; flex-direction: column; gap: 0.5rem; }
.form-row label {
  font-size: 0.8rem; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--fg-muted);
}
.form-row input, .form-row textarea {
  background: var(--bg-card); border: 1px solid var(--line-strong);
  border-radius: 8px; color: var(--fg); padding: 0.75rem 0.9rem;
  font-family: var(--font-body); font-size: 0.95rem; resize: vertical;
  transition: border-color 0.2s ease;
}
.form-row input:focus, .form-row textarea:focus {
  outline: none; border-color: var(--accent);
}
.contact-form .btn { align-self: flex-start; border: none; cursor: pointer; }
.contact-form .btn:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }
.hp-field {
  position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden;
}
.form-status {
  margin: 0; font-size: 0.88rem; min-height: 1.2em; color: var(--fg-muted);
}
.form-status.is-error { color: #e5484d; }
.form-status.is-ok { color: var(--fg); }
.social-row {
  display: flex; justify-content: center; gap: 1rem; margin-top: 2.6rem;
}
.social-row a {
  display: flex; align-items: center; justify-content: center;
  width: 46px; height: 46px; border-radius: 50%;
  border: 1px solid var(--line-strong); color: var(--fg-muted);
  transition: all 0.25s ease;
}
.social-row a svg { width: 20px; height: 20px; }
.social-row a:hover { color: var(--bg); background: var(--fg); border-color: var(--fg); }

/* ---------- footer ---------- */
.site-footer {
  display: flex; justify-content: space-between; padding: 1.6rem var(--pad) 2rem;
  color: var(--fg-faint); font-size: 0.8rem; border-top: 1px solid var(--line);
  max-width: var(--maxw); margin: 0 auto;
}

/* ---------- lightbox ---------- */
.lightbox {
  position: fixed; inset: 0; z-index: 300; background: rgba(11,10,13,0.94);
  display: flex; align-items: center; justify-content: center;
  opacity: 0; pointer-events: none; transition: opacity 0.25s ease;
  padding: 3rem;
}
.lightbox.is-open { opacity: 1; pointer-events: auto; }
.lightbox figure { margin: 0; max-width: 900px; max-height: 86vh; }
.lightbox img { max-height: 76vh; width: auto; margin: 0 auto; border-radius: 8px; }
.lightbox figcaption { text-align: center; color: var(--fg-muted); margin-top: 1rem; font-size: 0.9rem; }
.lightbox figcaption:empty { display: none; margin-top: 0; }
.lightbox-close {
  position: absolute; top: 1.5rem; right: 1.8rem; background: none; border: none;
  color: var(--fg); font-size: 2.2rem; cursor: pointer; line-height: 1; z-index: 1;
}

/* ---------- reveal-on-scroll ----------
   Base hidden state only — GSAP + ScrollTrigger (or, as a fallback,
   the plain IntersectionObserver toggle in main.js) does the actual
   animating, so no CSS transition lives here: a CSS transition would
   fight GSAP's own tweening of these same properties. */
.reveal { opacity: 0; transform: translateY(24px); }
.reveal.is-visible {
  opacity: 1; transform: translateY(0);
  transition: opacity 0.7s ease, transform 0.7s ease;
  transition-delay: calc(var(--d, 0) * 0.09s);
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal, .star-layer { animation: none !important; transition: none !important; }
  .reveal { opacity: 1; transform: none; }
}

/* ---------- responsive ---------- */
@media (max-width: 900px) {
  .about-grid { grid-template-columns: 1fr; }
  .about-stats { border-left: none; padding-left: 0; border-top: 1px solid var(--line); padding-top: 1.6rem; flex-direction: row; flex-wrap: wrap; }
  .hero-columns { grid-template-columns: 1fr; text-align: center; gap: 2rem; }
  .hero-inner { justify-self: center; text-align: center; max-width: 100%; order: 2; }
  .hero-actions { justify-content: center; }
  .hero-portrait { width: clamp(140px, 34vw, 220px); order: 1; }
}

@media (max-width: 640px) {
  .main-nav {
    position: fixed; top: 64px; left: 0; right: 0; flex-direction: column;
    align-items: flex-start; gap: 0; background: var(--bg-elevated);
    border-bottom: 1px solid var(--line);
    padding: 0.5rem var(--pad) 1.2rem;
    transform: translateY(-130%); transition: transform 0.3s ease;
  }
  .main-nav.is-open { transform: translateY(0); }
  .main-nav a { padding: 0.8rem 0; width: 100%; border-bottom: 1px solid var(--line); }
  .main-nav a.nav-cta { margin-top: 0.8rem; text-align: center; }
  .main-nav .audio-widget { padding: 0.8rem 0; }
  .nav-toggle { display: flex; }
  .lightbox { padding: 1.2rem; }
}
