/* ==========================================================================
   highpass. — artist management for house music
   One screen, the seeder.gg way: paper, the drifting grid, the display type.
   It says what it is, and the name
   does the rest — set across the full column, standing on a 20 Hz – 20 kHz
   axis. The bubble menu sits in the top corner; its two pills open the
   two other pages by zooming into the name: into the dot of the i until its
   black is the page (who we are), into the full stop until its orange is
   (contact).

   Frames: Desktop wide 1920 · Desktop narrow 1280 · iPad 834 · iPhone 402
   ========================================================================== */

/* ==========================================================================
   Fonts — the two latin files, served locally. Both are variable on weight,
   so one file covers 400–700.
   ========================================================================== */
@font-face {
  font-family: "Instrument Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/instrument-sans-latin.woff2") format("woff2");
}
@font-face {
  font-family: "Instrument Sans Fallback";
  src: local("Arial");
  ascent-override: 94.42%;
  descent-override: 24.33%;
  line-gap-override: 0.00%;
  size-adjust: 102.74%;
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/inter-latin.woff2") format("woff2");
}
@font-face {
  font-family: "Inter Fallback";
  src: local("Arial");
  ascent-override: 90.44%;
  descent-override: 22.52%;
  line-gap-override: 0.00%;
  size-adjust: 107.12%;
}
/* ==========================================================================
   Design tokens
   ========================================================================== */
:root {
  /* Viewport width minus the scrollbar — pinned by the script; 100vw without it */
  --vw: 100vw;

  /* Colours */
  --color-bg: #ffffff;
  --color-ink: #0e0e10;
  --color-muted: #6b6b70;
  --color-accent: #f26a0f;          /* the bright accent: the full stop */
  --accent-rgb: 242, 106, 15;
  --deep-rgb: 154, 59, 0;
  --color-white: #ffffff;
  --color-grid: rgba(14, 14, 16, 0.07);

  /* Type */
  --font-display: "Instrument Sans", "Instrument Sans Fallback", ui-sans-serif, system-ui, sans-serif;
  --font-body: "Inter", "Inter Fallback", ui-sans-serif, system-ui, sans-serif;

  /* Desktop sizes: 1280 → 1920 (held below 1280 and above 1920) */
  --fs-title: clamp(48px, (var(--vw) * 0.01875) + 24px, 60px);
  --fs-line: 19px;
  --fs-btn: 16px;
  --fs-axis: 12px;
  --fs-foot: 14px;

  /* Spacing. The column is the poster's measure: the viewport less its
     margins, capped — and on a short landscape window held to what lets the
     name, which is set to the column, still fit the one screen. */
  --vh: 100vh;
  --column: min(1680px, var(--vw) - 160px, max(960px, (var(--vh) - 320px) * 3.2));
  --page-top: 48px;
  --page-bottom: 40px;
  --top-gap: 48px;                   /* the least air between the top row and the name */
  --bubble-h: 56px;                  /* the menu toggle */
  --shadow-bubble: 0 4px 16px rgba(0, 0, 0, 0.12);
  --grid-pitch: 96px;

  /* The name fills the column: the ink of "highpass." is this many ems wide
     at the tracking below (measured), so the size is the column over that. */
  --mark-em: 4.058;
  --mark-track: -0.055em;
  --fs-mark: calc(var(--column) / var(--mark-em));

  /* Radii + curves */
  --radius-pill: 999px;
  --ease-settle: cubic-bezier(0.22, 1, 0.36, 1);
}

@supports (height: 100svh) { :root { --vh: 100svh; } }

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

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

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-ink);
  font-family: var(--font-body);
  line-height: normal;
  -webkit-font-smoothing: antialiased;
  overflow: hidden;                   /* older Safari */
  overflow: clip;
}

h1, h2, p { margin: 0; }
ul { margin: 0; padding: 0; list-style: none; }
a { color: inherit; text-decoration: none; }

.u-display { font-family: var(--font-display); font-weight: 700; }

/* Read, not seen: the whole sentence for a screen reader where the script has split the visible one into words. */
.u-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  -webkit-user-select: none;
  user-select: none;
}

::selection { background: rgba(var(--accent-rgb), 0.24); }
.view--who ::selection { background: rgba(255, 255, 255, 0.24); }
.view--contact ::selection { background: var(--color-ink); color: var(--color-white); }

/* ==========================================================================
   Page — one screen tall: the top row at the top, the name at the bottom
   ========================================================================== */
.page {
  position: relative;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100svh;
  overflow: hidden;
  padding: var(--page-top) 0 var(--page-bottom);
  background: var(--color-bg);
}

/* Arrival. Everything comes in the way the menu's pills do: words rise into
   place as they fade up, one after the other; the buttons pop from nothing
   with a back-out overshoot and their labels rise into them just after. The
   paper stays put. Each plays once, when the page loads. */
@keyframes rise-in { from { opacity: 0; transform: translateY(24px); } }
@keyframes pop-in { from { transform: scale(0); } }
@keyframes fade-in { from { opacity: 0; } }

.poster__title,
.mark,
.axis,
.footer > * {
  animation: rise-in 500ms cubic-bezier(0.215, 0.61, 0.355, 1) backwards;
  animation-delay: var(--enter, 0ms);
}
.poster__title { --enter: 60ms; }
.mark { --enter: 260ms; animation-duration: 700ms; }
.axis { --enter: 480ms; }
.footer > * { --enter: 580ms; }
.footer > :last-child { --enter: 660ms; }

.nav__toggle {
  animation: pop-in 500ms cubic-bezier(0.34, 1.45, 0.64, 1) backwards;
  animation-delay: 180ms;
}

@media (prefers-reduced-motion: reduce) {
  .poster__title, .mark, .axis, .footer > *, .nav__toggle { animation: none; }
}

/* ==========================================================================
   Backdrop — the paper behind the page: 1px ink lines at 7%, one square
   pitch, drifting one square every minute.
   Drawn one pitch larger on the top and left so the drift never shows an edge.
   ========================================================================== */
.backdrop {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}

.backdrop__grid {
  position: absolute;
  top: calc(1px - var(--grid-pitch));
  left: calc(1px - var(--grid-pitch));
  right: 0;
  bottom: 0;
  background-image:
    linear-gradient(to right, transparent calc(100% - 1px), var(--color-grid) calc(100% - 1px)),
    linear-gradient(to bottom, transparent calc(100% - 1px), var(--color-grid) calc(100% - 1px));
  background-size: var(--grid-pitch) 100%, 100% var(--grid-pitch);
  background-repeat: repeat;
  animation: grid-drift 60s linear infinite;
}
@keyframes grid-drift {
  to { transform: translate(var(--grid-pitch), var(--grid-pitch)); }   /* one square: the loop is seamless */
}
@media (prefers-reduced-motion: reduce) { .backdrop__grid { animation: none; } }

.column {
  position: relative;
  z-index: 1;
  width: var(--column);
  margin-right: auto;
  margin-left: auto;
}

/* ==========================================================================
   The poster
   ========================================================================== */
.poster {
  display: flex;
  flex: 1;
  flex-direction: column;
}

.poster__top {
  position: relative;
  z-index: 20;                      /* the menu layer lives in here */
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 32px;
}

/* What it is. */
.poster__title {
  font-size: var(--fs-title);
  line-height: 1.04;
  letter-spacing: -0.03em;
  color: var(--color-ink);
  white-space: nowrap;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 18px 24px;              /* 36 each side less the 8 + 16 arrow: same width */
  border: 0;
  border-radius: var(--radius-pill);
  font-family: var(--font-body);
  font-size: var(--fs-btn);
  font-weight: 600;
  line-height: 19px;
  white-space: nowrap;
}

/* ==========================================================================
   The name — set across the full column, standing on the axis every EQ
   draws: 20 Hz to 20 kHz, log-spaced.
   ========================================================================== */
.poster__mark {
  position: relative;
  margin-top: auto;
  padding-top: var(--top-gap);
}

.mark {
  margin: 0 0 0 -0.047em;            /* the h's side bearing: the stem sits on the column edge */
  font-size: var(--fs-mark);
  line-height: 1;
  letter-spacing: var(--mark-track);
  color: var(--color-ink);
  white-space: nowrap;
  -webkit-user-select: none;
  user-select: none;
}
.mark__dot { color: var(--color-accent); }

/* The name, heard through its own filter. "high" stands over the low end of
   the axis, so it is turned down and "pass" comes through — until Who we
   are is pressed: then the filter opens, and the zoom goes in through the i
   at full ink. It closes again once the poster is back. */
.mark__high { opacity: 0.45; transition: opacity 320ms ease; }
.mark.is-open .mark__high { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .mark__high { transition: none; } }

/* The two squares are doors: the dot of the i goes to Who we are, the full
   stop to Contact — the same pages the menu opens, without the menu. Each is
   a link the script lays over its square (it knows where the ink sits), a
   little larger than the square on small screens so a thumb can find it.
   Under the pointer the square comes up to full strength — on the i that is
   the dot alone, the rest of "high" stays turned down — and says where it
   leads: a question mark in the dot, an envelope in the full stop, drawn in
   outline in the middle of the square. Nothing moves or grows. */
.spot {
  position: absolute;
  display: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.spot.is-placed { display: block; }
.spot::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--w, 0px);
  height: var(--h, 0px);
  margin: calc(var(--h, 0px) / -2) 0 0 calc(var(--w, 0px) / -2);
  background: var(--spot);
  opacity: 0;
  transition: opacity 160ms ease;
}
.spot:focus-visible::before { opacity: 1; }

.spot__icon {
  position: absolute;
  top: 50%;
  left: 50%;
  width: calc(var(--w, 0px) * 0.6);
  height: calc(var(--h, 0px) * 0.6);
  transform: translate(-50%, -50%);
  fill: none;
  stroke: var(--spot-ink);
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0;
  transition: opacity 160ms ease;
  pointer-events: none;
}
.spot__icon-dot { fill: var(--spot-ink); stroke: none; }
.spot:focus-visible .spot__icon { opacity: 1; }
@media (hover: hover) and (pointer: fine) {           /* a thumb has no hover: nothing stays lit after a tap */
  .spot:hover::before,
  .spot:hover .spot__icon { opacity: 1; }
}
.spot:focus-visible { outline: none; }               /* the ring goes round the square, not the (larger) touch box */
.spot:focus-visible::before { outline: 2px solid var(--color-ink); outline-offset: 6px; }
.spot--who { --spot: var(--color-ink); --spot-ink: var(--color-white); }
.spot--contact { --spot: var(--color-accent); --spot-ink: var(--color-ink); }
@media (prefers-reduced-motion: reduce) { .spot::before, .spot__icon { transition: none; } }

.axis {
  position: relative;
  height: 40px;
  margin-top: calc(var(--fs-mark) * 0.14);        /* clear of the g and the p, then a little air */
  font-family: var(--font-body);
  font-size: var(--fs-axis);
  font-weight: 500;
  letter-spacing: 0.02em;
  line-height: 14px;
  color: var(--color-muted);
}
.axis::before {                      /* the axis itself */
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: rgba(14, 14, 16, 0.28);
}
.axis i {
  position: absolute;
  top: 0;
  left: calc(var(--at) * 100%);
  width: 1px;
  height: 6px;
  background: rgba(14, 14, 16, 0.28);
}
.axis i:last-of-type { margin-left: -1px; }      /* the last tick stays inside the column */
.axis i.is-major { height: 11px; background: rgba(14, 14, 16, 0.6); }
.axis span {
  position: absolute;
  top: 19px;
  left: calc(var(--at) * 100%);
  transform: translateX(-50%);
  white-space: nowrap;
}
.axis span.is-start { transform: none; }
.axis span.is-end { transform: translateX(-100%); }

/* ==========================================================================
   Footer — the note on the left, the address on the right
   ========================================================================== */
.footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  margin-top: 20px;
  font-family: var(--font-body);
  font-size: var(--fs-foot);
  line-height: 17px;
  color: var(--color-muted);
  white-space: nowrap;
}
.footer__link { transition: color 200ms ease; }
.footer__link:hover { color: var(--color-ink); }
.footer__link:focus-visible { outline: 2px solid var(--color-ink); outline-offset: 3px; border-radius: 4px; }

/* ==========================================================================
   Bubble menu — seeder's: a round toggle whose two lines cross into an X,
   and two pills that pop out beside it one after the other, each tilted its
   own way. All of it runs on the checkbox: :checked opens it, so nothing
   here needs a script; the script only adds Escape and click-outside.
   ========================================================================== */
.nav {
  position: relative;
  display: flex;
  flex: none;
  align-items: center;
  height: var(--bubble-h);
}

.nav__toggle {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  gap: 6px;
  order: 2;
  width: var(--bubble-h);
  height: var(--bubble-h);
  border-radius: 50%;
  background: var(--color-white);
  box-shadow: var(--shadow-bubble);
  cursor: pointer;
}

/* The checkbox sits exactly over the bubble, so the menu opens and closes
   with no script. */
.nav__toggle-input {
  order: 3;
  position: relative;
  z-index: 1;
  flex-shrink: 0;
  width: var(--bubble-h);
  height: var(--bubble-h);
  margin: 0 0 0 calc(-1 * var(--bubble-h));
  padding: 0;
  border: 0;
  border-radius: 50%;
  opacity: 0;
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
}

.nav:has(.nav__toggle-input:focus-visible) .nav__toggle {
  outline: 2px solid var(--color-ink);
  outline-offset: 3px;
}

.nav__toggle-bar {
  display: block;
  width: 26px;
  height: 2px;
  border-radius: 2px;
  background: var(--color-ink);
  transform-origin: center;
  transition: transform 300ms ease;
}
.nav__toggle-input:checked ~ .nav__toggle .nav__toggle-bar:nth-child(1) { transform: translateY(4px) rotate(45deg); }
.nav__toggle-input:checked ~ .nav__toggle .nav__toggle-bar:nth-child(2) { transform: translateY(-4px) rotate(-45deg); }

/* The pills: a row to the toggle's left on desktop, a stack under it on
   smaller screens — nearest pill first. */
.menu {
  position: absolute;
  top: 50%;
  right: calc(var(--bubble-h) + 12px);
  z-index: 5;
  transform: translateY(-50%);
  visibility: hidden;
  transition: visibility 0s linear 220ms;
}
.nav__toggle-input:checked ~ .menu { visibility: visible; transition-delay: 0s; }

.menu__list {
  display: flex;
  align-items: center;
  gap: 12px;
}

/* Each pill pops from nothing with a back-out overshoot, starting from the
   one next to the button (0 / 160ms), and folds back in 200ms. */
.menu__col {
  display: flex;
  transform: scale(0);
  transform-origin: 50% 50%;
  transition: transform 200ms cubic-bezier(0.55, 0.055, 0.675, 0.19);
  will-change: transform;
}
.menu__col:nth-child(2) { --pop-delay: 0ms; }
.menu__col:nth-child(1) { --pop-delay: 160ms; }
.nav__toggle-input:checked ~ .menu .menu__col {
  transform: none;
  transition: transform 500ms cubic-bezier(0.34, 1.45, 0.64, 1) var(--pop-delay);
}

.menu__pill {
  display: inline-flex;
  align-items: center;
  padding: 18px 24px;
  border-radius: var(--radius-pill);
  background: var(--color-white);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.10);
  font-family: var(--font-body);
  font-size: var(--fs-btn);
  font-weight: 600;
  line-height: 19px;
  color: var(--color-ink);
  white-space: nowrap;
  --rot: 0deg;
}
.menu__pill.glow-btn {
  transform: rotate(var(--rot));
  --glow-spot: rgba(var(--accent-rgb), 0.16);
  --glow-rim: rgba(var(--accent-rgb), 0.85);
  --glow-shadow: 0 4px 14px rgba(0, 0, 0, 0.10), 0 12px 28px -12px rgba(var(--accent-rgb), 0.45);
}
.menu__pill.glow-btn:hover { transform: rotate(var(--rot)) translateY(-1px); }
.menu__pill.glow-btn:active { transform: rotate(var(--rot)) scale(0.985); }

/* The label rises into the pill just after it lands. */
.menu__label {
  display: inline-block;
  transform: translateY(24px);
  opacity: 0;
  transition: transform 200ms cubic-bezier(0.55, 0.055, 0.675, 0.19), opacity 200ms cubic-bezier(0.55, 0.055, 0.675, 0.19);
  will-change: transform, opacity;
}
.nav__toggle-input:checked ~ .menu .menu__label {
  transform: none;
  opacity: 1;
  transition:
    transform 500ms cubic-bezier(0.215, 0.61, 0.355, 1) calc(var(--pop-delay) + 50ms),
    opacity 500ms cubic-bezier(0.215, 0.61, 0.355, 1) calc(var(--pop-delay) + 50ms);
}

@media (min-width: 1025px) {
  .menu__col:nth-child(1) .menu__pill { --rot: -8deg; }
  .menu__col:nth-child(2) .menu__pill { --rot: 8deg; }
}

/* Tablet and phone: a stack under the toggle, right-aligned, top pill first. */
@media (max-width: 1024px) {
  .menu { top: calc(100% + 12px); right: 0; transform: none; }
  .menu__list { flex-direction: column; align-items: flex-end; gap: 10px; }
  .menu__col:nth-child(1) { --pop-delay: 0ms; }
  .menu__col:nth-child(2) { --pop-delay: 160ms; }
}

@media (prefers-reduced-motion: reduce) {
  .menu, .menu__col, .menu__pill, .menu__label, .nav__toggle-bar { transition: none !important; }
}

/* ==========================================================================
   The two other pages. Each is a full-screen <dialog> whose ground is the
   colour of the piece of the name it is reached through: the ink of the
   i's dot, the orange of the full stop. The script zooms the poster into
   that piece until it fills the window, opens the page over it, and zooms
   back out on the way home. They open from their address (#who, #contact),
   so the back button closes them and the links can be shared; without the
   script the same addresses show them through :target, with no zoom.
   ========================================================================== */
.view {
  display: none;
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  overflow: auto;
  overscroll-behavior: contain;
}
.view[open] { display: block; }
.view:focus { outline: none; }            /* the page itself is never the control */
.view::backdrop { background: transparent; }
.view > .backdrop { position: fixed; }     /* the grid stays with the window when a short screen scrolls the page */
html:not(.js) .view:target { display: block; z-index: 50; }

.view--who {
  --view-ground: var(--color-ink);
  background: var(--view-ground);
  color: var(--color-white);
  --color-grid: rgba(255, 255, 255, 0.06);
  --view-soft: #a4a4a4;
  --view-focus: var(--color-white);
  --close-bg: var(--color-white);
  --close-fg: var(--color-ink);
}
.view--contact {
  --view-ground: var(--color-accent);
  background: var(--view-ground);
  color: var(--color-ink);
  --color-grid: rgba(14, 14, 16, 0.08);
  --view-soft: rgba(14, 14, 16, 0.8);
  --view-focus: var(--color-ink);
  --close-bg: var(--color-ink);
  --close-fg: var(--color-accent);
}

.view__inner {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  width: var(--column);
  min-height: 100%;
  margin: 0 auto;
  padding: var(--page-top) 0 var(--page-bottom);
}

.view__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: var(--bubble-h);
}
.view__mark { font-size: 28px; letter-spacing: -0.04em; white-space: nowrap; }
.view--who .view__mark-dot { color: var(--color-accent); }
.view--contact .view__mark-dot { color: var(--color-white); }

/* The close bubble: the toggle's X, in the page's own colours — white with
   an ink X on the black page, ink with an orange X on the orange one. */
.view__close {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  flex: none;
  gap: 6px;
  width: var(--bubble-h);
  height: var(--bubble-h);
  border-radius: 50%;
  background: var(--close-bg);
  box-shadow: var(--shadow-bubble);
  cursor: pointer;
  transition: transform 260ms var(--ease-settle);
}
.view__close:hover { transform: scale(1.06); }
.view__close:active { transform: scale(0.96); }
.view__close:focus-visible { outline: 2px solid var(--view-focus); outline-offset: 3px; }
.view__close span {
  display: block;
  width: 26px;
  height: 2px;
  border-radius: 2px;
  background: var(--close-fg);
}
.view__close span:nth-child(1) { transform: translateY(4px) rotate(45deg); }
.view__close span:nth-child(2) { transform: translateY(-4px) rotate(-45deg); }

.view__body {
  display: flex;
  flex: 1;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  padding: 48px 0 calc(var(--bubble-h) + 24px);     /* the top bar's height again underneath: optically centred */
}

.view__label {
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.12em;
  line-height: 16px;
  text-transform: uppercase;
  color: var(--view-soft);
}

/* Who we are, in three steps on one screen: who; the work; the artist. The
   first is the statement. The other two are one picture — an EQ on the
   poster's own 20 Hz – 20 kHz axis: the work stands in the low end, then a
   high-pass sweeps up the axis, the low end is cut, and what is left above
   the cutoff is the artist.

   Nothing scrolls. A wheel notch, a swipe, an arrow key, a square or the
   arrow moves one step (the script only sets data-step and draws the
   curve), and every change is played in time, word by word: the words of a
   step drift up, soften and are gone; the next ones rise out of a blur, one
   after the other. Without the script, and on screens too short to hold
   the picture, the page is a plain scroll that shows the filtered state. */
.view--who { color-scheme: dark; --ease-fluid: cubic-bezier(0.16, 1, 0.3, 1); --ease-away: cubic-bezier(0.5, 0, 0.75, 0); }
.view--who .view__inner { padding-bottom: 0; }
.view--who .view__top { position: relative; z-index: 3; }

.step {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  min-height: var(--vh);
  min-height: 100dvh;
  margin-top: calc(-1 * (var(--page-top) + var(--bubble-h)));          /* under the top bar: the step is the whole screen */
  padding: calc(var(--page-top) + var(--bubble-h) + 40px) 0 calc(var(--page-bottom) + var(--bubble-h) + 32px);
}
.view__statement {
  max-width: 21em;
  margin-top: 24px;
  font-size: clamp(30px, var(--column) / 28, 52px);
  line-height: 1.14;
  letter-spacing: -0.035em;
}
.view__lead { color: var(--color-accent); }
.view__copy {
  max-width: 30em;
  margin-top: 28px;
  font-size: clamp(19px, var(--column) / 56, 26px);
  font-weight: 500;
  line-height: 1.34;
  letter-spacing: -0.015em;
  color: var(--view-soft);
}

.eq { position: relative; }
.eq__stage {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 24px 0 calc(var(--page-bottom) + 24px);
}
.eq__plot { position: relative; display: flex; flex-direction: column; }
.eq__screen { position: relative; height: clamp(130px, 28vh, 280px); }
.eq__live { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }   /* the chord itself, as it sounds: drawn by the script from the audio, under the curve that is cutting it */
.eq__graph { position: absolute; inset: 0; width: 100%; height: 100%; overflow: hidden; }
.eq__line { fill: none; stroke: var(--color-white); stroke-width: 2.5px; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.eq__zero {                                   /* the 0 dB line */
  position: absolute;
  left: 0;
  right: 0;
  top: 28.57%;
  height: 1px;
  background: rgba(255, 255, 255, 0.1);
}
.eq__zero i {
  position: absolute;
  right: 0;
  bottom: 6px;
  font: 500 var(--fs-axis)/14px var(--font-body);
  font-style: normal;
  letter-spacing: 0.02em;
  color: #8a8a8e;
}
.eq__band {                                   /* the low end, before it is cut */
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 46.6%;
  border-right: 1px dashed rgba(var(--accent-rgb), 0.7);
  background: rgba(var(--accent-rgb), 0.22);
  /* Full at the axis, nothing at the top — an eased fall (no straight ramp, so no visible place where it ends),
     and as a mask, so the dashed cutoff line dissolves with it instead of stopping on an edge. */
  -webkit-mask-image: linear-gradient(to top, #000 0%, rgba(0, 0, 0, 0.9) 18%, rgba(0, 0, 0, 0.68) 38%, rgba(0, 0, 0, 0.4) 58%, rgba(0, 0, 0, 0.17) 76%, rgba(0, 0, 0, 0.04) 90%, transparent 100%);
  mask-image: linear-gradient(to top, #000 0%, rgba(0, 0, 0, 0.9) 18%, rgba(0, 0, 0, 0.68) 38%, rgba(0, 0, 0, 0.4) 58%, rgba(0, 0, 0, 0.17) 76%, rgba(0, 0, 0, 0.04) 90%, transparent 100%);
  opacity: 0;
  transform-origin: 0 50%;
}
.eq__node {                                   /* the filter's handle: the name's square */
  position: absolute;
  width: 14px;
  height: 14px;
  margin: -7px 0 0 -7px;
  background: var(--color-accent);
  transition: opacity 240ms ease;
}
.eq__node.is-off { opacity: 0; }

.axis--eq { margin-top: 0; color: #8a8a8e; }
.axis--eq::before, .axis--eq i { background: rgba(255, 255, 255, 0.26); }
.axis--eq i.is-major { background: rgba(255, 255, 255, 0.55); }

.eq__low { margin-top: 20px; }
.eq__low-title { opacity: 0.5; }                 /* cut: turned down, still read (large type; the small print below stays at 0.75) */
.eq__low-title { font-size: clamp(20px, var(--column) / 46, 30px); line-height: 1.15; letter-spacing: -0.025em; }
.eq__low-list {
  margin-top: 8px;
  font-family: var(--font-body);
  font-size: clamp(15px, var(--column) / 70, 19px);
  line-height: 1.5;
  color: var(--view-soft);
  opacity: 0.75;
}
.eq__pass {
  margin-top: 24px;
  font-size: clamp(26px, var(--column) / 13, 34px);
  line-height: 1.1;
  letter-spacing: -0.035em;
  text-wrap: balance;
}
.eq__cta { display: flex; margin-top: 32px; }
.eq .eq__cta .btn { margin-top: 0; }

/* The steps: the name's square, three times, and the arrow. */
.steps { display: none; }
.steps__dot, .steps__next {
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.steps__dot { position: relative; width: 26px; height: 44px; }
.steps__dot::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 10px;
  height: 10px;
  margin: -5px 0 0 -5px;
  background: rgba(255, 255, 255, 0.4);
  transition: background-color 500ms ease, transform 700ms var(--ease-fluid);
}
.steps__dot:hover::before { background: rgba(255, 255, 255, 0.6); }
.steps__dot[aria-current="step"]::before { background: var(--color-accent); transform: scale(1.2); }
.steps__next {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--bubble-h);
  height: var(--bubble-h);
  margin-left: 14px;
  border-radius: 50%;
  background: var(--close-bg);
  color: var(--close-fg);
  box-shadow: var(--shadow-bubble);
  transition: transform 260ms var(--ease-settle), opacity 400ms ease, visibility 0s;
}
.steps__next svg { transform: rotate(90deg); }
.steps__next:hover { transform: scale(1.06); }
.steps__next:active { transform: scale(0.96); }
.steps__next.is-done { opacity: 0; visibility: hidden; transform: scale(0.8); transition: transform 500ms var(--ease-fluid), opacity 400ms ease, visibility 0s 400ms; }
.steps__dot:focus-visible, .steps__next:focus-visible, .steps__sound:focus-visible { outline: 2px solid var(--view-focus); outline-offset: 3px; }

/* The speaker: this page stands on a held chord, so the way to turn it (and the buttons' notes) off is here, first in the row. */
.steps__sound {
  order: -1;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin-right: 6px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: rgba(255, 255, 255, 0.6);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: color 300ms ease;
}
.steps__sound[hidden] { display: none; }
.steps__sound:hover { color: var(--color-white); }
.steps__sound svg { fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.steps__sound[aria-pressed="true"] .steps__sound-off,
.steps__sound[aria-pressed="false"] .steps__sound-on { display: none; }
.steps__sound[aria-pressed="false"] { color: rgba(255, 255, 255, 0.45); }

/* Wide screens: the words stand inside the EQ — the work under the low end,
   the artist under everything that passes. */
@media (min-width: 1025px) {
  .eq__screen { height: auto; flex: 1; min-height: 240px; }
  .eq__low, .eq__pass { position: absolute; bottom: 68px; margin: 0; text-shadow: 0 0 3px rgba(14, 14, 16, 0.85), 0 0 14px rgba(14, 14, 16, 0.9); }   /* 40 of axis, then air; the ground's colour round the letters keeps them clear of the live spectrum behind */
  .eq__low { left: 0; width: 31%; }
  .eq__pass { left: 50%; right: 0; font-size: clamp(28px, var(--column) / 31, 50px); }
  .eq__cta { margin-top: 24px; }
}

/* Screens tall enough to hold the picture: the three steps lie on top of one
   another on the one screen, and data-step says which is showing. */
@media (min-width: 1025px) and (min-height: 600px), (max-width: 1024px) and (min-height: 620px) {
  html.js .view--who { overflow: hidden; touch-action: pan-x pinch-zoom; }
  html.js .view--who.is-pinched { touch-action: auto; }                        /* pinched in: a drag moves about the enlarged page; the script reads no swipes then */
  html.js .view--who .view__inner { height: 100%; }
  html.js .step, html.js .eq { position: absolute; top: 0; left: 0; width: 100%; height: 100%; min-height: 0; margin: 0; }
  html.js .view--who:not([data-step="0"]) .step,
  html.js .view--who:not([data-step="1"]):not([data-step="2"]) .eq { pointer-events: none; }
  html.js .eq__stage { height: 100%; padding: calc(var(--page-top) + var(--bubble-h) + 28px) 0 var(--page-bottom); }
  html.js .steps {                                                           /* (on the column, not the window: the column is what zooms) */
    position: absolute;
    right: 0;
    bottom: var(--page-bottom);
    z-index: 3;
    display: flex;
    align-items: center;
  }

  /* The page's own arrival gives way to the words' (below). */
  html.js .view--who[open] .view__label, html.js .view--who[open] .view__statement, html.js .view--who[open] .view__copy,
  html.js .view--who[open] .eq .btn, html.js .view--who[open] .eq .btn * { animation: none; }

  /* Words. Showing is the resting state; arriving is slow and one after the
     other, leaving is quick and nearly together. */
  html.js .view--who .w {
    display: inline-block;
    transition: transform 1200ms var(--ease-fluid), opacity 1000ms var(--ease-fluid), filter 1200ms var(--ease-fluid);
    transition-delay: calc(var(--flow-delay, 340ms) + var(--w) * 26ms);
  }
  html.js .view--who .eq__low-list .w { transition-delay: calc(var(--flow-delay, 340ms) + 160ms + var(--w) * 18ms); }
  html.js .view--who .view__copy .w { transition-delay: calc(var(--flow-delay, 340ms) + 380ms + var(--w) * 20ms); }
  html.js .view--who .eq__pass { --flow-delay: 900ms; }                         /* once the filter is most of the way up */

  /* …gone upwards: the first step's words after it, */
  html.js .view--who:not([data-step="0"]) .step .w {
    opacity: 0;
    transform: translateY(-0.6em);
    filter: blur(9px);
    transition-duration: 520ms, 420ms, 520ms;
    transition-timing-function: var(--ease-away);
    transition-delay: calc(var(--w) * 6ms);
  }
  /* …waiting below: the first step's before the page has begun, the work before its step, the artist before theirs. */
  html.js .view--who:not([data-step]) .step .w,
  html.js .view--who:not([data-step="1"]):not([data-step="2"]) .eq__low .w,
  html.js .view--who:not([data-step="2"]) .eq__pass .w {
    opacity: 0;
    transform: translateY(0.75em);
    filter: blur(9px);
    transition-duration: 520ms, 420ms, 520ms;
    transition-timing-function: var(--ease-away);
    transition-delay: calc(var(--w) * 6ms);
  }

  /* The picture itself comes up out of the same blur; the low end then fills from the left, and drains when it is cut. */
  html.js .view--who .eq__screen,
  html.js .view--who .axis--eq { transition: opacity 1100ms var(--ease-fluid) 260ms, transform 1300ms var(--ease-fluid) 260ms, filter 1100ms var(--ease-fluid) 260ms; }
  html.js .view--who:not([data-step="1"]):not([data-step="2"]) .eq__screen,
  html.js .view--who:not([data-step="1"]):not([data-step="2"]) .axis--eq {
    opacity: 0;
    transform: translateY(30px);
    filter: blur(7px);
    transition-duration: 460ms;
    transition-timing-function: var(--ease-away);
    transition-delay: 0ms;
  }
  html.js .view--who .eq__band { transform: scaleX(0); transition: transform 1500ms var(--ease-fluid) 620ms, opacity 1100ms ease; }
  html.js .view--who[data-step="1"] .eq__band { opacity: 1; transform: scaleX(1); }
  html.js .view--who[data-step="2"] .eq__band { opacity: 0; transform: scaleX(1); transition-delay: 0ms, 200ms; }

  html.js .view--who .eq__low-title, html.js .view--who .eq__low-list { opacity: 1; transition: opacity 1200ms var(--ease-fluid) 300ms; }

  html.js .view--who .eq__cta { transition: opacity 900ms var(--ease-fluid) 1500ms, transform 1100ms var(--ease-fluid) 1500ms, visibility 0s; }
  html.js .view--who:not([data-step="2"]) .eq__cta {
    opacity: 0;
    transform: translateY(16px);
    visibility: hidden;                         /* not there to be tabbed to until the filter has closed on the artist */
    transition: opacity 320ms var(--ease-away), transform 320ms var(--ease-away), visibility 0s 320ms;
  }

  /* A page someone arrived on, or a window resized across the line: the state is simply there. */
  html.js .view--who.is-instant .w, html.js .view--who.is-instant .eq__screen, html.js .view--who.is-instant .axis--eq,
  html.js .view--who.is-instant .eq__band, html.js .view--who.is-instant .eq__low-title, html.js .view--who.is-instant .eq__low-list,
  html.js .view--who.is-instant .eq__cta { transition: none !important; }
}
@media (min-width: 1025px) and (min-height: 600px) {
  html.js .eq__stage { justify-content: flex-end; }                          /* the picture stands on the bottom row, level with the steps */
  html.js .eq__plot { flex: 1; min-height: 0; max-height: max(560px, 66vh); }
  html.js .eq__cta .btn { min-height: var(--bubble-h); }
  html.js .view--who[data-step="2"] .eq__low-title { opacity: 0.5; }         /* cut: still there, turned down */
  html.js .view--who[data-step="2"] .eq__low-list { opacity: 0.75; }
}
@media (max-width: 1024px) and (min-height: 620px) {
  /* Narrow: the words stand under the EQ, in one and the same place — the work is there until it is cut, then the artist is. */
  html.js .eq__stage { padding-bottom: calc(var(--page-bottom) + var(--bubble-h) + 20px); }
  html.js .eq__plot { display: grid; grid-template-columns: minmax(0, 1fr); }
  html.js .eq__low, html.js .eq__pass { grid-area: 3 / 1; align-self: start; margin-top: 20px; }
  html.js .view--who[data-step="2"] .eq__low .w {
    opacity: 0;
    transform: translateY(-0.6em);
    filter: blur(9px);
    transition-duration: 520ms, 420ms, 520ms;
    transition-timing-function: var(--ease-away);
    transition-delay: calc(var(--w) * 6ms);
  }
}
@media (prefers-reduced-motion: reduce) {
  .eq__node, .steps__dot::before, .steps__next, .steps__next.is-done { transition: none; }
  .steps__next:hover { transform: none; }
  html.js .view--who .w, html.js .view--who .eq__screen, html.js .view--who .axis--eq, html.js .view--who .eq__band,
  html.js .view--who .eq__low-title, html.js .view--who .eq__low-list, html.js .view--who .eq__cta { transition: none !important; transform: none !important; filter: none !important; }
}

/* Contact: the two lines are the page — the address, the Instagram under
   it, both set to the column and one line-pitch apart. */
.view__line {
  font-family: var(--font-body);
  font-size: var(--fs-line);
  line-height: 1.55;
  color: var(--view-soft);
  transition: opacity 240ms ease;
}
.view__bigs {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  margin: 6px 0 0 -0.04em;
  font-size: min(132px, var(--column) / 8.6);       /* "team@highpass.cc" is 8.43em wide at this tracking */
}
/* Short desktop windows: the two lines give way so the page still fits the
   one screen (404 = everything on the page but the two lines). */
@media (min-width: 1025px) {
  .view__bigs { font-size: min(132px, var(--column) / 8.6, max(72px, (var(--vh) - 404px) / 2.2)); }
}
.view__big {
  position: relative;
  display: block;
  line-height: 1.1;
  letter-spacing: -0.04em;
  white-space: nowrap;
  transition: opacity 240ms ease;
}
.view__big:focus-visible { outline: 2px solid var(--view-focus); outline-offset: 6px; border-radius: 6px; }
/* The Instagram mark, where a superscript would sit after the handle. */
.view__glyph {
  position: absolute;
  top: 0.3em;
  left: calc(100% + 0.16em);
  width: clamp(20px, 0.3em, 44px);
  height: clamp(20px, 0.3em, 44px);
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.view__glyph-dot { fill: currentColor; stroke: none; }

/* Pointing at a line (or tabbing to it) turns everything else down and
   repeats the line up and down the window in outline: a strict column, one
   line-pitch apart, the other line keeping its own slot. The script lays
   the rows out (it knows where the line sits); this only draws them. */
.view__top, .view__label { transition: opacity 240ms ease; }
.view.is-echo .view__top,
.view.is-echo .view__label,
.view.is-echo .view__line,
.view.is-echo .btn,
.view.is-echo .view__big:not(.is-active) { opacity: 0.14; }

/* The same on Who we are, kept quiet: the name at the head of the statement does it, in its own orange. */
.view--who { --echo-ink: var(--color-accent); }
.view__copy, .steps { transition: opacity 240ms ease; }
.view--who.is-echo .view__copy,
.view--who.is-echo .steps { opacity: 0.14; }
html.js .view--who.is-echo .w,
html.js .view--who.is-echo-out .w { transition: opacity 240ms ease; transition-delay: 0ms; }   /* (not the words' own slow arrival) */
html.js .view--who.is-echo .view__statement .w { opacity: 0.14; }
html.js .view--who.is-echo .view__statement .view__lead .w { opacity: 1; }
/* The words the column runs over step right back (the script marks them): the outlines get a lane of their own
   through the paragraph instead of being printed across it. */
html.js .view--who.is-echo .w.is-under { opacity: 0.2; }
html.js .view--who.is-echo .view__statement .w.is-under { opacity: 0.03; }

.echo {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}
.echo__group { position: absolute; inset: 0; line-height: 1.1; letter-spacing: -0.04em; }   /* (the script sets the line's own measure where it differs — and, where the column is to thin out towards its ends, a mask) */
.echo__row {
  position: absolute;
  font-family: var(--font-display);
  font-weight: 700;
  line-height: inherit;
  letter-spacing: inherit;
  white-space: nowrap;
  /* The outline: a stroke twice the wanted weight with the ground's colour
     filled back over it. Only the outer half shows — and none of the seams
     a variable font's overlapping contours leave inside a plain stroke. */
  color: var(--view-ground);
  -webkit-text-stroke: clamp(1.6px, 0.024em, 3.2px) var(--echo-ink, var(--color-ink));   /* half of it shows: hairline at any size */
  paint-order: stroke fill;
  opacity: 0;
  transition: opacity 160ms ease;
}
.echo__group.is-on .echo__row { opacity: 1; transition: opacity 320ms ease calc(var(--d, 0) * 34ms); }
@media (prefers-reduced-motion: reduce) {
  .echo__row, .echo__group.is-on .echo__row,
  .view__top, .view__label, .view__line, .view__big, .view__copy, .steps { transition: none; }
}

.view .btn { margin-top: 40px; }
.view .glow-btn:focus-visible { outline-color: var(--view-focus); }
.btn--accent {
  background: var(--color-accent);
  color: var(--color-ink);
  --glow-spot: rgba(255, 255, 255, 0.34);
  --glow-shadow: 0 12px 28px -10px rgba(var(--accent-rgb), 0.6);
}
.btn--ink {
  background: var(--color-ink);
  color: var(--color-white);
  --glow-spot: rgba(255, 255, 255, 0.2);
  --glow-rim: rgba(255, 255, 255, 0.85);
  --glow-shadow: 0 12px 28px -10px rgba(14, 14, 16, 0.55);
}

/* Arrival: the zoom lands on a flat field of colour; then the paper's grid
   fades up and the page comes in the way the poster does — the words rise,
   the bubble and the button pop, one after the other. Leaving, they go first. */
.view[open] .backdrop { animation: fade-in 700ms ease both; }
.view[open] .view__mark,
.view[open] .view__label,
.view[open] .view__statement,
.view[open] .view__copy,
.view[open] .view__line,
.view[open] .view__big {
  animation: rise-in 500ms cubic-bezier(0.215, 0.61, 0.355, 1) backwards;
  animation-delay: calc(var(--i, 0) * 80ms + 60ms);
}
.view[open] .view__close,
.view[open] .steps__dot,
.view[open] .steps__next,
.view[open] .steps__sound,
.view[open] .btn {
  animation: pop-in 500ms cubic-bezier(0.34, 1.45, 0.64, 1) backwards;
  animation-delay: calc(var(--i, 0) * 80ms + 60ms);
}
.view[open] .btn .glow-btn__label,
.view[open] .btn .glow-btn__arrow {
  animation: rise-in 500ms cubic-bezier(0.215, 0.61, 0.355, 1) backwards;
  animation-delay: calc(var(--i, 0) * 80ms + 110ms);
}
.view__mark { --i: 0; }
.view__close, .view__label, .view__line { --i: 1; }
.view__statement, .view__big:nth-child(1) { --i: 2; }
.view__big:nth-child(2), .view__copy { --i: 3; }
.view .btn { --i: 4; }
.steps__dot:nth-child(1) { --i: 4; }
.steps__dot:nth-child(2) { --i: 5; }
.steps__dot:nth-child(3) { --i: 6; }
.steps__next { --i: 7; }
.steps__sound { --i: 3; }

/* A page someone arrived on is already painted (through :target) when the
   script takes it over: nothing replays. */
.view.is-static .backdrop,
.view.is-static .view__inner * { animation: none !important; }

.view.is-leaving .backdrop,
.view.is-leaving .view__inner,
.view.is-leaving .echo { animation: view-out 180ms ease both; }
@keyframes view-out { to { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .view[open] .backdrop,
  .view[open] .view__mark, .view[open] .view__label, .view[open] .view__statement, .view[open] .view__copy, .view[open] .view__line, .view[open] .view__big,
  .view[open] .view__close, .view[open] .steps__dot, .view[open] .steps__next, .view[open] .steps__sound, .view[open] .btn,
  .view[open] .btn .glow-btn__label, .view[open] .btn .glow-btn__arrow,
  .view.is-leaving .backdrop, .view.is-leaving .view__inner, .view.is-leaving .echo { animation: none; }
  .view__close { transition: none; }
  .view__close:hover { transform: none; }
}

/* The zoom's stand-in: a flat rectangle laid exactly over the dot (or the
   full stop) and scaled with the poster, so the field of colour that fills
   the window has clean edges however far the poster's bitmap is stretched. */
.iris {
  position: fixed;
  z-index: 40;
  pointer-events: none;
  will-change: transform;
}
.iris__icon {                          /* the pressed square's icon, carried into the zoom and faded there */
  position: absolute;
  top: 50%;
  left: 50%;
  width: 60%;
  height: 60%;
  transform: translate(-50%, -50%);
  fill: none;
  stroke: currentColor;
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.iris__icon .spot__icon-dot { fill: currentColor; stroke: none; }
html.is-zooming body { pointer-events: none; }

/* ==========================================================================
   Glow button — the label moves over to make room for an arrow, and a light
   follows the cursor across the face (--x / --y): a soft spot and a bright
   rim. Without a script, eight hover strips inside the button set --x and
   the registered property glides between them; with the script the pointer
   sets both exactly.
   ========================================================================== */
@property --x { syntax: "<length-percentage>"; inherits: true; initial-value: 50%; }
@property --y { syntax: "<length-percentage>"; inherits: true; initial-value: 50%; }

.glow-btn {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  gap: 8px;
  cursor: pointer;
  --x: 50%;
  --y: 50%;
  --glow-spot: rgba(255, 255, 255, 0.28);
  --glow-rim: rgba(255, 255, 255, 0.95);
  --glow-shadow: 0 12px 28px -10px rgba(var(--deep-rgb), 0.55);
  transition:
    transform 260ms var(--ease-settle),
    box-shadow 300ms ease,
    opacity 240ms ease,
    --x 160ms ease-out,
    --y 160ms ease-out;
}
.glow-btn:hover { transform: translateY(-1px); box-shadow: var(--glow-shadow); }
.glow-btn:active { transform: translateY(0) scale(0.985); }
.glow-btn:focus-visible { outline: 2px solid var(--color-ink); outline-offset: 3px; }

.glow-btn__glow,
.glow-btn__ring {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
}
.glow-btn__glow { background: radial-gradient(140px circle at var(--x) var(--y), var(--glow-spot), transparent 60%); }
.glow-btn__ring {
  padding: 1.5px;
  background: radial-gradient(110px circle at var(--x) var(--y), var(--glow-rim), transparent 70%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
}
/* The light fades out where the pointer left it. With the script the last
   position stays set; the hover-strip fallback cannot remember it, so there
   the light simply goes out on leave and only fades in. */
.glow-btn:hover .glow-btn__glow,
.glow-btn:hover .glow-btn__ring { opacity: 1; transition: opacity 300ms ease; }
.glow-btn.is-js .glow-btn__glow,
.glow-btn.is-js .glow-btn__ring { transition: opacity 300ms ease; }

.glow-btn__label,
.glow-btn__arrow { position: relative; z-index: 1; }
.glow-btn__arrow {
  flex: none;
  width: 16px;
  height: 16px;
  transition: transform 260ms var(--ease-settle);
}
.glow-btn:hover .glow-btn__arrow { transform: translateX(2px); }

.glow-btn__zones { position: absolute; inset: 0; z-index: 2; display: none; }
.glow-btn__zones i { flex: 1; }

@media (hover: hover) and (pointer: fine) {
  .glow-btn__zones { display: flex; }
  .glow-btn:not(.is-js):has(.glow-btn__zones i:nth-child(1):hover) { --x: 6.25%; }
  .glow-btn:not(.is-js):has(.glow-btn__zones i:nth-child(2):hover) { --x: 18.75%; }
  .glow-btn:not(.is-js):has(.glow-btn__zones i:nth-child(3):hover) { --x: 31.25%; }
  .glow-btn:not(.is-js):has(.glow-btn__zones i:nth-child(4):hover) { --x: 43.75%; }
  .glow-btn:not(.is-js):has(.glow-btn__zones i:nth-child(5):hover) { --x: 56.25%; }
  .glow-btn:not(.is-js):has(.glow-btn__zones i:nth-child(6):hover) { --x: 68.75%; }
  .glow-btn:not(.is-js):has(.glow-btn__zones i:nth-child(7):hover) { --x: 81.25%; }
  .glow-btn:not(.is-js):has(.glow-btn__zones i:nth-child(8):hover) { --x: 93.75%; }
  .glow-btn.is-js { transition-property: transform, box-shadow, opacity; }
}

@media (prefers-reduced-motion: reduce) {
  .glow-btn, .glow-btn__arrow,
  .glow-btn:hover .glow-btn__glow, .glow-btn:hover .glow-btn__ring,
  .glow-btn.is-js .glow-btn__glow, .glow-btn.is-js .glow-btn__ring { transition: none; }
  .glow-btn:hover { transform: none; }
  .glow-btn:hover .glow-btn__arrow { transform: none; }
}

/* ==========================================================================
   Tablet — ≤1024 (iPad 834; column = width − 64)
   ========================================================================== */
@media (max-width: 1024px) {
  :root {
    --column: calc(var(--vw) - 64px);
    --grid-pitch: 64px;
    --fs-title: 44px;
    --fs-line: 17px;
    --page-top: 40px;
    --page-bottom: 32px;
  }
}

/* ==========================================================================
   Mobile — ≤768 (iPhone 402; column = width − 32): the statement sized to
   sit beside the toggle, the axis keeps only its decades.
   ========================================================================== */
@media (max-width: 768px) {
  :root {
    --column: calc(var(--vw) - 32px);
    --bubble-h: 48px;
    --fs-title: clamp(24px, (var(--vw) - 32px - 48px - 16px) / 9.1, 44px);   /* "Artist Management" fits beside the toggle */
    --fs-line: 16px;
    --fs-axis: 11px;
    --fs-foot: 13px;
    --page-top: 32px;
    --page-bottom: 24px;
    --top-gap: 56px;
  }

  .poster__top { gap: 16px; }
  .poster__title { white-space: normal; }
  .menu { top: calc(100% + 30px); }          /* clear of the statement's second line */

  .axis { height: 36px; }
  .axis .is-minor-label { display: none; }

  .footer { margin-top: 14px; }

  .view__mark { font-size: 24px; }
  .view__body { padding: 40px 0 calc(var(--bubble-h) + 16px); }
  .view__statement { margin-top: 20px; font-size: clamp(26px, var(--column) / 13, 34px); }
  .view__copy { margin-top: 22px; font-size: 18px; }
  .view .btn { align-self: stretch; margin-top: 32px; }
  .eq__cta { margin-top: 24px; }
  .eq .eq__cta .btn { flex: 1; margin-top: 0; }
  .eq__node { width: 12px; height: 12px; margin: -6px 0 0 -6px; }
}

/* ==========================================================================
   Contrast themes (forced colours): backgrounds and shadows are dropped, so
   the bubbles, their bars and the pills get real edges in system colours.
   ========================================================================== */
@media (forced-colors: active) {
  .nav__toggle, .view__close, .btn, .menu__pill { border: 1px solid ButtonText; }
  .spot:hover::before, .spot:focus-visible::before { background: Highlight; }
  .spot__icon { stroke: HighlightText; }
  .spot__icon-dot { fill: HighlightText; }
  .nav__toggle-bar, .view__close span { background: ButtonText; }
  .mark__dot, .view__lead { color: Highlight; }
  .echo__row { color: Canvas; -webkit-text-stroke-color: CanvasText; }
  .axis::before, .axis i, .axis i.is-major { background: CanvasText; }
  .eq__line { stroke: CanvasText; }
  .steps__dot:hover::before { background: ButtonText; }                        /* (before the next rule, so the current step stays Highlight under the mouse) */
  .eq__node, .steps__dot[aria-current="step"]::before { background: Highlight; }
  .steps__dot::before { background: GrayText; }
  .steps__next { border: 1px solid ButtonText; }
  .steps__sound { color: ButtonText; }
}
