:root {
  --page-pad: clamp(24px, 6vw, 96px);
  --page-pad-left: clamp(72px, 18vw, 288px);
  --media-height: 80vh;
  --media-ratio: 9 / 16;
  --media-ratio-num: 0.5625; /* 9 / 16, usable inside calc() */
  --link-hover: rgb(255, 51, 204);
  --header-pad-top: 24px;
}

/* /info's video only — 25% smaller than the site default (80vh),
   scoped so staging.html's reels keep using the root value. */
.info-page {
  --media-height: 60vh;
}

html {
  scrollbar-gutter: stable;
}

html, body {
  margin: 0;
  padding: 0;
  background: #000;
  color: #fff;
}

body.coming-soon {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* staging.html's entry gate — fixed so it sits on top of the real page
   underneath (rather than being the page itself, like .coming-soon
   above); tapping/clicking it (JS) dismisses it to reveal the page.
   Lives entirely in staging.html's own markup, so renaming that file
   to index.html on launch day brings this along with it — nothing
   else to wire up that day. */
.enter-splash {
  position: fixed;
  inset: 0;
  z-index: 2000;
  background: #000;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  cursor: pointer;
  text-align: center;
  padding: 0 5vw;
}

.enter-splash.dismissed {
  display: none;
}

/* .enter-title / .enter-subtitle are their own classes (not reusing
   .info-header / .body-copy etc.) specifically so their font sizes can
   be tuned here without changing anything else on the site. */
/* flat 80px (the full/hero size) from ~444px width upward — the point
   where 18vw naturally reaches 80px, so there's no jump. Below that it
   scales down fluidly with the viewport instead of letting a word
   overflow past the edge (no mid-word breaking). */
.enter-title {
  font-family: "gandur-new", sans-serif;
  font-weight: 300;
  font-style: normal;
  color: #fff;
  margin: 0;
  font-size: clamp(40px, 18vw, 80px);
}

.enter-subtitle {
  font-family: "neue-haas-grotesk-text", sans-serif;
  font-weight: 400;
  font-style: normal;
  color: #fff;
  margin: 0;
  font-size: 14px;
}

.coming-soon-text {
  font-family: "gandur-new", sans-serif;
  font-weight: 300;
  font-style: normal;
  color: #fff;
  text-align: center;
  line-height: 1;
  margin: 0;
  padding: 0 5vw;
  font-size: clamp(5rem, 18vw, 20rem);
}

img {
  display: block;
  width: 100%;
  height: auto;
}

.page {
  padding: var(--page-pad);
  padding-bottom: 200px;
  /* flat 24px from 460px width up; below that it scales down with the
     viewport (5.22vw hits 24px exactly at 460px, so there's no jump) */
  padding-top: clamp(12px, 5.22vw, 24px);
}

.statement-text {
  margin-top: 24px;
}

@media (min-width: 900px) {
  .page {
    padding-left: var(--page-pad-left);
  }
}

.info-header,
.video-title {
  font-family: "gandur-new", sans-serif;
  font-weight: 300;
  font-style: normal;
  color: #fff;
  margin: 0;
}

.video-title {
  font-size: clamp(24px, 16.36vw, 36px);
}

@media (min-width: 450px) {
  .video-title {
    font-size: 65px;
  }
}

/* 130px is the full/hero size, flat from 650px width upward. Below
   650px it scales down fluidly with the viewport (20vw hits 130px
   exactly at 650px, so there's no jump) instead of cropping. */
.info-header {
  white-space: nowrap;
  /*padding-top: var(--header-pad-top);*/
  margin-bottom: clamp(32px, 6vw, 64px);
  font-size: clamp(48px, 16.5vw, 130px);
}

/* staging.html only — 12px less than the shared .info-header value
   above, so the info page's header spacing is untouched */
.staging-page .info-header {
  margin-bottom: clamp(20px, 6vw, 52px);
}

.info-header a {
  color: inherit;
  text-decoration: none;
}

.info-header a:hover {
  color: var(--link-hover);
  text-decoration: underline;
}

.body-copy {
  font-family: "neue-haas-grotesk-text", sans-serif;
  font-weight: 400;
  font-style: normal;
  font-size: 12px;
  line-height: 1.5;
  color: #fff;
  max-width: 65ch;
}

.body-copy p {
  margin: 0 0 1.5em 0;
}

.body-copy a {
  color: #fff;
  text-decoration: underline;
}

.body-copy a:hover {
  color: var(--link-hover);
}

.body-copy em {
  font-style: italic;
}

/* the numbered tapestry list inside .body-copy — inherits that block's
   own font/size (no font-family set here on purpose). Laid out like a
   table of contents: the list is centered on the page as a block
   (inherited from .staging-page's text-align: center — its own
   text-align: left below only affects content inside it), but each row
   is a flex line with a fixed-width number column, so every title's
   first letter lines up under the one above it regardless of digit
   width ("1." vs a two-digit number, should one ever come up). */
.tapestry-list {
  display: inline-block;
  text-align: left;
  list-style: none;
  margin: 0 0 1.5em 0;
  padding: 0;
}

.tapestry-list li {
  display: flex;
}

.tapestry-num {
  flex: 0 0 1.5em;
  text-align: left;
}

.tapestry-title {
  flex: 1 1 auto;
  text-align: left;
}

.stills {
  margin-top: clamp(48px, 8vw, 96px);
  max-width: 900px;
}

.stills img {
  margin-bottom: clamp(32px, 5vw, 56px);
}

.stills img:last-child {
  margin-bottom: 0;
}

.gif-block {
  margin-top: clamp(48px, 8vw, 96px);
}

.gif-block img {
  width: auto;
  height: var(--media-height);
  aspect-ratio: var(--media-ratio);
  max-width: calc(100vw - 2 * var(--page-pad));
}

@media (min-width: 900px) {
  .gif-block img {
    max-width: calc(100vw - var(--page-pad-left) - var(--page-pad));
  }
}

.video-section {
  margin-top: clamp(32px, 5vw, 96px);
}

/* two carriage returns' worth of the body-copy text that follows it:
   12px font-size * 1.5 line-height * 2 lines = 36px */
.video-preview {
  margin-bottom: 36px;
}

.preview-section {
  margin: clamp(48px, 8vw, 96px) 0 24px 0;
}

.preview-note {
  font-family: "neue-haas-grotesk-text", sans-serif;
  font-weight: 400;
  font-style: normal;
  font-size: 12px;
  line-height: 1.5;
  color: #fff;
  text-align: left;
  margin: 0;
}

.preview-note em {
  font-style: normal;
}

.preview-note a {
  color: #fff;
  text-decoration: underline;
}

.preview-note a:hover {
  color: var(--link-hover);
}

/* .video-frame's width is derived from the same height + ratio as the
   video itself, so anything inside it (the numeral, the title) is
   guaranteed to match the video's rendered width, regardless of how
   long that text is. .reel-frame reuses the same formula so the reel
   embeds on staging.html match the info page's Vimeo sizing exactly. */
.video-frame,
.preview-frame,
.reel-frame {
  width: min(
    calc(var(--media-height) * var(--media-ratio-num)),
    calc(100vw - 2 * var(--page-pad))
  );
}

.preview-label {
  font-family: "neue-haas-grotesk-text", sans-serif;
  font-weight: 400;
  font-style: normal;
  font-size: 12px;
  line-height: 1.5;
  color: #fff;
  text-align: left;
  letter-spacing: 0.05em;
  margin: 0 0 8px 0;
}

.sound-note {
  font-family: "neue-haas-grotesk-text", sans-serif;
  font-weight: 400;
  font-style: normal;
  font-size: 12px;
  line-height: 1.5;
  color: #fff;
  text-align: left;
  margin: 0 0 32px 0;
}

/* mobile/narrow widths — tighter spacing below the preview video */
@media (max-width: 600px) {
  .sound-note,
  .video-preview {
    margin-bottom: 16px;
  }
}

@media (min-width: 900px) {
  .video-frame,
  .preview-frame,
  .reel-frame {
    width: min(
      calc(var(--media-height) * var(--media-ratio-num)),
      calc(100vw - var(--page-pad-left) - var(--page-pad))
    );
  }
}

/* height comes from aspect-ratio (not a fixed var(--media-height))
   because .video-frame/.preview-frame/.reel-frame's own width is
   capped by viewport width on narrow-but-tall screens (Pixel 10, etc.)
   — see the min() formula above. With a fixed height, that cap left
   the box taller than the actual (narrower) video, so Vimeo
   letterboxed it and anything below (like .reel-title) ended up with
   extra empty space under the visible video. Deriving height from the
   real rendered width instead means the box is always exactly the
   video's own aspect ratio, whichever formula branch capped the width. */
.video-embed {
  position: relative;
  width: 100%;
  aspect-ratio: var(--media-ratio);
}

.video-embed iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

.video-title {
  text-align: left;
  margin: 0 0 24px 0;
}

/* Staging page (staging.html) — same components as the info page,
   but centered rather than left-justified. */
.staging-page {
  text-align: center;
}

@media (min-width: 900px) {
  .staging-page {
    padding-left: var(--page-pad);
  }
}

.follow-sentinel {
  height: 0;
}

.follow-row {
  position: sticky;
  top: 0;
  z-index: 500;
  background: #000;
  padding: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
}

/* .stuck is toggled by JS once the sticky follow-row has actually
   pinned itself to the top of the viewport — give it breathing room
   as a floating header bar; in normal flow it stays flush (0). */
.follow-row.stuck {
  padding: 12px 0;
}

.follow-link {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 0;
  color: #fff;
  text-decoration: none;
}

.follow-text {
  font-family: "neue-haas-grotesk-text", sans-serif;
  font-weight: 400;
  font-style: normal;
  font-size: 14px;
  line-height: 1.5;
  margin: 0;
}

/* below this width the long version wraps to a second line (tested at
   ~570px with a fallback system font — the live page uses Typekit's
   neue-haas-grotesk-text, which may wrap at a slightly different width,
   so nudge this breakpoint if the swap happens a beat too early/late
   once it's live), so swap to the short version instead of wrapping. */
.follow-text-short {
  display: none;
}

@media (max-width: 600px) {
  .follow-text-full {
    display: none;
  }
  .follow-text-short {
    display: inline;
  }
}

/* the ☞ that follows .follow-text — its own flex sibling (not nested
   inline) so align-items: center on .follow-link centers it, and the
   IG logo, against the text's own height; size it here independently.
   Fine-tuning hooks (all three are independent of everything else on
   the row, so adjust freely):
     - vertical position: translateY below — increase to nudge it down,
       decrease/make negative to nudge it up
     - space to the text on its left: margin-left
     - space to the IG logo on its right: margin-right */
.follow-arrow {
  font-size: 28px;
  line-height: 1;
  margin-left: 6px;
  margin-right: 3px;
  transform: translateY(3px);
}

/* replaces .follow-arrow above (now commented out in the markup) — a
   hand-traced vector (SVG) of the original scanned engraving. The svg's
   own path data lives in media/Manicule_v01.svg, not here — this is an
   empty <span>, shaped by that file used as a mask and painted with
   background-color, so it recolors on hover along with the text and
   the Instagram icon (see .follow-link:hover below) and stays sharp at
   any size since it's still a vector.
   Fine-tuning hooks, independent of everything else on the row:
     - size: height (width follows via aspect-ratio, using the source
       svg's own viewBox proportions, 624 x 202)
     - vertical position: translateY — increase to nudge it down,
       decrease/make negative to nudge it up
     - space to the text on its left: margin-left
     - space to the IG logo on its right: margin-right */
.follow-hand {
  display: block;
  height: 16px;
  width: auto;
  aspect-ratio: 624 / 202;
  flex-shrink: 0;
  margin-left: 9px;
  margin-right: 3px;
  transform: translateY(1px);
  background-color: currentColor;
  -webkit-mask-image: url("media/Manicule_v01.svg");
  mask-image: url("media/Manicule_v01.svg");
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
}

/* recolors the text, hand, and Instagram outline together — .follow-text
   inherits color from here (no color of its own), and both icons use
   fill/stroke="currentColor" so they follow the same switch. */
.follow-link:hover {
  color: var(--link-hover);
}

.instagram-icon {
  width: 30px;
  height: 30px;
  flex-shrink: 0;
}

/* narrow/phone widths — without flex-shrink: 0 above, the row (text +
   hand + icon) could exceed the available width and the flex algorithm
   would shrink every child proportionally, including this icon, making
   it look smaller on phones. Now that it can't shrink, give it a
   touch more size here instead — it's the tap target to Instagram, so
   bigger is better on touch devices. */
@media (max-width: 600px) {
  .instagram-icon {
    width: 34px;
    height: 34px;
  }
}

.reels {
  margin-top: clamp(36px, 8vw, 84px);
}

.reel-block {
  margin-bottom: clamp(48px, 8vw, 96px);
}

.reel-block:last-child {
  margin-bottom: 0;
}

.reel-frame {
  margin: 0 auto;
}

/* single clamp instead of a fluid size + a hard breakpoint override —
   same approach as .info-header above: the vw slope (7.22vw) is chosen
   so it arrives at 32.5px right around 450px on its own, then the
   clamp's own ceiling holds it flat from there — no separate media
   query, no jump. The old 8.18vw actually hit its 18px ceiling at a
   ~220px-wide viewport, well below any real phone, so in practice
   every phone (320px and up) was pinned flat at 18px the whole way to
   450px — the vw component wasn't doing anything on a real device. */
.reel-title {
  font-family: "gandur-new", sans-serif;
  font-weight: 300;
  font-style: normal;
  color: #fff;
  text-align: center;
  margin: clamp(8px, 4vw, 24px) 0 0 0;
  font-size: clamp(24px, 7.22vw, 32.5px);
}

/* very wide displays only — the title moves beside the video instead
   of below it and reads like a museum wall label: left-aligned, capped
   to about 21 characters wide (21ch — 30ch reduced by 30%), and
   bottom-aligned with the video rather than centered on it.
   With 7 reels this needs every video (and every label) lined up in
   its own column down the page — centering each reel-block on its own
   let each row's width drift with that row's title length, so the
   videos zig-zagged instead of stacking straight. Fixed by making
   .reels itself a 2-column grid and turning each .reel-block into
   `display: contents` — its reel-frame and reel-title become direct
   grid children, auto-placed two-per-row, so column 1 (sized off the
   video's own explicit width, identical for every reel) and column 2
   (sized off the widest title, capped at 21ch) are each one consistent
   width shared by all 7 rows.
   The video's own left edge stays where a centered video alone would
   land (same axis as the header, .follow-row, etc.) rather than
   shifting left to center the video+label pair as a unit: .reels'
   explicit width here is set to that same shared reel-frame width
   formula (so column 1 exactly fills it) and centered the usual way
   with margin auto; column 2 doesn't fit inside that width, so the
   label simply overflows past the box's right edge (default
   overflow: visible) instead of pulling the video leftward to make
   room for it. margin-bottom restores the gap to .body-copy below
   that .reel-block's own margin (inert once it's display: contents)
   would otherwise have provided. Scoped to .staging-page so /info's
   own reel-title use, if any, is untouched. */
@media (min-width: 1200px) {
  .staging-page .reels {
    display: grid;
    grid-template-columns: max-content max-content;
    column-gap: clamp(16px, 3vw, 32px);
    row-gap: clamp(48px, 8vw, 96px);
    width: min(
      calc(var(--media-height) * var(--media-ratio-num)),
      calc(100vw - 2 * var(--page-pad))
    );
    margin-left: auto;
    margin-right: auto;
    margin-bottom: clamp(48px, 8vw, 96px);
  }

  .staging-page .reel-block {
    display: contents;
  }

  .staging-page .reel-title {
    display: flex;
    align-items: baseline;
    align-self: end;
    text-align: left;
    max-width: 21ch;
    margin: 0 0 24px 0;
  }

  /* splits the numeral ("I.&nbsp;&nbsp;&nbsp;") from the title text so a
     wrapped second or third line indents to where the title itself
     starts, not back out to the numeral's left edge. .reel-num is a
     fixed-width flex item (its own content, numeral + trailing nbsp
     gap); .reel-title-text is the flexible item that wraps within
     whatever width is left inside .reel-title's 21ch cap — since that's
     its own box, every wrapped line of it starts at that same left
     edge. min-width: 0 lets it actually wrap instead of overflowing
     (flex items default to a min-width equal to their content). */
  .staging-page .reel-num {
    flex: 0 0 auto;
  }

  .staging-page .reel-title-text {
    flex: 1 1 auto;
    min-width: 0;
  }
}

/* the shared .reel-frame width formula above assumes the asymmetric
   left-justified page padding used on /info; the staging page's padding
   is symmetric, so recompute the viewport-based cap to match it */
@media (min-width: 900px) {
  .staging-page .reel-frame {
    width: min(
      calc(var(--media-height) * var(--media-ratio-num)),
      calc(100vw - 2 * var(--page-pad))
    );
  }
}

.staging-page .body-copy {
  margin: 0 auto;
}

.signup {
  margin-top: clamp(48px, 8vw, 96px);
}

.signup-text {
  font-family: "neue-haas-grotesk-text", sans-serif;
  font-weight: 400;
  font-style: normal;
  font-size: 12px;
  line-height: 1.5;
  color: #fff;
  margin: 0 0 16px 0;
}

.signup-form {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: center;
}

.signup-form input[type="email"] {
  font-family: "neue-haas-grotesk-text", sans-serif;
  font-weight: 400;
  font-style: normal;
  font-size: 12px;
  line-height: 1.5;
  color: #fff;
  background: #000;
  border: 1px solid #fff;
  padding: 10px 12px;
  min-width: 220px;
  appearance: none;
  border-radius: 0;
}

.signup-form input[type="email"]::placeholder {
  font-family: "neue-haas-grotesk-text", sans-serif;
  color: rgba(255, 255, 255, 0.6);
}

.signup-form button {
  font-family: "neue-haas-grotesk-text", sans-serif;
  font-weight: 400;
  font-style: normal;
  font-size: 12px;
  line-height: 1.5;
  color: #000;
  background: #fff;
  border: 1px solid #fff;
  padding: 10px 20px;
  cursor: pointer;
  appearance: none;
  border-radius: 0;
}

.signup-form button:hover {
  background: var(--link-hover);
  border-color: var(--link-hover);
  color: #fff;
}

.mute-toggle {
  position: fixed;
  right: clamp(16px, 4vw, 32px);
  bottom: clamp(16px, 4vw, 32px);
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  cursor: pointer;
  z-index: 1000;
  background: none;
  border: none;
  padding: 0;
}

.mute-toggle:hover {
  opacity: 0.7;
}

.mute-toggle svg {
  width: 26px;
  height: 26px;
  display: block;
}

.mute-toggle .icon-off {
  display: none;
}

.mute-toggle[data-muted="true"] .icon-on {
  display: none;
}

.mute-toggle[data-muted="true"] .icon-off {
  display: block;
}


