/*
 * Thrumm Energy — a one-page project in live 3D (tickets/SC-08.md).
 *
 * Layers of the pinned stage, back to front:
 *   .field     z0  the hall in one state of its light: the script paints its back wall, its
 *                  neon tubes, its wet floor and its haze on the canvas inside (.hall)
 *   .word …    z1  the sign on that wall: the monument word; in act 3 the phrase
 *   #gl        z2  the cans, what the floor mirrors of them, their light, the sparks: a
 *                  transparent canvas over the hall
 *   .marks     z3  two crosses and a tag
 *   .bar …     z4  the interface, which stands still: the captions of act 1, the callouts
 *                  of act 2, the line and the button of act 4
 * After the stage, in the flow of the page: .foot — the wall once more, with its tape and its sign.
 */

:root {
  --th-black: #0b0b0f;
  --th-paper: #f4f4f6;
  --th-mint: #19e3b1;
  --th-violet: #7a5cff;
  --th-orange: #ff5a36;
  --th-citrus: #f5e663;
  --th-cherry: #e0245e;

  --ease-camera: cubic-bezier(0.65, 0, 0.35, 1);
  --ease-text: cubic-bezier(0.16, 1, 0.3, 1);
  --gutter: clamp(16px, 2.6vw, 40px);

  /*
   * The faces of the brand: the condensed black italic of the can for the names and the
   * captions, its plain sibling for what is small. The studio's own face is kept for its
   * corner only.
   *
   * The large words — the sign on the wall, the phrase, the line of the finale, the sign
   * of the footer — are set two ways, to be chosen between by eye (the query ?type=):
   * "wide", the default, in a wide black italic set solid, a slab of a word; "condensed"
   * in the face of the can. The rules below are the wide setting; what the condensed one
   * changes stands under :root[data-type="condensed"].
   */
  --face-display: "Barlow Condensed", "Arial Narrow", Arial, sans-serif;
  --face-wide: "Archivo", "Arial Black", Arial, sans-serif;
  --face-big: var(--face-wide);
  --big-stretch: 125%;
  --face-text: "Barlow", system-ui, -apple-system, "Segoe UI", sans-serif;
  --face-studio: "Onest", system-ui, -apple-system, "Segoe UI", sans-serif;
}

:root[data-type="condensed"] {
  --face-big: var(--face-display);
  --big-stretch: 100%;
}

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

html {
  background: var(--th-black);
  /* On the root, not the body: nothing of the document is left with the browser's black. */
  color: var(--th-paper);
  scrollbar-color: var(--th-mint) var(--th-black);
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  font-family: var(--face-text);
  font-size: 16px;
  line-height: 1.35;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overscroll-behavior-y: none;
}

::selection {
  background-color: var(--th-mint);
  color: #000;
}

p,
h1,
h2,
h3,
ol,
ul {
  margin: 0;
  padding: 0;
}

/* ——— The pinned scene ——— */

/* Six screens of scroll for the four acts, and the screen the stage itself takes. */
.scene {
  position: relative;
  height: 700vh;
}

.stage {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;
  overflow: hidden;
  isolation: isolate;
}

/* ——— z0: the hall ——— */

/*
 * A field is the hall in one state of its light. The script paints the hall on the
 * canvas inside; the colours here are what stands behind it — and all there is without
 * the script.
 */
.field {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background-color: var(--f);
  background-image: radial-gradient(
    120% 92% at 50% 46%,
    var(--f-hi) 0%,
    var(--f) 46%,
    var(--f-lo) 100%
  );
}

.field[data-tone="black"] {
  --f: #0b0b0f;
  --f-hi: #17171f;
  --f-lo: #050507;
  --w: var(--th-paper);
}

/* Act 1: the hall stays dark. A flavour turns the sign and the tubes to its colour. */
.field[data-tone^="k-"] {
  --f: #0b0b0f;
  --f-hi: color-mix(in srgb, var(--w) 14%, #0b0b0f);
  --f-lo: #050507;
}

.field[data-tone="k-mint"] {
  --w: var(--th-mint);
}

.field[data-tone="k-violet"] {
  --w: var(--th-violet);
}

.field[data-tone="k-citrus"] {
  --w: var(--th-citrus);
}

.field[data-tone="k-cherry"] {
  --w: var(--th-cherry);
}

.field[data-tone="k-orange"] {
  --w: var(--th-orange);
}

.field[data-tone="mint"] {
  --f: #19e3b1;
  --f-hi: #43f2c6;
  --f-lo: #0db78d;
}

.field[data-tone="violet"] {
  --f: #7a5cff;
  --f-hi: #9079ff;
  --f-lo: #5a3be2;
}

/* Once the hall is painted, nothing stands behind it (see scene.js → paintHalls). */
.has-hall .field {
  background: none;
}

/*
 * The painted hall: a little wider than the screen, so it can slide against the scroll
 * and away from the pointer — the wall is far, the cans are near.
 */
.hall {
  position: absolute;
  left: -4%;
  top: 0;
  width: 108%;
  height: 100%;
  transform: translate3d(calc(var(--wx, 0px) + var(--ws, 0px)), 0, 0);
}

/*
 * A flood: a hard-edged circle that grows from a can and takes the hall. The layer is
 * clipped to the circle — a shape, which costs the browser nothing to move; a mask of a
 * gradient was painted anew every frame, as large as the screen. The two rings that run
 * just inside its edge are drawn with the cans.
 */
.flood {
  visibility: hidden;
  -webkit-clip-path: circle(var(--r1, 0px) at var(--fx, 50%) var(--fy, 50%));
  clip-path: circle(var(--r1, 0px) at var(--fx, 50%) var(--fy, 50%));
}

.flood.is-open {
  visibility: visible;
}

.flood.is-full {
  -webkit-clip-path: none;
  clip-path: none;
}

/* A field wholly under a full one is not painted. */
.field.is-under {
  visibility: hidden;
}

/* The warm-up: for two frames every layer of the hall is on, all but transparent, so the browser has made each before a flood asks for it. */
.stage.is-warming .field {
  visibility: visible;
}

.stage.is-warming .flood {
  opacity: 0.004;
  -webkit-clip-path: none;
  clip-path: none;
}

/* ——— z1: the sign on the wall ——— */

/*
 * The monument word: a neon sign in the upper third of the wall, over the heads of the
 * cans that stand before it. Wide: one slab of a word as wide as the wall. Condensed: the
 * face is narrow, so the letters are set wide apart, each a lamp of its own, and the sign
 * is as wide as the wall without being taller. The script sets the size and the spacing.
 */
.word {
  position: absolute;
  /* Wider than the wall: a line that does not fit its box is not centred in it. */
  left: -12%;
  right: -12%;
  top: var(--sign-y, 26%);
  transform: translate3d(calc(var(--wx, 0px) + var(--ws, 0px)), -50%, 0);
  color: var(--w);
  /* What spread letters add after the last one is given back in front: the sign stays in the middle. */
  padding-left: max(0em, var(--word-track, 0em));
  font-family: var(--face-big);
  font-size: var(--word-size, 15.2vw);
  font-stretch: var(--big-stretch);
  font-style: italic;
  font-weight: 900;
  font-kerning: none;
  line-height: 0.8;
  letter-spacing: var(--word-track, -0.02em);
  text-align: center;
  white-space: nowrap;
  user-select: none;
  -webkit-user-select: none;
}

/*
 * Act 3: the phrase on the lit wall. White, not black: the cans are black, and they stand
 * before these letters. Wide: two lines, each as large as the wall lets it be, running
 * against each other with the scroll, as words on a wall of lamps can. Condensed: one line
 * as wide as the wall, running against the scroll (two lines on a tall screen).
 */
.shout {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: var(--wall, 60%);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: var(--th-paper);
  font-family: var(--face-big);
  font-size: var(--shout-size, 17vw);
  font-stretch: var(--big-stretch);
  font-style: italic;
  font-weight: 900;
  font-kerning: none;
  line-height: 0.8;
  text-transform: uppercase;
  white-space: nowrap;
  user-select: none;
  -webkit-user-select: none;
}

.shout span {
  display: block;
  font-size: var(--shout-0, 1em);
  /* On the line itself: an em of spacing is the line's own em. */
  letter-spacing: -0.03em;
  transform: translate3d(calc(var(--shift, 0px) + var(--wx, 0px) + var(--ws, 0px)), 0, 0);
}

.shout span:last-child {
  font-size: var(--shout-1, 1em);
  transform: translate3d(calc(var(--shift, 0px) * -1 + var(--wx, 0px) + var(--ws, 0px)), 0, 0);
}

:root[data-type="condensed"] .shout {
  top: var(--phrase-y, 24%);
  display: block;
  height: auto;
  transform: translate3d(calc(var(--shift, 0px) + var(--wx, 0px) + var(--ws, 0px)), -50%, 0);
  padding-left: var(--shout-track, 0em);
  letter-spacing: var(--shout-track, 0em);
  text-align: center;
}

:root[data-type="condensed"] .shout span {
  display: inline;
  font-size: inherit;
  letter-spacing: inherit;
  transform: none;
}

/* ——— z2: the cans ——— */

#gl {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  opacity: 0;
  transition: opacity 900ms var(--ease-camera);
}

#gl.is-ready {
  opacity: 1;
}

/* ——— Tones of the interface: paper in the dark, black on a colour ——— */

[data-ui] {
  --ui: var(--th-paper);
  --ui-dim: rgb(244 244 246 / 0.74);
  --ui-line: rgb(244 244 246 / 0.36);
  color: var(--ui);
  transition: color 320ms var(--ease-camera);
}

/* Pure black on the colours: on violet nothing lighter holds 4.5 to 1. */
[data-ui][data-tone="mint"],
[data-ui][data-tone="violet"] {
  --ui: #000;
  --ui-dim: #000;
  --ui-line: rgb(0 0 0 / 0.46);
}

/* For a reader of the page, not for the eye: the half of the name the giant word already says. */
.sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ——— z3: the markup layer ——— */

.marks {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.cross {
  position: absolute;
  width: 15px;
  height: 15px;
  color: var(--ui-line);
  transition: color 320ms var(--ease-camera);
}

.cross::before,
.cross::after {
  content: "";
  position: absolute;
  background-color: currentColor;
}

.cross::before {
  left: 7px;
  top: 0;
  width: 1px;
  height: 15px;
}

.cross::after {
  left: 0;
  top: 7px;
  width: 15px;
  height: 1px;
}

.cross[data-at="a"] {
  left: calc(22% - 7px);
  top: calc(15% - 7px);
}

.cross[data-at="b"] {
  right: calc(22% - 7px);
  bottom: calc(13% - 7px);
}

/* ——— z4: the interface ——— */

.bar {
  position: absolute;
  top: var(--gutter);
  left: var(--gutter);
  right: var(--gutter);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  font-family: var(--face-display);
  font-size: 20px;
  font-style: italic;
  font-weight: 900;
  letter-spacing: 0.04em;
  line-height: 1;
  text-transform: uppercase;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
}

/* The mark: a volume knob, its pointer past two o'clock. */
.brand-mark {
  flex: none;
  width: 26px;
  height: 26px;
  fill: none;
  stroke: currentColor;
  stroke-width: 7;
  stroke-linecap: round;
}

/* The captions share one cell; one is shown at a time. */
.captions {
  position: absolute;
  left: var(--gutter);
  bottom: calc(var(--gutter) + 4px);
  display: grid;
  width: min(30vw, 440px);
}

.caption {
  grid-area: 1 / 1;
  align-self: end;
}

.title {
  font-family: var(--face-display);
  font-size: clamp(36px, 4vw, 66px);
  font-style: italic;
  font-weight: 900;
  line-height: 0.95;
  text-transform: uppercase;
}

.notes {
  margin-top: 12px;
  font-size: clamp(15px, 1.2vw, 18px);
  font-weight: 500;
  line-height: 1.35;
}

/* A line comes up from under a mask and leaves the way it came. */
.line {
  display: block;
  overflow: hidden;
  padding-bottom: 0.14em;
  margin-bottom: -0.14em;
}

.line > span {
  display: block;
  transform: translate3d(0, 118%, 0);
  transition: transform 240ms var(--ease-camera);
}

.caption.is-on .line > span,
.callout.is-on .line > span,
.final.is-on .line > span {
  transform: none;
  transition: transform 560ms var(--ease-text) calc(var(--i, 0) * 60ms + 120ms);
}

/* The pointer of the five flavours. */
.index {
  position: absolute;
  right: var(--gutter);
  top: 70%;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 18px;
  transform: translateY(-50%);
}

.count {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  line-height: 1;
  opacity: 0.62;
  transition: opacity 320ms var(--ease-camera);
}

.index {
  transition:
    opacity 320ms var(--ease-camera),
    visibility 0s linear 0s,
    color 320ms var(--ease-camera);
}

.stage:not([data-act="0"]) .index,
.stage:not([data-act="0"]) .cross {
  opacity: 0;
  visibility: hidden;
  transition:
    opacity 320ms var(--ease-camera),
    visibility 0s linear 320ms;
}

.stage:not([data-state="0"]) .count {
  opacity: 1;
}

.count-now {
  display: block;
  height: 1em;
  overflow: hidden;
}

.roll {
  display: flex;
  flex-direction: column;
  transform: translate3d(0, calc(var(--n, 0) * -1em), 0);
  transition: transform 520ms var(--ease-text);
}

.roll > span {
  display: block;
  height: 1em;
}

.count-dash {
  color: var(--ui-dim);
}

.ticks {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
  list-style: none;
}

.ticks button {
  position: relative;
  display: block;
  width: 44px;
  height: 22px;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  cursor: pointer;
}

.ticks button::after {
  content: "";
  position: absolute;
  right: 0;
  top: 10px;
  width: 16px;
  height: 2px;
  background-color: currentColor;
  opacity: 0.5;
  transition:
    width 420ms var(--ease-text),
    opacity 240ms linear;
}

.ticks button:hover::after,
.ticks button:focus-visible::after {
  opacity: 0.85;
}

.ticks button:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

.stage[data-state="1"] .ticks li:nth-child(1) button::after,
.stage[data-state="2"] .ticks li:nth-child(2) button::after,
.stage[data-state="3"] .ticks li:nth-child(3) button::after,
.stage[data-state="4"] .ticks li:nth-child(4) button::after,
.stage[data-state="5"] .ticks li:nth-child(5) button::after {
  width: 40px;
  opacity: 1;
}

.hint {
  position: absolute;
  right: var(--gutter);
  bottom: calc(var(--gutter) + 4px);
  display: flex;
  align-items: center;
  gap: 12px;
  color: var(--ui-dim);
  font-size: 14px;
  font-weight: 500;
  line-height: 1;
  transition:
    opacity 320ms var(--ease-camera),
    color 320ms var(--ease-camera);
}

.hint i {
  display: block;
  width: 1px;
  height: 34px;
  background-color: currentColor;
}

.stage.is-moving .hint {
  opacity: 0;
}

/* ——— Act 2: one can in detail ——— */

.detail,
.final {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.leaders {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.leader path {
  fill: none;
  stroke: var(--ui);
  stroke-width: 1;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  transition: stroke-dashoffset 240ms var(--ease-camera);
}

.leader .dot {
  fill: var(--ui);
  opacity: 0;
  transition: opacity 160ms linear;
}

.leader .ring {
  fill: none;
  stroke: var(--ui);
  stroke-width: 1;
  opacity: 0;
  transition: opacity 160ms linear;
}

.leader.is-on path {
  stroke-dashoffset: 0;
  transition: stroke-dashoffset 560ms var(--ease-text) 100ms;
}

.leader.is-on .dot {
  opacity: 1;
  transition: opacity 200ms linear 420ms;
}

.leader.is-on .ring {
  opacity: 0.7;
  transition: opacity 200ms linear 500ms;
}

.callout {
  position: absolute;
  left: var(--gutter);
  width: min(27vw, 400px);
}

.callout[data-n="0"] {
  top: 21%;
}

.callout[data-n="1"] {
  left: auto;
  right: var(--gutter);
  top: 40%;
  text-align: right;
}

.callout[data-n="1"] .callout-word {
  margin-left: auto;
}

.callout[data-n="2"] {
  top: 64%;
}

.callout-word {
  width: -webkit-fit-content;
  width: fit-content;
  font-family: var(--face-display);
  font-size: clamp(40px, 4.8vw, 78px);
  font-style: italic;
  font-weight: 900;
  line-height: 0.95;
  text-transform: uppercase;
}

.callout-text {
  margin-top: 12px;
  color: var(--ui-dim);
  font-size: clamp(15px, 1.25vw, 19px);
  font-weight: 500;
  line-height: 1.35;
}

/* ——— Act 4: the five together ——— */

.final-body {
  position: absolute;
  left: var(--gutter);
  top: 44%;
  width: min(48vw, 720px);
  transform: translate3d(0, -50%, 0);
}

.final-title {
  font-family: var(--face-big);
  font-size: clamp(2.5rem, 5.1vw, 5.4rem);
  font-stretch: var(--big-stretch);
  font-style: italic;
  font-weight: 900;
  letter-spacing: -0.035em;
  line-height: 0.96;
  text-transform: uppercase;
  white-space: nowrap;
}

/* The narrow face takes «Five flavours.» in one line; the wide one breaks it after «Five». */
:root[data-type="condensed"] .final-title {
  font-size: clamp(3.2rem, 7.2vw, 6.6rem);
  letter-spacing: normal;
  line-height: 0.9;
}

:root[data-type="condensed"] .wide-break {
  display: none;
}

/* The button: a capsule of the brand's mint in the dark, its arrow in a black round. */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 18px;
  height: 60px;
  margin-top: clamp(24px, 4vh, 44px);
  padding: 6px 6px 6px 26px;
  border-radius: 999px;
  background-color: var(--th-mint);
  color: #000;
  font-size: 17px;
  font-weight: 600;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  /* It is wiped in from its left end, not faded: the capsule is whole or it is not there. */
  clip-path: inset(0 100% 0 0 round 999px);
  transform: translate3d(0, 12px, 0);
  visibility: hidden;
  transition:
    clip-path 240ms var(--ease-camera),
    transform 240ms var(--ease-camera),
    visibility 0s linear 240ms,
    background-color 160ms linear;
}

/* Shown, the clip stands a little off the capsule: room for the ring of the focus. */
.final.is-on .pill {
  clip-path: inset(-6px -6px -6px -6px round 999px);
  transform: none;
  visibility: visible;
  pointer-events: auto;
  transition:
    clip-path 560ms var(--ease-text) 340ms,
    transform 560ms var(--ease-text) 340ms,
    visibility 0s linear 0s,
    background-color 160ms linear;
}

.pill:hover {
  background-color: #5cf0cc;
}

.pill:focus-visible {
  outline: 2px solid var(--th-paper);
  outline-offset: 3px;
}

.pill-round {
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background-color: var(--th-black);
  color: var(--th-mint);
  transition: transform 160ms var(--ease-camera);
}

.pill-round svg,
.studio svg {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.75;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform 160ms var(--ease-camera);
}

.pill:hover .pill-round,
.pill:focus-visible .pill-round {
  transform: scale(1.06);
}

.pill:hover .pill-round svg,
.pill:focus-visible .pill-round svg {
  transform: rotate(45deg);
}

/* ——— The footer: the wall of the hall once more, its sign, and the studio's lime corner ——— */

/*
 * Not a table of the brand: the back wall again, lower down. A tape of the five flavours
 * runs along it; under the tape the name stands as a sign of neon tube, as wide as the
 * wall, its feet under the edge of the screen. It burns in the colour of the last can.
 */
.foot {
  position: relative;
  display: flex;
  flex-direction: column;
  min-height: 56vh;
  padding-top: clamp(40px, 9vh, 96px);
  overflow: hidden;
  border-top: 1px solid rgb(244 244 246 / 0.16);
  background-color: var(--th-black);
  /* What the sign throws up the wall, and the seams of its panels. */
  background-image:
    radial-gradient(
      72% 82% at 50% 108%,
      rgb(255 90 54 / 0.28) 0%,
      rgb(255 90 54 / 0.09) 44%,
      rgb(255 90 54 / 0) 72%
    ),
    repeating-linear-gradient(
      90deg,
      rgb(0 0 0 / 0.5) 0 2px,
      rgb(255 255 255 / 0.035) 2px 3px,
      rgb(0 0 0 / 0) 3px calc(100% / 12)
    );
}

/* The tape: one line, edge to edge, running by itself. Two runs of the same five, so it never ends. */
.tape {
  overflow: hidden;
  padding: 18px 0;
  border-top: 1px solid rgb(244 244 246 / 0.2);
  border-bottom: 1px solid rgb(244 244 246 / 0.2);
}

.tape-track {
  display: flex;
  width: max-content;
  animation: tape 44s linear infinite;
}

/* It runs only while it can be seen (the script says when). */
.is-live .foot:not(.is-seen) .tape-track {
  animation-play-state: paused;
}

@keyframes tape {
  to {
    transform: translate3d(-50%, 0, 0);
  }
}

.tape-run {
  display: flex;
  flex: none;
  gap: clamp(30px, 4.2vw, 68px);
  padding-right: clamp(30px, 4.2vw, 68px);
  list-style: none;
}

.tape-run li {
  display: flex;
  align-items: center;
  gap: 12px;
  white-space: nowrap;
}

/* The colour of the flavour: the dot the can carries on its back, lit. */
.tape-run li::before {
  content: "";
  flex: none;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background-color: var(--c);
  box-shadow: 0 0 12px var(--c);
}

.tape-run b {
  font-family: var(--face-display);
  font-size: clamp(22px, 2vw, 30px);
  font-style: italic;
  font-weight: 900;
  letter-spacing: 0.01em;
  line-height: 1.1;
  text-transform: uppercase;
}

.tape-run span,
.foot-note {
  color: rgb(244 244 246 / 0.74);
  font-size: 15px;
  line-height: 1.4;
}

.foot-note {
  margin-top: 22px;
  padding: 0 var(--gutter);
}

/*
 * The sign. The script draws it on a canvas: a neon tube round the outline of the letters,
 * the hot line down its middle, its glow — drawn once, nothing here is animated. The
 * letters below hold its place in the page, and stand for it when there is no script:
 * the same word, lit whole in the orange of the last can. (An outline by a stroke of the
 * text will not do: the face is built of overlapping shapes, and every seam shows.)
 */
.neon {
  margin: auto 0 -0.28em;
  padding-top: clamp(36px, 7vh, 72px);
  color: var(--th-orange);
  font-family: var(--face-big);
  font-size: var(--neon-size, 15.4vw);
  font-stretch: var(--big-stretch);
  font-style: italic;
  font-weight: 900;
  letter-spacing: -0.02em;
  line-height: 0.8;
  text-align: center;
  white-space: nowrap;
  filter: drop-shadow(0 0 7px rgb(255 90 54 / 0.95)) drop-shadow(0 0 30px rgb(255 90 54 / 0.6));
  user-select: none;
  -webkit-user-select: none;
}

.neon-sign {
  position: absolute;
  left: 0;
  bottom: 0;
  display: none;
  width: 100%;
  pointer-events: none;
}

.has-sign .neon-sign {
  display: block;
}

.has-sign .neon {
  visibility: hidden;
}

:root[data-type="condensed"] .neon {
  margin-bottom: -0.17em;
  font-size: var(--neon-size, 26vw);
  letter-spacing: normal;
}

/* The studio signs in its own colours, not the brand's: volt and ink, in the corner. */
.studio {
  position: absolute;
  right: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 18px var(--gutter) 18px 26px;
  border-top-left-radius: 28px;
  background-color: #d6fa50;
  color: #0a0a0a;
  /* The studio's own face, here and nowhere else on the page. */
  font-family: var(--face-studio);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.08em;
  line-height: 1;
  text-decoration: none;
  text-transform: uppercase;
  transition: background-color 180ms linear;
}

.studio:hover,
.studio:focus-visible {
  background-color: #b8dc2c;
}

.studio:focus-visible {
  outline: 2px solid var(--th-paper);
  outline-offset: 3px;
}

.studio svg {
  width: 16px;
  height: 16px;
}

.studio:hover svg,
.studio:focus-visible svg {
  transform: rotate(45deg);
}

/* ——— A tall screen: the word in two halves, over the can and under it ——— */

@media (max-aspect-ratio: 4 / 5) {
  .scene {
    height: 680vh;
    height: 680svh;
  }

  /* The callouts share the foot of the screen; the newest one is shown. */
  .callout[data-n="0"],
  .callout[data-n="1"],
  .callout[data-n="2"] {
    left: var(--gutter);
    right: var(--gutter);
    top: auto;
    bottom: calc(var(--gutter) + 6px + env(safe-area-inset-bottom, 0px));
    width: auto;
    text-align: left;
  }

  .callout-word,
  .callout[data-n="1"] .callout-word {
    margin-left: 0;
    font-size: 44px;
  }

  .callout-text {
    margin-top: 8px;
    font-size: 15px;
  }

  .final-body {
    top: auto;
    bottom: calc(var(--gutter) + 10px + env(safe-area-inset-bottom, 0px));
    width: auto;
    transform: none;
  }

  .final-title {
    font-size: clamp(2rem, 9.3vw, 2.8rem);
  }

  :root[data-type="condensed"] .final-title {
    font-size: clamp(3rem, 14vw, 3.8rem);
  }

  .pill {
    height: 54px;
    margin-top: 20px;
  }

  .pill-round {
    width: 42px;
    height: 42px;
  }

  /* The sign in two lines, as on the wall above; whole, over the studio's corner. */
  .foot {
    min-height: 0;
  }

  .neon {
    margin: 0;
    padding: 44px 5% 78px;
    font-size: var(--neon-size, 25.5vw);
  }

  :root[data-type="condensed"] .neon {
    margin: 0;
    font-size: var(--neon-size, 44vw);
  }

  .neon b {
    display: block;
    text-align: left;
  }

  .neon b:last-child {
    text-align: right;
  }

  /* The sign in two lines, at the top of the wall. */
  .word {
    left: 5%;
    right: 5%;
    display: flex;
    flex-direction: column;
    padding-left: 0;
    transform: translate3d(calc(var(--wx, 0px) + var(--ws, 0px)), -50%, 0);
    font-size: var(--word-size, 26.8vw);
  }

  .word span:first-child {
    text-align: left;
  }

  /* The spacing after its last letter hangs over the edge, so the letter itself stands on it. */
  .word span:last-child {
    margin-right: calc(var(--word-track, -0.02em) * -1);
    text-align: right;
  }

  /* The condensed phrase in two lines too; they run against each other. */
  :root[data-type="condensed"] .shout {
    top: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: var(--wall, 60%);
    padding-left: 0;
    transform: none;
  }

  :root[data-type="condensed"] .shout span {
    display: block;
    transform: translate3d(calc(var(--shift, 0px) + var(--wx, 0px) + var(--ws, 0px)), 0, 0);
  }

  :root[data-type="condensed"] .shout span:last-child {
    transform: translate3d(calc(var(--shift, 0px) * -1 + var(--wx, 0px) + var(--ws, 0px)), 0, 0);
  }

  .captions {
    width: min(74vw, 310px);
    bottom: calc(var(--gutter) + 6px + env(safe-area-inset-bottom, 0px));
  }

  .title {
    font-size: 36px;
  }

  .notes {
    margin-top: 8px;
    font-size: 15px;
  }

  .index {
    top: var(--gutter);
    transform: none;
    gap: 14px;
  }

  .count {
    height: 26px;
  }

  .ticks button {
    width: 44px;
    height: 18px;
  }

  .ticks button::after {
    top: 8px;
  }

  .hint {
    bottom: calc(var(--gutter) + 6px + env(safe-area-inset-bottom, 0px));
  }

  .hint span {
    display: none;
  }

  .cross[data-at="a"] {
    left: calc(var(--gutter) - 1px);
    top: calc(50% - 7px);
  }

  .cross[data-at="b"] {
    right: calc(var(--gutter) - 1px);
    bottom: calc(21% - 7px);
  }

}

/*
 * ——— Reduced motion (or ?still): the acts become plain sections ———
 *
 * No pinned stage and no long scroll: the script draws one frame of each act
 * and sets it in a section of its own (.still) — the field, the picture of
 * the cans, the words — one under another. Nothing pulses.
 */

.rm .scene {
  height: auto;
}

.rm .stage {
  position: relative;
}

.rm .stage[hidden] {
  display: none;
}

.still {
  position: relative;
  height: 100vh;
  height: 100svh;
  overflow: hidden;
  isolation: isolate;
}

.still .field {
  visibility: visible;
  -webkit-clip-path: none;
  clip-path: none;
}

.still-shot {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
}

.rm .hint,
.rm .index {
  display: none;
}

/* The tape stands: one run, wrapped, all five of it in sight. */
.rm .tape-track {
  display: block;
  width: auto;
  animation: none;
}

.rm .tape-run {
  flex-wrap: wrap;
  row-gap: 12px;
  padding: 0 var(--gutter);
}

.rm .tape-run li {
  flex-wrap: wrap;
  row-gap: 2px;
  white-space: normal;
}

.rm .tape-run[aria-hidden="true"] {
  display: none;
}

.rm #gl,
.rm [data-ui],
.rm .line > span,
.rm .roll,
.rm .leader path,
.rm .leader circle,
.rm .pill {
  transition: none !important;
}

.rm .line > span {
  transform: none;
}

.rm .caption:not(.is-on) {
  display: none;
}

.rm .leader path {
  stroke-dashoffset: 0;
}

.rm .leader .dot {
  opacity: 1;
}

.rm .leader .ring {
  opacity: 0.7;
}

.rm .pill {
  clip-path: none;
  transform: none;
  visibility: visible;
  pointer-events: auto;
}

@media (max-aspect-ratio: 4 / 5) {
  /* On a phone the three callouts stand in a column at the foot, without their lines. */
  .rm .detail {
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    gap: 14px;
    padding: 0 var(--gutter) calc(var(--gutter) + 6px);
  }

  .rm .callout,
  .rm .callout[data-n="1"] {
    position: static;
  }

  .rm .callout-word {
    font-size: 32px;
  }

  .rm .callout-text {
    margin-top: 4px;
  }

  .rm .leaders {
    display: none;
  }
}

/* Before the script has run, or without it. */
@media (prefers-reduced-motion: reduce) {
  .scene {
    height: auto;
  }

  .stage {
    position: relative;
  }

  #gl,
  [data-ui],
  .line > span,
  .roll {
    transition: none;
  }

  .tape-track {
    display: block;
    width: auto;
    animation: none;
  }

  .tape-run {
    flex-wrap: wrap;
    row-gap: 12px;
    padding: 0 var(--gutter);
  }

  .tape-run li {
    flex-wrap: wrap;
    row-gap: 2px;
    white-space: normal;
  }

  .tape-run[aria-hidden="true"] {
    display: none;
  }
}

/* ——— No WebGL: the field, the word and the words stay ——— */

.no-gl #gl {
  display: none;
}

/* ——— Checks ——— */

.hud {
  position: fixed;
  left: 8px;
  top: 64px;
  z-index: 20;
  margin: 0;
  padding: 8px 10px;
  border-radius: 4px;
  background: rgb(0 0 0 / 0.82);
  color: #b6ff7a;
  font: 11px/1.45 ui-monospace, Menlo, monospace;
  white-space: pre;
  pointer-events: none;
}

.labels {
  position: fixed;
  inset: 0;
  z-index: 30;
  display: grid;
  gap: 8px;
  padding: 8px;
  overflow: auto;
  background: #222;
}

.labels canvas {
  display: block;
  width: 100%;
  height: auto;
}
