/* ══ Theme ══════════════════════════════════════════════════ */
:root {
  --black:       #0b0608;
  --panel:       #1b1015;
  --edge:        #050203;

  --red:         #b02030;
  --red-bright:  #e0364b;
  --red-deep:    #6b1524;
  --blood:       #6e0f1d;   /* the fluid rising behind the intro */
  --white:       #efe7e0;
  --paper:       #ffffff;   /* must match the logo's interior white exactly */
  --rule:        rgba(239, 231, 224, 0.15);   /* hairlines between parts */
  --body:        #c3aeb4;
  --dim:         #8d6f78;

  --px: 4px;
  --beat: 0;
  --vitality: 0;
  --fill: 0;                 /* 0–1, how far the blood has risen */
  --glitch: 0;               /* 0–1, how hard the screen is tearing */
  --glitch-amt: 0;           /* the same tearing, driving the status line */

  --display: "Silkscreen", ui-monospace, "SF Mono", Menlo, Consolas, monospace;  /* intro only */
  --mono: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
html, body { height: 100%; }

body {
  margin: 0;
  background: var(--black);
  color: var(--body);
  font-family: var(--mono);
  -webkit-font-smoothing: antialiased;
}

/* the page can't scroll until the heart hands over */
body.is-intro { overflow: hidden; }

img { max-width: 100%; }

/* ══════════════════════════════════════════════════════════ */
/* ══ WELCOME                                               ══ */
/* ══════════════════════════════════════════════════════════ */
.welcome {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: var(--black);
  font-family: var(--display);
  letter-spacing: 0.06em;
  color: var(--white);
  -webkit-font-smoothing: none;
  transition: opacity 700ms ease, filter 700ms ease;
}

body.is-live .welcome {          /* handed over to the site */
  opacity: 0;
  filter: blur(6px) brightness(2);
  pointer-events: none;
}

.stage {
  position: relative;
  height: 100dvh;
  width: 100%;
  display: grid;
  place-items: center;
  padding: clamp(12px, 3vw, 32px);
}

/* ── panels ── */
.panel {
  position: absolute;
  background: var(--edge);
  padding: var(--px);
  border: var(--px) solid var(--edge);
  box-shadow: 0 0 0 2px rgba(176, 32, 48, 0.18);
}
.panel__inner {
  background: var(--panel);
  border: 2px solid #34191f;
  padding: clamp(8px, 1.4vw, 16px);
}

.monitor { top: clamp(12px, 3vw, 36px); left: clamp(12px, 3vw, 36px); }

.ekg-block {
  position: absolute;
  bottom: clamp(12px, 3vw, 36px);
  right: clamp(12px, 3vw, 36px);
  display: grid;
  justify-items: end;
  gap: 10px;
}
.ekg { position: relative; }          /* the block places it now */

/* once the heart is going, the status reads as bright as the readout */
.stage[data-alive="1"] .ekg-status { color: var(--white); }

.ekg-status {
  margin: 0;
  transition: color 500ms ease;
  font-size: clamp(8px, 0.85vw, 11px);
  letter-spacing: 0.12em;
  line-height: 1.7;
  color: var(--dim);
  text-align: right;
  white-space: nowrap;      /* the second line stays in one piece */
}

/* The status value tears itself apart the same way the heart does: the line is
   drawn three times, the two copies offset into red and cyan and sliced into
   bands that jump about. */
.ekg-status__value {
  position: relative;
  display: inline-block;
  text-align: left;         /* the ellipsis grows rightward into reserved space */
}
.ekg-status__value[data-glitch] { animation: statusJitter 0.24s steps(1) infinite; }

.ekg-status__value[data-glitch]::before,
.ekg-status__value[data-glitch]::after {
  content: attr(data-text);
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  pointer-events: none;
}
.ekg-status__value[data-glitch]::before {
  color: #ff2d2d;
  animation: statusSliceA 0.6s steps(1) infinite;
}
.ekg-status__value[data-glitch]::after {
  color: #2de0ff;
  animation: statusSliceB 0.47s steps(1) infinite;
}

@keyframes statusJitter {
  0%, 100% { transform: translate(0, 0); }
  25%      { transform: translate(1px, 0); }
  50%      { transform: translate(-1px, 0); }
  75%      { transform: translate(0, -1px); }
}
/* offsets ride --glitch-amt, the same escalation the canvas glitch uses, so the
   line comes apart at the same rate the heart does */
@keyframes statusSliceA {
  0%   { clip-path: inset(0 0 78% 0);   transform: translate(calc(var(--glitch-amt) * -3px), 0); }
  20%  { clip-path: inset(34% 0 42% 0); transform: translate(calc(var(--glitch-amt) *  3px), 0); }
  40%  { clip-path: inset(64% 0 10% 0); transform: translate(calc(var(--glitch-amt) * -2px), 0); }
  60%  { clip-path: inset(10% 0 70% 0); transform: translate(calc(var(--glitch-amt) *  4px), 0); }
  80%  { clip-path: inset(50% 0 28% 0); transform: translate(calc(var(--glitch-amt) * -4px), 0); }
  100% { clip-path: inset(76% 0 2% 0);  transform: translate(calc(var(--glitch-amt) *  2px), 0); }
}
@keyframes statusSliceB {
  0%   { clip-path: inset(58% 0 18% 0); transform: translate(calc(var(--glitch-amt) *  3px), 0); }
  25%  { clip-path: inset(8% 0 74% 0);  transform: translate(calc(var(--glitch-amt) * -4px), 0); }
  50%  { clip-path: inset(40% 0 36% 0); transform: translate(calc(var(--glitch-amt) *  2px), 0); }
  75%  { clip-path: inset(72% 0 6% 0);  transform: translate(calc(var(--glitch-amt) * -2px), 0); }
  100% { clip-path: inset(24% 0 58% 0); transform: translate(calc(var(--glitch-amt) *  4px), 0); }
}

.monitor__inner { min-width: clamp(120px, 13vw, 176px); }
.monitor__row { display: flex; align-items: baseline; gap: 0.4em; }

.monitor__value {
  font-size: clamp(30px, 4.4vw, 56px);
  line-height: 1;
  font-weight: 700;
  color: var(--dim);
  font-variant-numeric: tabular-nums;
  transition: color 500ms ease;
}
.monitor__unit { font-size: clamp(10px, 1.1vw, 14px); color: var(--dim); transition: color 500ms ease; }

.stage[data-alive="1"] .monitor__value {
  color: var(--red-bright);
  text-shadow: 0 0 calc(6px + 12px * var(--beat)) rgba(224, 54, 75, 0.75);
}
.stage[data-alive="1"] .monitor__unit { color: var(--white); }

.monitor__status {
  margin-top: 0.7em;
  font-size: clamp(8px, 0.85vw, 11px);
  color: var(--dim);
  border-top: 2px solid #34191f;
  padding-top: 0.6em;
  transition: color 500ms ease;
}
.stage[data-alive="1"] .monitor__status { color: var(--white); }

.ekg__inner { position: relative; padding: var(--px); }
#ekg {
  display: block;
  width: clamp(200px, 26vw, 340px);
  height: auto;
  image-rendering: pixelated;
}
.ekg__lead {
  position: absolute;
  top: 10px; left: 12px;
  font-size: 9px;
  color: rgba(239, 231, 224, 0.45);
  pointer-events: none;
}

/* ── the fluid ── */
.fluid {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: calc(var(--fill) * 100%);
  background: var(--blood);
  pointer-events: none;
  z-index: 0;
  visibility: hidden;          /* nothing to show, and no crest, until it starts */
}
.fluid[data-on] { visibility: visible; }

/* crest, drawn just above the body of the fluid */
.fluid__surface {
  position: absolute;
  left: -50%;
  right: -50%;
  bottom: 100%;
  height: 15px;
  /* a touch brighter than the body, so the surface reads as a meniscus */
  background: #8f1526;
  clip-path: polygon(
    0% 100%, 0% 55%, 8% 30%, 17% 22%, 25% 34%, 33% 58%, 42% 68%,
    50% 58%, 58% 34%, 67% 22%, 75% 30%, 83% 55%, 92% 72%, 100% 78%,
    100% 100%);
  transform-origin: bottom center;
  animation: swell 5.5s ease-in-out infinite alternate;
}
@keyframes swell {
  from { transform: translateX(-6%) scaleY(1); }
  to   { transform: translateX(6%) scaleY(1.5); }
}

/* the heart and its prompt ride above the fluid */
.heartzone { position: relative; z-index: 1; }

/* ── the heart ── */
.heartzone { display: grid; justify-items: center; gap: clamp(14px, 2.4vh, 28px); }

.heart {
  position: relative;
  display: block;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  transform: scale(var(--scale, 1));
  transform-origin: 50% 55%;
  -webkit-tap-highlight-color: transparent;
}
.heart:focus-visible { outline: none; }
.heart:focus-visible .heart__stack { outline: var(--px) solid var(--red-bright); outline-offset: 10px; }

/* fixed box so swapping between differently-shaped frames doesn't reflow */
.heart__stack {
  --h: clamp(230px, 46vh, 460px);
  position: relative;
  display: block;
  height: var(--h);
  width: calc(var(--h) * 0.84);
}

.heart__img {
  position: absolute;
  top: 0;
  left: 50%;
  height: 100%;
  width: auto;
  max-width: none;
  transform: translateX(-50%);
  filter:
    grayscale(calc(0.9 - 0.9 * var(--vitality)))
    brightness(calc(0.66 + 0.34 * var(--vitality)))
    contrast(calc(0.88 + 0.12 * var(--vitality)));
  transition: filter 700ms ease;
}
.heart__stack.is-pixel .heart__img { image-rendering: pixelated; }

/* Most flicker frames are shown white rather than red — brightness(0) throws the
   hue away, invert(1) makes it white, and the alpha survives both. */
.heart__stack.is-white .heart__img {
  filter: brightness(0) invert(1) brightness(0.88);
}

/* during the glitch the canvas draws the heart instead */
.stage[data-glitch="1"] .heart { opacity: 0; }
.stage[data-glitch="1"] .heart__glow { opacity: 0; }

.heart__glow {
  position: absolute;
  inset: -14%;
  border-radius: 50%;
  background: radial-gradient(circle,
    rgba(224, 54, 75, calc(0.30 * var(--beat) * var(--vitality))) 0%,
    transparent 62%);
  pointer-events: none;
}

.heart:hover .heart__img {
  filter:
    grayscale(calc(0.68 - 0.68 * var(--vitality)))
    brightness(calc(0.82 + 0.24 * var(--vitality)))
    contrast(calc(0.92 + 0.08 * var(--vitality)));
}

/* ── prompt + pips ── */
.prompt {
  margin: 0;
  font-size: clamp(10px, 1.15vw, 14px);
  color: var(--dim);
  text-align: center;
  animation: breathe 2.4s ease-in-out infinite;
}
.prompt[data-done="1"] { opacity: 0; animation: none; transition: opacity 500ms ease; }
@keyframes breathe { 0%, 100% { opacity: 0.45; } 50% { opacity: 1; } }

.pips { display: flex; gap: 10px; margin: 0; padding: 0; list-style: none; }
.pip {
  width: 12px; height: 12px;
  background: transparent;
  border: 2px solid #4a2b33;
  transition: background 220ms ease, border-color 220ms ease, box-shadow 220ms ease;
}
.pip[data-on="1"] {
  background: var(--red-bright);
  border-color: var(--red-bright);
  box-shadow: 0 0 10px rgba(224, 54, 75, 0.7);
}
.pips[data-done="1"] { opacity: 0; transition: opacity 500ms ease; }

.cooldown {
  width: 56px;
  height: 3px;
  background: #2a181d;
  opacity: 0;
  transition: opacity 200ms ease;
}
.cooldown[data-on="1"] { opacity: 1; }
.cooldown span {
  display: block;
  height: 100%;
  background: var(--red-bright);
  transform-origin: left center;
  transform: scaleX(var(--cool, 1));
}

/* ── corner buttons ── */
.sound, .skip {
  position: absolute;
  background: none;
  border: 2px solid #4a2b33;
  color: var(--dim);
  font-family: var(--display);
  font-size: clamp(8px, 0.85vw, 11px);
  letter-spacing: 0.14em;
  padding: 8px 12px;
  cursor: pointer;
  transition: color 200ms ease, border-color 200ms ease, opacity 300ms ease;
}
.sound:hover, .sound:focus-visible, .skip:hover, .skip:focus-visible {
  color: var(--white); border-color: var(--red); outline: none;
}
.sound { top: clamp(12px, 3vw, 36px); right: clamp(12px, 3vw, 36px); }
.sound[aria-pressed="false"] { opacity: 0.55; text-decoration: line-through; }
.skip  { bottom: clamp(12px, 3vw, 36px); left: clamp(12px, 3vw, 36px); }
.stage[data-alive="1"] .skip { opacity: 0; pointer-events: none; }

/* ── every other bit of text tears with it ──────────────────
   Chromatic offset by text-shadow rather than duplicated copies: it needs no
   mirrored content, so it works on the live BPM digits and on padded controls
   without anything to keep in sync. Offsets ride --glitch-amt like the rest.
   These come after the readout rules on purpose — the alive state puts its own
   glow on .monitor__value, and this has to win. */
.stage[data-glitch="1"] .monitor__value,
.stage[data-glitch="1"] .monitor__unit,
.stage[data-glitch="1"] .monitor__status,
.stage[data-glitch="1"] .ekg-status,
.stage[data-glitch="1"] .ekg__lead,
.stage[data-glitch="1"] .sound {
  text-shadow:
    calc(var(--glitch-amt) * -2px) 0 rgba(255, 45, 45, 0.85),
    calc(var(--glitch-amt) *  2px) 0 rgba(45, 224, 255, 0.85);
  animation: textTear 0.36s steps(1) infinite;
}
.stage[data-glitch="1"] .monitor__unit  { animation-duration: 0.29s; }
.stage[data-glitch="1"] .monitor__status { animation-duration: 0.43s; }
.stage[data-glitch="1"] .ekg__lead      { animation-duration: 0.31s; }
.stage[data-glitch="1"] .sound          { animation-duration: 0.47s; }

@keyframes textTear {
  0%   { transform: translate(calc(var(--glitch-amt) * -2px), 0); clip-path: inset(0 0 0 0); }
  20%  { transform: translate(calc(var(--glitch-amt) *  3px), 0); clip-path: inset(0 0 36% 0); }
  40%  { transform: translate(calc(var(--glitch-amt) * -1px), 0); clip-path: inset(30% 0 0 0); }
  60%  { transform: translate(calc(var(--glitch-amt) *  2px), 0); clip-path: inset(0 0 0 0); }
  80%  { transform: translate(calc(var(--glitch-amt) * -3px), 0); clip-path: inset(54% 0 10% 0); }
  100% { transform: translate(0, 0);                              clip-path: inset(0 0 0 0); }
}

/* ── CRT dressing ── */
.scanlines, .crt { position: absolute; inset: 0; pointer-events: none; }
.scanlines {
  background: repeating-linear-gradient(to bottom,
    rgba(0,0,0,0.20) 0px, rgba(0,0,0,0.20) 1px, transparent 1px, transparent 3px);
  opacity: 0.32;
}

/* the glitch is drawn here: a low-res buffer blown up with hard pixel edges */
.crt {
  width: 100%;
  height: 100%;
  opacity: var(--glitch);
  image-rendering: pixelated;
}

/* ══════════════════════════════════════════════════════════ */
/* ══ HOME                                                  ══ */
/* ══════════════════════════════════════════════════════════ */
.home {
  opacity: 0;
  transform: translateY(14px);
  pointer-events: none;
  transition: opacity 900ms ease 120ms, transform 900ms ease 120ms;
}
body.is-live .home { opacity: 1; transform: none; pointer-events: auto; }

.site-header {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 18px clamp(20px, 5vw, 64px);
  background: rgba(11, 6, 8, 0.86);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--rule);
}

.site-header__mark {
  font-size: 14px;
  font-weight: 500;
  letter-spacing: 0.08em;
  color: var(--white);
  text-decoration: none;
}
.site-header__mark span { color: var(--red-bright); margin-left: 0.5em; }

.site-nav { display: flex; gap: clamp(14px, 2.5vw, 34px); }
.site-nav a {
  font-size: 12px;
  letter-spacing: 0.08em;
  color: var(--white);
  text-decoration: none;
  padding: 4px 0;
  border-bottom: 2px solid transparent;
  transition: color 200ms ease, border-color 200ms ease;
}
.site-nav a:hover,
.site-nav a:focus-visible,
.site-nav a:active {
  color: var(--red-bright);
  border-bottom-color: var(--red-bright);
  outline: none;
}

/* White field with the logo centred on it. The logo's black bottom edge is
   flush with the black base below, so the two read as one shape running down
   into the rest of the page. */
.hero { background: var(--paper); }

.hero__stage {
  position: relative;
  padding: clamp(90px, 20vh, 220px) clamp(20px, 5vw, 64px) 0;   /* room to fall */
}
.hero__title { margin: 0; }
.hero__logo {
  display: block;
  width: min(660px, 78vw);
  height: auto;
  margin: 0 auto;
}

/* ── draggable name blocks ── */
.hero__blocks {
  position: absolute;
  inset: 0;
  overflow: hidden;
  margin: 0;
  list-style: none;
  /* Before the physics takes over — and if it never does, under reduced motion
     or with the library blocked — the names sit in a row in the clear space
     above the logo, where they cover nothing. */
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: center;
  gap: 10px;
  padding: clamp(24px, 6vh, 56px) 16px 0;
}
/* the typed line never appears without physics, so it can share that space */
.hero__blocks[data-live] { display: block; padding: 0; }
.hero__blocks[data-live] .chip { position: absolute; top: 0; left: 0; }

/* The held-name line. No collision, and painted between the logo and the
   blocks: the wrapper is positioned and sits before .hero__blocks in the DOM,
   so it covers the logo while a block dragged across it covers the line. */
.hero__sayWrap {
  position: absolute;
  inset: 0;
  padding-top: clamp(26px, 6.5vh, 66px);
  pointer-events: none;
}

.hero__say {
  /* sticks under the header, and only as far as the title section reaches */
  position: sticky;
  top: clamp(74px, 11vh, 108px);
  box-sizing: content-box;
  width: fit-content;
  max-width: 90%;
  margin: 0 auto;
  padding: 7px 12px;
  /* it travels down over the black logo, so it carries its own ground */
  background: var(--paper);
  color: var(--black);
  font-size: clamp(13px, 1.4vw, 17px);
  line-height: 1.5;
  letter-spacing: -0.01em;
  text-align: left;
  white-space: pre;
  opacity: 0;
  transition: opacity 260ms ease;
}
.hero__say[data-on] { opacity: 1; }

/* holds the width of the untyped remainder so nothing shifts as it types */
.hero__ghost { visibility: hidden; }

.hero__caret {
  display: inline-block;
  width: 1ch;
  height: 1.05em;
  background: var(--red-bright);
  vertical-align: -0.18em;
}
.hero__say[data-done] .hero__caret { animation: caret 1s steps(1) infinite; }
@keyframes caret { 0%, 50% { opacity: 1; } 50.01%, 100% { opacity: 0; } }

.chip {
  display: inline-flex;
  align-items: center;
  height: 44px;
  padding: 0 18px;
  background: var(--paper);
  border: 2px solid var(--black);
  border-radius: 12px;
  color: var(--black);
  font-size: 15px;
  font-weight: 500;
  letter-spacing: -0.01em;
  white-space: nowrap;
  user-select: none;
  -webkit-user-select: none;
  touch-action: none;          /* the chip takes the drag; the page still scrolls */
  cursor: grab;
  will-change: transform;
}
.hero__blocks[data-dragging] .chip { cursor: grabbing; }

.hero__base {
  background: var(--black);
  margin-top: -2px;                 /* eat any sub-pixel gap at the seam */
  padding: clamp(30px, 5vh, 60px) clamp(20px, 5vw, 64px) clamp(44px, 9vh, 96px);
  text-align: center;
}
.hero__tag {
  margin: 0;
  font-size: clamp(11px, 1.15vw, 13px);
  letter-spacing: 0.22em;
  color: var(--red-bright);
}
.hero__lede {
  margin: 1.6em auto 0;
  max-width: 60ch;
  font-weight: 300;
  font-size: clamp(14px, 1.35vw, 17px);
  line-height: 1.75;
}

/* the section after the hero continues that black — no dividing line */
.hero + .section { border-top: 0; }

.section {
  padding: clamp(40px, 8vh, 80px) clamp(20px, 5vw, 64px);
  border-top: 1px solid var(--rule);
  max-width: 1200px;
  margin-inline: auto;          /* sit on the page centre like the hero */
}
.section__title {
  margin: 0 0 2.2em;
  font-weight: 400;
  font-size: 12px;
  letter-spacing: 0.22em;
  color: var(--dim);
  text-align: center;
}
.contact { text-align: center; }

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: clamp(20px, 3vw, 40px);
  margin: 0; padding: 0;
  list-style: none;
}

.card__link {
  display: block;
  color: inherit;
  text-decoration: none;
}
.card__link:focus-visible { outline: 2px solid var(--red-bright); outline-offset: 6px; }

/* placeholder tiles until there are real thumbnails */
.card__art {
  display: grid;
  place-items: center;
  aspect-ratio: 4 / 3;
  border: 2px solid var(--rule);
  background-color: #0e0709;
  background-image:
    repeating-linear-gradient(to right,  rgba(239, 231, 224, 0.05) 0 1px, transparent 1px 10px),
    repeating-linear-gradient(to bottom, rgba(239, 231, 224, 0.05) 0 1px, transparent 1px 10px);
  transition: border-color 250ms ease, transform 250ms ease;
}
.card__art[data-art="2"] { background-position: 4px 0, 0 4px; }
.card__art[data-art="3"] { background-position: 8px 0, 0 8px; }
.card__art[data-art="4"] { background-position: 2px 0, 0 6px; }
a.card__link:hover .card__art,
a.card__link:focus-visible .card__art { border-color: var(--red); transform: translateY(-4px); }

/* thumbnail and play glyph share one grid cell so they stack */
.card__art > * { grid-area: 1 / 1; }

.card__thumb {
  place-self: stretch;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: brightness(0.84) saturate(0.95);
  transition: filter 250ms ease;
}
a.card__link:hover .card__thumb,
a.card__link:focus-visible .card__thumb { filter: brightness(1) saturate(1); }

.card__play {
  width: 0;
  height: 0;
  /* stacked shadows give a dark halo, so the glyph reads on a busy thumbnail
     without needing a visible disc behind it */
  filter: drop-shadow(0 0 9px rgba(0, 0, 0, 0.95))
          drop-shadow(0 1px 3px rgba(0, 0, 0, 0.85));
  border-style: solid;
  border-width: 11px 0 11px 19px;
  border-color: transparent transparent transparent var(--white);
  opacity: 0.4;
  transition: opacity 250ms ease, transform 250ms ease;
}
a.card__link:hover .card__play,
a.card__link:focus-visible .card__play { opacity: 1; transform: scale(1.15); }

.card__soon {
  font-size: 10px;
  letter-spacing: 0.2em;
  color: var(--dim);
  border: 1px solid #3a2129;
  padding: 6px 10px;
}
.card--soon .card__art { opacity: 0.6; }
.card--soon .card__title { color: var(--body); }

.card__title {
  margin: 1.2em 0 0.5em;
  font-weight: 500;
  font-size: 16px;
  letter-spacing: -0.01em;
  color: var(--white);
}
.card__meta {
  margin: 0 0 1em;
  font-size: 11px;
  letter-spacing: 0.16em;
  color: var(--red-bright);
}
.card__note { margin: 0; font-weight: 300; font-size: 14px; line-height: 1.7; }

.vh {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.contact a {
  font-size: clamp(15px, 2.2vw, 28px);
  font-weight: 500;
  letter-spacing: -0.02em;
  color: var(--white);
  text-decoration: none;
  border-bottom: 2px solid var(--red);
  padding-bottom: 6px;
  transition: color 200ms ease, border-color 200ms ease;
}
.contact a:hover, .contact a:focus-visible { color: var(--red-bright); border-color: var(--red-bright); outline: none; }

.site-footer {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  padding: 28px clamp(20px, 5vw, 64px) 48px;
  border-top: 1px solid var(--rule);
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--dim);
}
.site-footer p { margin: 0; margin-right: auto; }
.site-footer__heart {
  width: 18px;
  image-rendering: pixelated;
  animation: footbeat 1s ease-in-out infinite;
}
@keyframes footbeat {
  0%, 62%, 100% { transform: scale(1); }
  8%  { transform: scale(1.16); }
  20% { transform: scale(1); }
  30% { transform: scale(1.09); }
}

.replay {
  background: none;
  border: 2px solid #4a2b33;
  color: var(--dim);
  font: inherit;
  padding: 7px 11px;
  cursor: pointer;
  transition: color 200ms ease, border-color 200ms ease;
}
.replay:hover, .replay:focus-visible { color: var(--white); border-color: var(--red); outline: none; }

/* ══ Small screens ══════════════════════════════════════════ */
@media (max-width: 720px) {
  :root { --px: 3px; }
  .heart__stack { --h: clamp(180px, 33vh, 290px); }
  /* The gap either side of the logo has to be wider than the widest block,
     or a block slid down the slope gets wedged against the wall. */
  .hero__logo { width: 58vw; }
  .hero__stage { padding-top: clamp(110px, 26vh, 200px); }
  .chip { height: 32px; padding: 0 11px; font-size: 11px; border-radius: 9px; }
  .monitor { top: 12px; left: 12px; }
  .sound   { top: 12px; right: 12px; }
  .skip    { bottom: 12px; left: 12px; }
  .ekg-block { bottom: 12px; right: 50%; transform: translateX(50%); justify-items: center; }
  .ekg-status { text-align: center; }
  #ekg { width: min(74vw, 320px); }
  .skip { bottom: calc(12px + 190px); }
  .site-header { padding: 14px 20px; }
  .site-nav { gap: 16px; }
}

@media (max-width: 480px) {
  /* keep the header on one line on small phones */
  .site-header { padding: 12px 16px; }
  .site-header__mark { font-size: 11px; }
  .site-header__mark span { display: none; }
  .site-nav { gap: 14px; }
  .site-nav a { font-size: 10px; letter-spacing: 0.04em; }
}

/* ══ Reduced motion ═════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
  .fluid__surface { animation: none; }
  .stage[data-glitch="1"] .monitor__value,
  .stage[data-glitch="1"] .monitor__unit,
  .stage[data-glitch="1"] .monitor__status,
  .stage[data-glitch="1"] .ekg-status,
  .stage[data-glitch="1"] .ekg__lead,
  .stage[data-glitch="1"] .sound { animation: none; text-shadow: none; }
  .ekg-status__value[data-glitch],
  .ekg-status__value[data-glitch]::before,
  .ekg-status__value[data-glitch]::after { animation: none; }
  .ekg-status__value[data-glitch]::before,
  .ekg-status__value[data-glitch]::after { display: none; }
  .hero__say { transition-duration: 1ms; }
  .hero__say[data-done] .hero__caret { animation: none; }
  html { scroll-behavior: auto; }
  .prompt { animation: none; opacity: 0.8; }
  .site-footer__heart { animation: none; }
  .stage, .heart__img, .home, .welcome { transition-duration: 1ms; }
}
