/* Cp3rap — one page.
 *
 * Palette from the game's css/themes.css, so the site, the game and the character read as one
 * thing. Two fonts live in fonts/ and the brand marks in icons/, which means this page makes
 * ZERO third-party requests: nothing tracks a visitor, and nothing outside can break it.
 *
 * The three things doing the work here, since the first draft had none of them:
 *   1. Scale contrast. The wordmark is enormous, labels are tiny. Nothing is medium.
 *   2. Full-bleed sections instead of bordered cards in a row.
 *   3. Real typography, real brand marks, and a little grain so it isn't a flat CSS surface.
 */

/* --- the two typefaces ------------------------------------------------------------------ */

@font-face {
  font-family: "Syne";
  src: url("fonts/syne.woff2") format("woff2");
  font-weight: 700 800;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Space Grotesk";
  src: url("fonts/space-grotesk.woff2") format("woff2");
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}

:root {
  --bg: #07040e;
  --bg-2: #120826;
  --line: rgba(190, 140, 255, 0.22);

  --accent: #8b2cff;
  --accent-soft: #c084fc;
  --green: #39ff14;
  --magenta: #ff2d9a;

  --text: #f5efff;
  --muted: #9d8cbb;

  --display: "Syne", "Segoe UI", system-ui, sans-serif;
  --body: "Space Grotesk", "Segoe UI", system-ui, -apple-system, sans-serif;

  --page: 72rem;
  --gap: clamp(4.5rem, 11vh, 8.5rem);
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--body);
  font-size: clamp(1rem, 0.95rem + 0.25vw, 1.1rem);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%;
  overflow-x: hidden;
}

img { max-width: 100%; height: auto; display: block; }
a { color: inherit; }

:focus-visible {
  outline: 3px solid var(--green);
  outline-offset: 4px;
  border-radius: 3px;
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 60;
  padding: 0.8rem 1.2rem;
  background: var(--bg-2);
  color: var(--text);
}
.skip:focus { left: 0; }

/* Film grain across everything. One generated SVG, no image file, ~0 bytes of network. */
.grain {
  position: fixed;
  inset: 0;
  z-index: 40;
  pointer-events: none;
  opacity: 0.16;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* --- hero -------------------------------------------------------------------------------- */

.hero {
  position: relative;
  min-height: 100svh;
  display: grid;
  place-items: center;
  overflow: hidden;
  padding: 6rem 1.5rem 7rem;
}

.hero-art {
  position: absolute;
  inset: 0;
  background: url("assets/hero-pulse.jpg") center 30% / cover no-repeat;
  transform: scale(1.06);          /* room for the parallax drift, so no edge shows */
  will-change: transform;
}

/* Sunk far enough that white type stays readable, and faded into the page at the bottom so
   there is no seam between the picture and the black below it. */
.hero-shade {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(120% 90% at 50% 40%, rgba(7, 4, 14, 0.15) 0%, rgba(7, 4, 14, 0.82) 70%, rgba(7, 4, 14, 0.97) 100%),
    linear-gradient(180deg, rgba(7, 4, 14, 0.75) 0%, rgba(7, 4, 14, 0.1) 35%, var(--bg) 100%);
}

.hero-inner {
  position: relative;
  width: 100%;
  max-width: var(--page);
  text-align: center;
}

.wordmark {
  margin: 0;
  width: min(100%, 60rem);
  margin-inline: auto;
  filter: drop-shadow(0 0 26px rgba(139, 44, 255, 0.6)) drop-shadow(0 0 80px rgba(139, 44, 255, 0.35));
}

.wordmark svg { display: block; width: 100%; height: auto; }

.wordmark text {
  font-family: var(--display);
  font-weight: 800;
  font-size: 215px;
  fill: var(--text);
}

.ekg {
  display: block;
  width: min(42rem, 88%);
  height: clamp(28px, 5vw, 46px);
  margin: clamp(0.75rem, 2vw, 1.5rem) auto 0;
}

.ekg path {
  fill: none;
  stroke: var(--green);
  stroke-width: 3;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
  filter: drop-shadow(0 0 7px rgba(57, 255, 20, 0.7));
  stroke-dasharray: 700;
  animation: trace 5s ease-in-out infinite;
}

@keyframes trace {
  0%   { stroke-dashoffset: 700; opacity: 0.3; }
  40%  { stroke-dashoffset: 0;   opacity: 1; }
  80%  { stroke-dashoffset: 0;   opacity: 1; }
  100% { stroke-dashoffset: -700; opacity: 0.3; }
}

.cue {
  position: absolute;
  left: 50%;
  bottom: clamp(1.5rem, 5vh, 3rem);
  transform: translateX(-50%);
  display: grid;
  justify-items: center;
  gap: 0.4rem;
  color: var(--muted);
  font-size: 0.72rem;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  text-decoration: none;
}

.cue svg {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  animation: nudge 2.4s ease-in-out infinite;
}

.cue:hover { color: var(--text); }

@keyframes nudge {
  0%, 100% { transform: translateY(0); opacity: 0.6; }
  50%      { transform: translateY(5px); opacity: 1; }
}

/* --- shared type ------------------------------------------------------------------------- */

.eyebrow {
  margin: 0 0 1rem;
  color: var(--green);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.34em;
  text-transform: uppercase;
}

.section-title {
  margin: 0;
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(2rem, 6vw, 4rem);
  line-height: 1.05;
  letter-spacing: -0.01em;
}

/* --- the release -------------------------------------------------------------------------- */

.release {
  max-width: var(--page);
  margin: 0 auto;
  padding: var(--gap) 1.5rem;
}

.release-grid {
  display: grid;
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: center;
}

@media (min-width: 54rem) {
  .release-grid { grid-template-columns: minmax(16rem, 24rem) 1fr; }
}

.cover img {
  border-radius: 10px;
  box-shadow:
    0 0 0 1px var(--line),
    0 30px 70px rgba(0, 0, 0, 0.75),
    0 0 90px rgba(139, 44, 255, 0.3);
  transform: rotate(-1.4deg);
  transition: transform 0.5s cubic-bezier(0.2, 0.7, 0.2, 1);
}

.cover img:hover { transform: rotate(0deg) scale(1.02); }

.release-title {
  margin: 0 0 1.25rem;
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(3rem, 11vw, 6.5rem);
  line-height: 0.9;
  letter-spacing: -0.02em;
}

.release-title .sub {
  display: block;
  margin-top: 0.7rem;
  font-family: var(--body);
  font-size: 0.78rem;
  font-weight: 500;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--muted);
}

.blurb {
  margin: 0 0 1rem;
  max-width: 34rem;
  font-size: clamp(1.05rem, 1rem + 0.45vw, 1.3rem);
}

.meta {
  margin: 0 0 2rem;
  color: var(--muted);
  font-size: 0.92rem;
}

.actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.9rem;
}

/* --- buttons and brand marks --------------------------------------------------------------- */

.cta {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  padding: 1.05rem 2rem;
  border-radius: 999px;
  background: linear-gradient(120deg, var(--accent) 0%, var(--magenta) 100%);
  color: #fff;
  font-weight: 700;
  font-size: 1.02rem;
  text-decoration: none;
  box-shadow: 0 10px 40px rgba(139, 44, 255, 0.45);
  transition: box-shadow 0.25s ease, transform 0.25s ease;
}

.cta svg {
  width: 1.1em;
  height: 1.1em;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform 0.25s ease;
}

.cta:hover { transform: translateY(-2px); box-shadow: 0 16px 50px rgba(139, 44, 255, 0.6); }
.cta:hover svg { transform: translateX(4px); }

.icon-link {
  display: inline-flex;
  align-items: center;
  gap: 0.65rem;
  padding: 0.85rem 1.35rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--text);
  font-weight: 500;
  text-decoration: none;
  transition: border-color 0.25s ease, background-color 0.25s ease, transform 0.25s ease;
}

.icon-link:hover {
  border-color: var(--accent-soft);
  background: rgba(139, 44, 255, 0.14);
  transform: translateY(-2px);
}

.icon-link.big { padding: 1rem 1.7rem; font-size: 1.02rem; }

/* The brand marks are real logo files, masked so they take the text colour rather than
   arriving as fixed-colour images. */
.i {
  display: inline-block;
  width: 1.3em;
  height: 1.3em;
  background-color: currentColor;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

.i-spotify { -webkit-mask-image: url("icons/spotify.svg"); mask-image: url("icons/spotify.svg"); }
.i-youtube { -webkit-mask-image: url("icons/youtube.svg"); mask-image: url("icons/youtube.svg"); }
.i-itch    { -webkit-mask-image: url("icons/itchdotio.svg"); mask-image: url("icons/itchdotio.svg"); }
.i-apple   { -webkit-mask-image: url("icons/applemusic.svg"); mask-image: url("icons/applemusic.svg"); }

/* Each mark warms to its own brand colour on hover. Subtle, and it tells a visitor the link
   is live without a single word of instruction. */
.icon-link:hover .i-spotify { color: #1ed760; }
.icon-link:hover .i-apple   { color: #fa243c; }
.icon-link:hover .i-youtube { color: #ff0033; }
.icon-link:hover .i-itch    { color: #fa5c5c; }

/* --- full-bleed feature bands --------------------------------------------------------------- */

.feature {
  position: relative;
  display: grid;
  align-items: center;
  min-height: min(78svh, 40rem);
  padding: var(--gap) 1.5rem;
  overflow: hidden;
  border-top: 1px solid var(--line);
}

.feature-art {
  position: absolute;
  inset: 0;
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
}

.feature-game .feature-art { background-image: url("assets/game-pulse.jpg"); }
.feature-tube .feature-art { background-image: url("assets/frame-yell.jpg"); background-position: center 35%; }

/* Dark where the words go, clear where the picture should be seen. Vertical on a phone,
   horizontal once there is room for text beside the image. */
.feature-art::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(7, 4, 14, 0.92) 0%, rgba(7, 4, 14, 0.72) 55%, rgba(7, 4, 14, 0.9) 100%);
}

@media (min-width: 54rem) {
  .feature-art::after {
    background: linear-gradient(90deg, rgba(7, 4, 14, 0.96) 0%, rgba(7, 4, 14, 0.8) 42%, rgba(7, 4, 14, 0.15) 100%);
  }
  .feature.reversed .feature-art::after {
    background: linear-gradient(270deg, rgba(7, 4, 14, 0.96) 0%, rgba(7, 4, 14, 0.8) 42%, rgba(7, 4, 14, 0.15) 100%);
  }
}

.feature-body {
  position: relative;
  width: 100%;
  max-width: var(--page);
  margin: 0 auto;
}

@media (min-width: 54rem) {
  .feature-body { max-width: calc(var(--page) / 2 + 6rem); margin-left: max(1.5rem, calc(50vw - var(--page) / 2)); }
  .feature.reversed .feature-body { margin-left: auto; margin-right: max(1.5rem, calc(50vw - var(--page) / 2)); text-align: right; }
  .feature.reversed .feature-body .eyebrow { text-align: right; }
}

.feature-title {
  margin: 0 0 1rem;
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(2.6rem, 9vw, 5.5rem);
  line-height: 0.92;
  letter-spacing: -0.02em;
}

.feature-text {
  margin: 0 0 2rem;
  max-width: 30rem;
  color: #d9cff0;
}

.feature.reversed .feature-text { margin-left: auto; }

/* --- the bio ---------------------------------------------------------------------------------- */

.bio {
  max-width: var(--page);
  margin: 0 auto;
  padding: var(--gap) 1.5rem;
  border-top: 1px solid var(--line);
  text-align: center;
}

/* Set larger than body copy but smaller than a section title: it is the only place on the page
   where he speaks in his own voice, so it should read as a statement rather than a caption. */
.bio-text {
  max-width: 44rem;
  margin: 0 auto 1.4rem;
  font-size: clamp(1.15rem, 1rem + 1vw, 1.7rem);
  line-height: 1.45;
}

/* The one picture of the two of them together, so the page is not only Pulse. Set wide and
   above the words, because the empty dark around them is part of the image. */
.bio-art {
  margin: 0 auto clamp(2rem, 4vw, 3rem);
  max-width: 60rem;
}

.bio-art img {
  width: 100%;
  border-radius: 12px;
  box-shadow:
    0 0 0 1px var(--line),
    0 30px 80px rgba(0, 0, 0, 0.7),
    0 0 100px rgba(139, 44, 255, 0.22);
}

.contact-avatar {
  display: block;
  width: 132px;
  height: 132px;
  margin: 0 auto 1.5rem;
  border-radius: 50%;
  object-fit: cover;
  box-shadow: 0 0 0 2px var(--accent), 0 0 44px rgba(139, 44, 255, 0.5);
}

.bio-sign {
  margin: 0;
  color: var(--muted);
  font-size: 0.95rem;
  letter-spacing: 0.08em;
}

.heart { color: var(--magenta); }

/* Present for screen readers and keyboard heading navigation, invisible on screen. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --- contact and footer ---------------------------------------------------------------------- */

.contact {
  max-width: var(--page);
  margin: 0 auto;
  padding: var(--gap) 1.5rem;
  text-align: center;
  border-top: 1px solid var(--line);
}

.contact .section-title a {
  text-decoration: none;
  background-image: linear-gradient(var(--accent-soft), var(--accent-soft));
  background-size: 0% 2px;
  background-position: 0 100%;
  background-repeat: no-repeat;
  transition: background-size 0.35s ease;
  word-break: break-word;
}

.contact .section-title a:hover { background-size: 100% 2px; }

.foot {
  max-width: var(--page);
  margin: 0 auto;
  padding: 2.5rem 1.5rem 3.5rem;
  border-top: 1px solid var(--line);
  color: var(--muted);
  font-size: 0.86rem;
  text-align: center;
}

.foot p { margin: 0 0 0.4rem; }

/* The badge sits here rather than in the hero, where it would say the name a second time.
   The artwork carries its own black square, so it needs no background of its own. */
.foot .mark {
  width: 104px;
  height: auto;
  margin: 0 auto 1.1rem;
}

.fine { opacity: 0.7; }

/* --- reveal on scroll ------------------------------------------------------------------------ */

/* Visible by default. The class only hides things once JavaScript has confirmed it is running
   AND the visitor has not asked for reduced motion - so nobody ever gets a blank page. */
.js-motion .reveal {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity 0.75s cubic-bezier(0.2, 0.7, 0.2, 1), transform 0.75s cubic-bezier(0.2, 0.7, 0.2, 1);
}

.js-motion .reveal.in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .ekg path { animation: none; stroke-dasharray: none; }
  .cue svg { animation: none; }
  .cta, .icon-link, .cover img { transition: none; }
  .cta:hover, .icon-link:hover { transform: none; }
  .cover img:hover { transform: rotate(-1.4deg); }
}
