/* ==========================================================================
   Utilitarian dark. Neutral charcoal, hairline rules, one ice-blue accent.
   Keys are mono and lowercase; values are the thing you actually read.
   ========================================================================== */

:root {
  --bg: #131416;
  --panel: #1a1c1f;
  --line: #25282c;
  --line-2: #33373c;
  --fg: #e7e8ea;
  --mut: #83878d;
  --acc: #6fb6d9;
  --acc-dim: rgba(111, 182, 217, 0.09);
  --alert: #e07a6a;

  --sans: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, 'SFMono-Regular', monospace;

  --gutter: clamp(20px, 5vw, 40px);
  --radius: 4px;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100vh;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.6;
  font-feature-settings: 'tnum' 1;
}

a {
  color: inherit;
}

:focus-visible {
  outline: 2px solid var(--acc);
  outline-offset: 2px;
  border-radius: 2px;
}

.sheet {
  max-width: 760px;
  margin: 0 auto;
  padding: 0 var(--gutter);
}

/* ── Hero ────────────────────────────────────────────────────────────────── */

.hero {
  padding: clamp(44px, 8vw, 76px) 0 clamp(28px, 5vw, 40px);
}

.hero--split {
  display: grid;
  gap: 28px;
  align-items: start;
}

@media (min-width: 760px) {
  .hero--split {
    grid-template-columns: minmax(0, 1fr) minmax(230px, 288px);
    gap: 48px;
  }
  /* Optical alignment: drops the card's label onto the eyebrow's baseline. */
  .hero__aside {
    padding-top: 4px;
  }
}

.hero__text > *:first-child {
  margin-top: 0;
}

.eyebrow {
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: 0.12em;
  color: var(--acc);
  margin: 0;
}

.hero__name {
  font-size: clamp(2.4rem, 9vw, 3.4rem);
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: -0.03em;
  margin: 0.3em 0 0;
  overflow-wrap: break-word;
}

.hero__role {
  font-size: 15px;
  color: var(--mut);
  margin: 0.85em 0 0;
}

.hero__tagline {
  font-size: 15px;
  color: var(--mut);
  max-width: 52ch;
  margin: 0.6em 0 0;
}

/* ── Sections ────────────────────────────────────────────────────────────── */

.block {
  padding: clamp(28px, 5vw, 44px) 0;
  border-top: 1px solid var(--line);
}

.block__head {
  display: flex;
  align-items: baseline;
  gap: 14px;
  margin-bottom: 20px;
}

.block__head h2 {
  font-family: var(--mono);
  font-size: 11.5px;
  font-weight: 400;
  letter-spacing: 0.12em;
  color: var(--acc);
  margin: 0;
  white-space: nowrap;
}

.block__head .fill {
  flex: 1;
  height: 1px;
  background: var(--line);
}

.block__head .count {
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--mut);
  white-space: nowrap;
}

/* ── Parts list ──────────────────────────────────────────────────────────── */

.bom {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}

.bom thead th {
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 400;
  letter-spacing: 0.1em;
  color: var(--mut);
  text-align: left;
  padding: 0 14px 9px 0;
  border-bottom: 1px solid var(--line);
}

.bom td {
  padding: 9px 14px 9px 0;
  border-bottom: 1px solid var(--line);
  vertical-align: baseline;
}

.bom tbody tr:last-child td {
  border-bottom: 0;
}

.bom tbody tr {
  transition: background-color 110ms ease;
}
.bom tbody tr:hover {
  background-color: rgba(255, 255, 255, 0.022);
}

.bom .item {
  width: 3rem;
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--mut);
}

.bom .label {
  width: 7.5rem;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--acc);
  opacity: 0.9;
}

.bom .value {
  font-weight: 400;
}

.bom .note {
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--mut);
  text-align: right;
  white-space: nowrap;
}

/* ── Links ───────────────────────────────────────────────────────────────── */

.links {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.link {
  display: inline-flex;
  align-items: baseline;
  gap: 9px;
  padding: 8px 14px;
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  font-family: var(--mono);
  font-size: 12.5px;
  text-decoration: none;
  color: var(--fg);
  background: transparent;
  transition: border-color 130ms ease, background-color 130ms ease, color 130ms ease;
}

.link__handle {
  color: var(--mut);
  transition: color 130ms ease;
}

.link:hover,
.link:focus-visible {
  border-color: var(--acc);
  background: var(--acc-dim);
  color: var(--acc);
}

.link:hover .link__handle,
.link:focus-visible .link__handle {
  color: var(--acc);
  opacity: 0.75;
}

/* ── Footer ──────────────────────────────────────────────────────────────── */

.foot {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 20px;
  justify-content: space-between;
  padding: 20px 0 40px;
  border-top: 1px solid var(--line);
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--mut);
}

.foot a {
  text-decoration: none;
  transition: color 130ms ease;
}
.foot a:hover {
  color: var(--acc);
}

/* ── Viewer ──────────────────────────────────────────────────────────────── */

.plate {
  margin: clamp(28px, 5vw, 44px) 0 0;
  display: flex;
  justify-content: center;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 12px;
}

.plate img,
.plate video {
  display: block;
  max-width: 100%;
  max-height: 76vh;
  height: auto;
  border-radius: 2px;
}

.facts {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 28px;
  padding: 18px 0;
  margin: 0;
}

.facts div {
  min-width: 84px;
}

.facts dt {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.1em;
  color: var(--mut);
  margin: 0 0 2px;
}

.facts dd {
  font-family: var(--mono);
  font-size: 13px;
  margin: 0;
}

/* ── Uploader ────────────────────────────────────────────────────────────── */

.field {
  display: block;
  margin-bottom: 18px;
}

.field span {
  display: block;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--mut);
  margin-bottom: 7px;
}

input[type='password'],
input[type='text'] {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  background: var(--panel);
  color: var(--fg);
  font-family: var(--mono);
  font-size: 13px;
}

input:focus {
  outline: none;
  border-color: var(--acc);
}

.drop {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 170px;
  padding: 26px;
  border: 1px dashed var(--line-2);
  border-radius: var(--radius);
  background: var(--panel);
  text-align: center;
  cursor: pointer;
  transition: border-color 130ms ease, background-color 130ms ease;
}

.drop:hover,
.drop.is-over {
  border-color: var(--acc);
  background: var(--acc-dim);
}

.drop strong {
  font-size: 15px;
  font-weight: 500;
}

.drop small {
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--mut);
}

.status {
  margin-top: 16px;
  font-family: var(--mono);
  font-size: 12.5px;
  min-height: 1.5em;
  color: var(--mut);
}
.status[data-tone='error'] { color: var(--alert); }
.status[data-tone='ok'] { color: var(--acc); }

.result {
  margin-top: 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--panel);
  padding: 14px 16px;
  display: none;
}
.result.is-shown { display: block; }

.result .eyebrow {
  color: var(--mut);
  margin-top: 10px;
}
.result .eyebrow:first-child { margin-top: 0; }

.result code {
  display: block;
  font-family: var(--mono);
  font-size: 12.5px;
  color: var(--acc);
  overflow-wrap: anywhere;
  padding: 5px 0 2px;
}

.btn {
  display: inline-block;
  margin-top: 12px;
  padding: 8px 15px;
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  background: transparent;
  color: var(--fg);
  font-family: var(--mono);
  font-size: 12px;
  cursor: pointer;
  text-decoration: none;
  transition: border-color 130ms ease, background-color 130ms ease, color 130ms ease;
}

.btn:hover {
  border-color: var(--acc);
  background: var(--acc-dim);
  color: var(--acc);
}

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
  gap: 6px;
}

.gallery a {
  position: relative;
  aspect-ratio: 1;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  transition: border-color 130ms ease;
}

.gallery a:hover {
  border-color: var(--acc);
}

.gallery img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.78;
  transition: opacity 130ms ease;
}

.gallery a:hover img {
  opacity: 1;
}

.gallery .slug {
  position: absolute;
  inset: auto 0 0 0;
  padding: 3px 6px;
  background: rgba(19, 20, 22, 0.88);
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--mut);
}

.empty {
  padding: 30px 16px;
  border: 1px dashed var(--line-2);
  border-radius: var(--radius);
  text-align: center;
  font-family: var(--mono);
  font-size: 12.5px;
  color: var(--mut);
}

.prose {
  max-width: 60ch;
  color: var(--mut);
  font-size: 14.5px;
}
.prose strong {
  color: var(--fg);
  font-weight: 500;
}

/* ── Narrow screens ─────────────────────────────────────────────────────── */

@media (max-width: 620px) {
  .bom thead {
    display: none;
  }
  .bom tr {
    display: grid;
    grid-template-columns: 2.6rem 1fr;
    gap: 1px 10px;
    padding: 11px 0;
    border-bottom: 1px solid var(--line);
  }
  .bom td {
    padding: 0;
    border: 0;
  }
  .bom .item {
    grid-row: span 3;
    width: auto;
  }
  .bom .label,
  .bom .note {
    width: auto;
    text-align: left;
    white-space: normal;
  }
}

@media (prefers-reduced-motion: reduce) {
  * {
    transition-duration: 0.01ms !important;
  }
}

/* ── Icons in link pills ─────────────────────────────────────────────────── */

.ico {
  flex: none;
  display: block;
  transform: translateY(0.09em);
}

.link {
  align-items: center;
}

.link__platform {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

/* ── Listening to ────────────────────────────────────────────────────────── */

.np[hidden] {
  display: none;
}

.np__slot {
  display: block;
  transition: opacity 260ms ease;
}

.np__slot.is-swapping {
  opacity: 0;
}

.np__label {
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: 0.12em;
  color: var(--acc);
  margin: 0 0 10px;
}

/* The section version already has a heading above it. */
.np:not(.np--hero) .np__label {
  display: none;
}

.np--hero .np__card {
  padding: 10px;
  gap: 11px;
}

.np--hero .np__art {
  width: 46px;
  height: 46px;
}

.np--hero .np__title {
  font-size: 13.5px;
}

.np--hero .np__artist {
  font-size: 11.5px;
}

.np--hero .np__eq {
  height: 13px;
}

.np__card {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px;
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  background: var(--panel);
  text-decoration: none;
  color: var(--fg);
  transition: border-color 130ms ease, background-color 130ms ease;
}

a.np__card:hover,
a.np__card:focus-visible {
  border-color: var(--acc);
  background: var(--acc-dim);
}

.np__art {
  flex: none;
  width: 56px;
  height: 56px;
  border-radius: 2px;
  object-fit: cover;
  background: var(--bg);
}

.np__art--empty {
  display: block;
  border: 1px solid var(--line);
}

.np__meta {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.np__title,
.np__artist {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.np__title {
  font-size: 14.5px;
  font-weight: 500;
}

.np__artist {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--mut);
}

a.np__card:hover .np__title {
  color: var(--acc);
}

/* Three bars, loosely a level meter. Purely decorative. */
.np__eq {
  flex: none;
  display: flex;
  align-items: flex-end;
  gap: 3px;
  height: 15px;
}

.np__eq i {
  width: 3px;
  background: var(--acc);
  border-radius: 1px;
  animation: np-bounce 1.1s ease-in-out infinite;
}

.np__eq i:nth-child(1) { height: 60%; animation-delay: -0.2s; }
.np__eq i:nth-child(2) { height: 100%; animation-delay: -0.55s; }
.np__eq i:nth-child(3) { height: 40%; animation-delay: -0.8s; }

@keyframes np-bounce {
  0%, 100% { transform: scaleY(0.35); }
  50%      { transform: scaleY(1); }
}

.np__eq i {
  transform-origin: bottom;
}

.np__bar {
  height: 2px;
  margin-top: 10px;
  background: var(--line);
  border-radius: 1px;
  overflow: hidden;
}

.np__fill {
  display: block;
  height: 100%;
  background: var(--acc);
}

.np__times {
  display: flex;
  justify-content: space-between;
  margin-top: 5px;
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--mut);
}

.np__idle {
  margin: 0;
  font-family: var(--mono);
  font-size: 12.5px;
  color: var(--mut);
}

@media (prefers-reduced-motion: reduce) {
  .np__eq i {
    animation: none;
    transform: scaleY(0.7);
  }
}

/* ── Collapsible tables ──────────────────────────────────────────────────── */

.fold summary {
  cursor: pointer;
  list-style: none;
  /* The default triangle would fight the chevron below. */
  margin-bottom: 20px;
}

.fold summary::-webkit-details-marker,
.fold summary::marker {
  display: none;
}

.fold summary:focus-visible {
  outline: 2px solid var(--acc);
  outline-offset: 4px;
  border-radius: 2px;
}

.fold summary .count {
  transition: color 130ms ease;
}

.fold summary:hover h2,
.fold summary:hover .count,
.fold summary:hover .chev {
  color: var(--acc);
}

.chev {
  flex: none;
  width: 8px;
  height: 8px;
  border-right: 1.5px solid var(--mut);
  border-bottom: 1.5px solid var(--mut);
  transform: rotate(45deg) translateY(-1px);
  transform-origin: center;
  transition: transform 160ms ease, border-color 130ms ease;
}

.fold summary:hover .chev {
  border-color: var(--acc);
}

.fold[open] summary .chev {
  transform: rotate(225deg) translateY(-1px);
}

/* When collapsed, the header shouldn't carry the open-state bottom gap. */
.fold:not([open]) summary {
  margin-bottom: 0;
}

/* ── Page-load sequence ──────────────────────────────────────────────────── */
/*
   One gesture: content rises into place while the hairline rules draw
   themselves left to right, like a panel coming up. Everything is wrapped in
   `no-preference`, so a visitor who opts out of motion gets a completely static
   page rather than an override fighting a default. Nothing starts at opacity 0
   outside this block, so the page is still readable if the CSS never loads.
*/

@media (prefers-reduced-motion: no-preference) {
  @keyframes rise {
    from {
      opacity: 0;
      transform: translateY(8px);
    }
    to {
      opacity: 1;
      transform: none;
    }
  }

  @keyframes draw {
    from { transform: scaleX(0); }
    to   { transform: scaleX(1); }
  }

  .hero__text > *,
  .hero__aside,
  .block,
  .foot {
    animation: rise 520ms cubic-bezier(0.2, 0.7, 0.3, 1) both;
  }

  .hero__text > *:nth-child(1) { animation-delay: 0ms; }
  .hero__text > *:nth-child(2) { animation-delay: 60ms; }
  .hero__text > *:nth-child(3) { animation-delay: 120ms; }
  .hero__text > *:nth-child(4) { animation-delay: 170ms; }
  .hero__aside { animation-delay: 210ms; }

  .block:nth-of-type(1) { animation-delay: 240ms; }
  .block:nth-of-type(2) { animation-delay: 300ms; }
  .block:nth-of-type(3) { animation-delay: 360ms; }
  .block:nth-of-type(4) { animation-delay: 420ms; }
  .foot { animation-delay: 480ms; }

  .block__head .fill {
    transform-origin: left center;
    animation: draw 620ms cubic-bezier(0.2, 0.7, 0.3, 1) both;
  }

  .block:nth-of-type(1) .fill { animation-delay: 330ms; }
  .block:nth-of-type(2) .fill { animation-delay: 390ms; }
  .block:nth-of-type(3) .fill { animation-delay: 450ms; }
  .block:nth-of-type(4) .fill { animation-delay: 510ms; }

  /* Pills arrive last, one after another. */
  .links .link {
    animation: rise 420ms cubic-bezier(0.2, 0.7, 0.3, 1) both;
  }
  .links .link:nth-child(1) { animation-delay: 470ms; }
  .links .link:nth-child(2) { animation-delay: 510ms; }
  .links .link:nth-child(3) { animation-delay: 550ms; }
  .links .link:nth-child(4) { animation-delay: 590ms; }
  .links .link:nth-child(5) { animation-delay: 630ms; }
  .links .link:nth-child(6) { animation-delay: 670ms; }
}

/* ── Row reveal ──────────────────────────────────────────────────────────── */
/*
   Only active once reveal.js has added .js-reveal to <html>, so a failed or
   blocked script leaves a plain, fully visible table.
*/

.js-reveal .bom tbody tr {
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 420ms cubic-bezier(0.2, 0.7, 0.3, 1),
    transform 420ms cubic-bezier(0.2, 0.7, 0.3, 1);
}

.js-reveal .bom tbody tr.is-in {
  opacity: 1;
  transform: none;
}

/* ── Row hover ───────────────────────────────────────────────────────────── */
/*
   An accent bar wipes in from the left. Drawn on the first cell rather than
   the row, because a table row won't take a pseudo-element reliably.
*/

.bom tbody td:first-child {
  position: relative;
}

.bom tbody td:first-child::before {
  content: '';
  position: absolute;
  left: -14px;
  top: 2px;
  bottom: 2px;
  width: 2px;
  background: var(--acc);
  transform: scaleY(0);
  transform-origin: center;
  transition: transform 160ms cubic-bezier(0.2, 0.7, 0.3, 1);
}

.bom tbody tr:hover td:first-child::before {
  transform: scaleY(1);
}

@media (max-width: 620px) {
  /* No room for a bleed outside the gutter on narrow screens. */
  .bom tbody td:first-child::before {
    left: -10px;
  }
}

/* ── Album-art tint ──────────────────────────────────────────────────────── */
/*
   --np-accent is set by now-playing.js from the cover art and falls back to
   the site accent, so an unreadable or washed-out cover changes nothing.
*/

.np {
  --np-accent: var(--acc);
  /* Declared here, not on :root, because this is the element JS writes to. */
  transition: --np-accent var(--amb-fade, 4s) ease;
}

.np--hero .np__label {
  color: var(--np-accent);
  transition: color 400ms ease;
}

.np__card {
  transition: border-color 400ms ease, background-color 130ms ease;
}

.np__eq i {
  background: var(--np-accent);
  transition: background-color 400ms ease;
}

.np__fill {
  background: var(--np-accent);
  transition: background-color 400ms ease;
}

a.np__card:hover,
a.np__card:focus-visible {
  border-color: var(--np-accent);
  background: color-mix(in srgb, var(--np-accent) 9%, transparent);
}

a.np__card:hover .np__title {
  color: var(--np-accent);
}

/* ── Hover detail on spec rows ───────────────────────────────────────────── */
/*
   Note and detail occupy the same grid cell, so the column is sized by the
   longer of the two and swapping between them shifts nothing. Expanding the
   row instead would move every row below it while the cursor is mid-travel.
*/

.note__stack {
  display: grid;
}

.note__stack > * {
  grid-area: 1 / 1;
  transition: opacity 180ms ease;
}

.note__b {
  opacity: 0;
  color: var(--acc);
}

.bom tbody tr.has-detail:hover .note__a {
  opacity: 0;
}

.bom tbody tr.has-detail:hover .note__b {
  opacity: 1;
}

/* No hover on touch, so show the detail outright and drop the swap. */
@media (hover: none) {
  .note__stack {
    display: block;
  }
  .note__b {
    opacity: 1;
    display: block;
    margin-top: 2px;
  }
}

/* ── Status ──────────────────────────────────────────────────────────────── */

.status {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 28px;
}

.status__row {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-family: var(--mono);
  font-size: 12.5px;
}

.status__dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--line-2);
  flex: none;
  transition: background-color 200ms ease, box-shadow 200ms ease;
}

.status__row.is-up .status__dot {
  background: var(--acc);
  box-shadow: 0 0 0 3px rgba(111, 182, 217, 0.14);
}

.status__row.is-down .status__dot {
  background: var(--alert);
  box-shadow: 0 0 0 3px rgba(224, 122, 106, 0.14);
}

.status__ms {
  color: var(--mut);
}

.status__row.is-down .status__ms {
  color: var(--alert);
}

/* ── Error pages ─────────────────────────────────────────────────────────── */

.hero__name--small {
  font-size: clamp(1.9rem, 6.5vw, 2.6rem);
}

.miss {
  display: inline-block;
  margin: 22px 0 0;
  padding: 7px 12px;
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  background: var(--panel);
  font-family: var(--mono);
  font-size: 12.5px;
  color: var(--mut);
  overflow-wrap: anywhere;
}

.foot a + a {
  margin-left: 0;
}

/* ══════════════════════════════════════════════════════════════════════════
   AMBIENT — tune here
   ══════════════════════════════════════════════════════════════════════════
   Two colour fields drifting behind the page plus moving grain. Set below the
   threshold of notice on purpose: you should catch it by looking away and
   back, not by looking at it.

   Every value is a variable so you can drag it around in devtools before
   committing. OLED and IPS render this very differently — trust your monitor
   over these numbers.

   --amb-opacity   0.20  screen blending on near-black eats a lot; this is
                         roughly as faint as 0.12 was before the change
   --amb-blur      90px  gradients already have soft falloff, so less is needed
   --amb-grain     0.03  0.06 is clearly textured
   --amb-cycle-a   60s   three mismatched cycles so the pattern never repeats
   --amb-cycle-b   80s
   --amb-cycle-c   100s
   --amb-fade      2.5s  how long a track change takes to bleed across
   ────────────────────────────────────────────────────────────────────────── */

/*
   Registered so the browser knows these are colours and can interpolate them.
   An unregistered custom property inside a gradient is just a string swap, so
   a track change repaints instantly no matter what transition you write. With
   @property the same change crossfades.

   Chrome/Edge 85+, Safari 16.4+, Firefox 128+. Anywhere older simply snaps,
   which is what it did before, so nothing breaks.
*/
@property --amb-a {
  syntax: '<color>';
  inherits: true;
  initial-value: #2f6f8e;
}
@property --amb-b {
  syntax: '<color>';
  inherits: true;
  initial-value: #3f4a96;
}
@property --amb-c {
  syntax: '<color>';
  inherits: true;
  initial-value: #2c7f7a;
}
@property --np-accent {
  syntax: '<color>';
  inherits: true;
  initial-value: #6fb6d9;
}

:root {
  --amb-fade: 2.5s;
  /* The transition lives here because this is the element JS writes to. */
  transition: --amb-a var(--amb-fade) ease, --amb-b var(--amb-fade) ease,
    --amb-c var(--amb-fade) ease;

  --amb-opacity: 0.2;
  --amb-blur: 90px;
  --amb-grain: 0.03;
  --amb-cycle-a: 60s;
  --amb-cycle-b: 80s;
  --amb-cycle-c: 100s;

  /* Overwritten from the album art by now-playing.js when it can read one.
     Three related hues rather than two: more surfaces to cross, more mixtures. */
  --amb-a: #2f6f8e;
  --amb-b: #3f4a96;
  --amb-c: #2c7f7a;
}

.amb {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
  contain: strict;
}

/*
   Radial gradients rather than solid discs. A flat circle with blur still has
   an edge you can find; a gradient with a transparent falloff has nowhere the
   colour stops, so it dissolves into the page instead of sitting on it.

   mix-blend-mode: screen means overlaps actually mix — where two fields cross
   you get a third colour neither of them is. Combined with three fields on
   different cycles, the palette keeps recombining without any colour property
   being animated. All the change comes from movement.
*/
.amb__a,
.amb__b,
.amb__c {
  position: absolute;
  display: block;
  mix-blend-mode: screen;
  filter: blur(var(--amb-blur));
  opacity: var(--amb-opacity);
  transition: opacity 1.2s ease;
  will-change: transform;
}

.amb__a {
  top: -30%;
  left: -22%;
  width: 80%;
  height: 135%;
  background: radial-gradient(circle at 50% 50%, var(--amb-a) 0%, transparent 68%);
}

.amb__b {
  top: -38%;
  right: -26%;
  width: 72%;
  height: 145%;
  background: radial-gradient(circle at 50% 50%, var(--amb-b) 0%, transparent 66%);
}

/* Smaller and lower. Gives the two big fields something to cross. */
.amb__c {
  bottom: -45%;
  left: 22%;
  width: 62%;
  height: 110%;
  background: radial-gradient(circle at 50% 50%, var(--amb-c) 0%, transparent 70%);
  opacity: calc(var(--amb-opacity) * 0.8);
}

.amb__grain {
  position: absolute;
  inset: -160px;
  display: block;
  opacity: var(--amb-grain);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* Content sits above the fields. */
.sheet {
  position: relative;
  z-index: 1;
}

@media (prefers-reduced-motion: no-preference) {
  .amb__a {
    animation: amb-drift-a var(--amb-cycle-a) ease-in-out infinite alternate;
  }
  .amb__b {
    animation: amb-drift-b var(--amb-cycle-b) ease-in-out infinite alternate;
  }
  .amb__c {
    animation: amb-drift-c var(--amb-cycle-c) ease-in-out infinite alternate;
  }
  .amb__grain {
    animation: amb-grain 8s steps(6) infinite;
  }

  /* Transform and opacity only, so this stays on the compositor and off the
     CPU. Nothing here triggers layout or paint. */
  @keyframes amb-drift-a {
    from { transform: translate3d(0, 0, 0) scale(1); }
    to   { transform: translate3d(7%, 4%, 0) scale(1.15); }
  }
  @keyframes amb-drift-b {
    from { transform: translate3d(0, 0, 0) scale(1.12); }
    to   { transform: translate3d(-6%, -5%, 0) scale(1); }
  }
  @keyframes amb-drift-c {
    from { transform: translate3d(-6%, 3%, 0) scale(1.05); }
    to   { transform: translate3d(8%, -7%, 0) scale(1.22); }
  }
  @keyframes amb-grain {
    0%   { transform: translate(0, 0); }
    20%  { transform: translate(-40px, 20px); }
    40%  { transform: translate(30px, -30px); }
    60%  { transform: translate(-20px, -20px); }
    80%  { transform: translate(40px, 30px); }
    100% { transform: translate(0, 0); }
  }
}

/* ── Frosted panels ──────────────────────────────────────────────────────── */
/*
   Semi-transparent so the fields show through. Without this the ambient layer
   looks like wallpaper behind unrelated content rather than light the whole
   page is sitting in.
*/

.np__card,
.link,
.plate,
.drop,
.result,
.miss {
  background-color: rgba(26, 28, 31, 0.72);
  backdrop-filter: blur(10px);
}

@supports not (backdrop-filter: blur(10px)) {
  .np__card,
  .link,
  .plate,
  .drop,
  .result,
  .miss {
    background-color: var(--panel);
  }
}

/* ── Hero rule ───────────────────────────────────────────────────────────── */

.hero__rule {
  width: 44px;
  height: 2px;
  margin-top: 18px;
  border-radius: 1px;
  background: var(--acc);
  opacity: 0.85;
}

.hero__name {
  font-size: clamp(2.6rem, 11vw, 4rem);
  letter-spacing: -0.035em;
  line-height: 0.98;
}

/* ── Spec groups ─────────────────────────────────────────────────────────── */

.bom tbody tr.grp td {
  padding: 26px 0 6px;
  border-bottom: 0;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--mut);
}

.bom tbody tr.grp:first-child td {
  padding-top: 4px;
}

.bom tbody tr.grp td span {
  display: inline-block;
  padding-bottom: 5px;
  border-bottom: 1px solid var(--line-2);
}

/* Group headers are structure, not data — no hover treatment. */
.bom tbody tr.grp:hover {
  background: none;
}

.bom tbody tr.grp td:first-child::before {
  display: none;
}

@media (max-width: 620px) {
  .bom tbody tr.grp {
    display: block;
    padding: 0;
    border-bottom: 0;
  }
  .bom tbody tr.grp td {
    padding: 22px 0 8px;
  }
}
