/* ── THE SONIC WAVEFORM ──────────────────────────────────────────────────────
   src/views/sonic-waveform.js + public/js/sonic-waveform.js. Arian's music
   visualizer (sonic-waveform.tsx), ported: a full-screen black band, the
   lines drawn live on a canvas behind everything, a shade rising from the
   foot so the words stand clear, and the words centred over it — each
   rising in turn the first time the band comes into view.

   Held to the site's rules where the component broke them: the badge is
   painted, not frosted (glass is for controls), and the button is the site's
   own, with no shadow under it.

   The component carried a line or two; this band carries two paragraphs, so
   the words stand on a pool of the band's own black (painted, never a shadow
   on a letter) and the text under the title is a shade lighter than the
   component's grey.

   Its teal is the site's main blue now — the YOUNIVERSE ramp, electric into
   cyan: on the waves, on the whole title, and on the pill so it does not
   stand apart. */
/* The band paints the page's black (--black), not pure black: the brand
   has no pure black but text, and the Domains below it stand on the same
   ground with no seam — Arian: "underneath vibranatix make the background
   all the same black and no separation". */
.sonic { position: relative; background: var(--black); color: #fff; }
/* The screen: a screen tall, and taller when its words need it: nothing is
   ever cut. */
.sonic__pin {
  position: relative; isolation: isolate; overflow: hidden;
  display: grid; place-items: center; grid-template-columns: minmax(0, 1fr);
  min-height: max(100svh, 32rem);
}

/* THE SCROLL PLAYS IT. Arian, 2026-09-26: "we need its animation to stop and
   require a few scrolls to animate the wave". With the script the band is a
   runway two stops long under its screen, and the screen stands still in it
   while the page scrolls on; the waves move only as it does (sonic-
   waveform.js). The stops are marks the page rests on (home.css on a phone,
   smooth-scroll.js with a wheel), a bar's height lower, since the page rests
   a mark just under the bar. For anyone who asked for less motion it is one
   screen with the waves standing still. */
.sonic__stop { display: none; }
@media (prefers-reduced-motion: no-preference) {
  /* The runway is room under the screen inside the band (a sticky screen
     cannot travel into its band's padding). */
  .js .sonic { --sonic-step: 45svh; }
  .js .sonic::after { content: ''; display: block; height: calc(2 * var(--sonic-step)); }
  .js .sonic__pin { position: sticky; top: 0; }
  .js .sonic__stop {
    display: block; position: absolute; left: 0; width: 1px; height: 1px; pointer-events: none;
    top: calc(var(--nav-h) + var(--s, 1) * var(--sonic-step));
  }
}
.sonic__canvas { position: absolute; inset: 0; z-index: 0; display: block; width: 100%; height: 100%; background: var(--black); }
/* The component's bg-gradient-to-t from-black via-black/30 to-transparent. */
.sonic__shade {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(to top, var(--black) 0%, rgba(4, 5, 7, .3) 50%, transparent 100%);
}

/* The column is the band's width and no wider, whatever word is in it. */
.sonic__inner {
  position: relative; z-index: 2;
  display: grid; justify-items: center; grid-template-columns: minmax(0, 1fr);
  width: 100%; min-width: 0;
  padding: clamp(4rem, 10svh, 7rem) var(--gutter);
  text-align: center;
}
/* The pool: the waves still pass behind the words, dimmed, and run bright on
   either side of them. */
.sonic__inner::before {
  content: ''; position: absolute; inset: -2rem -6rem; z-index: -1; pointer-events: none;
  background: radial-gradient(closest-side, rgba(4, 5, 7, .72) 70%, rgba(4, 5, 7, 0));
}
/* The component's pill (a tenth of its colour inside, a fifth on the edge),
   in the ramp's blue. */
.sonic__badge {
  display: inline-flex; align-items: center; gap: .5rem;
  margin: 0 0 1.5rem; padding: .375rem 1rem;
  border: 1px solid rgba(56, 225, 255, .2); border-radius: 999px;
  background: rgba(58, 102, 255, .1);
  font-family: var(--font-ui); font-size: .875rem; font-weight: 500; line-height: 1.4;
  color: #e5e7eb;
}
.sonic__icon { flex: none; width: 1rem; height: 1rem; }
/* rhythm.css sizes every h2 (0,3,1, and it loads last); this one is sized
   here, so it is written one class stronger. */
.sonic.env .sonic__inner .sonic__title {
  margin: 0 0 1.5rem;
  font-family: var(--font-display); font-weight: 300; text-transform: uppercase;
  /* TECHNOLOGY™ set this wide fits a phone's width; the script makes any
     longer word fit too. */
  font-size: clamp(1.5rem, 8.3vw, 4.5rem); line-height: 1; letter-spacing: .06em;
  color: var(--ramp-blue-b);
}
/* The whole title in the site's main blue — the YOUNIVERSE ramp exactly (see
   components.css), electric into cyan — as ONE gradient that runs through it
   in reading order: the first line takes the start of the ramp and the second
   carries on to the end, instead of each word or line starting it again. An
   inline span's background is laid out as if its lines stood end to end and
   then cut (box-decoration-break: slice), which is what carries it across. */
@supports ((background-clip: text) or (-webkit-background-clip: text)) {
  .sonic__title .sonic__ramp {
    background-image: linear-gradient(90deg, var(--ramp-blue-a) 0%, var(--ramp-blue-b) 100%);
    -webkit-box-decoration-break: slice; box-decoration-break: slice;
    -webkit-background-clip: text; background-clip: text;
    -webkit-text-fill-color: transparent; color: transparent;
  }
}
/* The ™, much smaller and raised to the top of the capitals, still inside the
   run, so it takes the ramp's colour where it stands: the cyan end. */
.sonic__title .sonic__tm { font-size: .3em; vertical-align: text-top; letter-spacing: 0; }
.sonic .sonic__body {
  max-width: 42rem; margin: 0 auto 2.5rem;
  font-size: 1.125rem; line-height: 1.6; color: #d1d5db;
}
.sonic .sonic__body p { margin: 0; }
.sonic .sonic__body p + p { margin-top: 1em; }
/* Nothing follows the last piece, so it leaves no gap under itself. */
.sonic__inner > :last-child { margin-bottom: 0; }
.sonic__cta { display: flex; justify-content: center; }

/* Rising in turn, as the component's pieces did (0.5s, then every 0.2s,
   0.8s each), the first time the band is seen. */
.js .sonic__inner > * { opacity: 0; transform: translateY(20px); }
.js .sonic.is-heard .sonic__inner > * {
  opacity: 1; transform: none;
  transition: opacity .8s ease-in-out, transform .8s ease-in-out;
  transition-delay: calc(var(--i, 0) * .2s + .5s);
}
@media (prefers-reduced-motion: reduce) {
  .js .sonic__inner > *, .js .sonic.is-heard .sonic__inner > * { opacity: 1; transform: none; transition: none; }
}

/* ── THE PICTURE BESIDE THE WORDS ─────────────────────────────────────────
   Arian, 2026-09-26, with a drawing of the band: the headphones on the
   right, standing over the sound wave, nearly the screen's height, and the
   words on the left, set flush left. The waves still run behind everything,
   as they were. On a phone the picture stands above the words. */
/* Arian, the same day: "the headphones are way too big on the screen", then
   "can still be a little smaller" — so about a quarter of the width, never
   over 440px or half the screen's height, centred in the right half. */
.sonic__art { --sonic-art: min(27vw, 440px, 50svh); position: absolute; z-index: 1; top: 50%; right: calc(25vw - var(--sonic-art) / 2); width: var(--sonic-art); transform: translateY(-50%); pointer-events: none; }
.sonic__art picture, .sonic__art img { display: block; width: 100%; height: auto; max-width: none; }
.sonic--art .sonic__inner { justify-self: start; justify-items: start; width: min(50vw, 46rem); text-align: left; padding-right: 0; }
.sonic--art .sonic__inner::before { inset: -2rem -3rem -2rem -8rem; }
.sonic--art .sonic .sonic__body, .sonic.sonic--art .sonic__body { margin-inline: 0; }
.sonic--art .sonic__cta { justify-content: flex-start; }
/* The picture comes up with the words, the first time the band is seen. */
.js .sonic--art .sonic__art { opacity: 0; transition: opacity 1.2s ease-out .3s; }
.js .sonic--art.is-heard .sonic__art { opacity: 1; }
@media (max-width: 760px) {
  .sonic--art .sonic__pin { align-content: center; }
  .sonic__art { position: relative; top: auto; right: auto; justify-self: center; width: min(36vw, 10rem); margin: calc(var(--nav-h) + 1.25rem) auto -.25rem; transform: none; }
  .sonic--art .sonic__inner { width: 100%; padding: 1rem var(--gutter) 2.5rem; }
}
@media (prefers-reduced-motion: reduce) {
  .js .sonic--art .sonic__art { opacity: 1; transition: none; }
}
