/* ============================================================
   WEST OF SPADINA — shared styles
   ============================================================ */

@font-face {
  font-family: "Neue Bit";
  src: url("../assets/fonts/NeueBit-Bold.otf") format("opentype");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Helvetica LT Std";
  src: url("../assets/fonts/Helvetica LT Std/HelveticaLTStd-Roman.otf") format("opentype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Helvetica LT Std";
  src: url("../assets/fonts/Helvetica LT Std/HelveticaLTStd-Bold.otf") format("opentype");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

:root {
  --pink: #ff3ec4;
  --pink-deep: #e0189f;
  --yellow: #ffe400;
  --black: #111111;
  --cream: #f8f4ee;
  --white: #ffffff;

  --font-body:
    -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
    "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-accent: "Neue Bit", var(--font-body);

  --container: 1240px;
  --nav-h: 130px;

  --ease-smooth: cubic-bezier(0.22, 1, 0.36, 1);
}

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: auto;
  scrollbar-gutter: stable;
  overflow-y: scroll;
}

body {
  margin: 0;
  background-color: var(--cream);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-repeat: repeat;
  background-size: 220px 220px;
  color: var(--black);
  font-family: var(--font-body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

/* Fixed to the viewport bottom (not the document), invisible in
   normal use since the opaque footer sits directly on top of it --
   only shows up during mobile Safari's elastic overscroll, where it
   keeps the reveal-past-the-end yellow (matching the footer) instead
   of flashing the page's own cream background. */
body::after {
  content: "";
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  height: 200px;
  z-index: -10;
  background: rgb(255, 228, 0);
  pointer-events: none;
}

img {
  max-width: 100%;
  display: block;
}

a {
  color: inherit;
  text-decoration: none;
}

.container {
  width: 100%;
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 24px;
}

.eyebrow {
  font-family: var(--font-accent);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-size: clamp(1rem, 1.4vw, 1.25rem);
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 18px;
  padding: clamp(12px, 1.6vw, 18px) clamp(40px, 5vw, 60px);
  border-radius: 999px;
  border: none;
  background: var(--black);
  color: var(--white);
  font-family: var(--font-accent);
  font-weight: 700;
  font-size: clamp(1.3rem, 2vw, 1.7rem);
  line-height: 1;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  cursor: pointer;
  /* Neue Bit only ships one weight -- thickened with a stroke instead
     of a heavier font file, same technique used elsewhere on site. */
  -webkit-text-stroke: 0.8px currentColor;
  text-shadow: 0.3px 0 currentColor, -0.3px 0 currentColor;
}

.btn--yellow {
  background: var(--yellow);
  border-color: var(--black);
  color: var(--black);
}

.btn--pink {
  background: var(--pink);
  border-color: var(--black);
  color: var(--white);
}

.btn--yellow-pink {
  background: var(--yellow);
  border-color: var(--black);
  color: var(--black);
  /* Less bold than the base .btn -- drop its stroke-based thickening. */
  -webkit-text-stroke: 0;
  text-shadow: none;
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.18);
}

/* The arrow itself is drawn from two bars (like the +/- toggle
   elsewhere on the site) rather than relying on the "→" glyph text --
   Neue Bit doesn't have its own arrow character, so that glyph was
   rendering thin in a fallback font instead of the bold, chunky look
   the rest of the site's icons have. */
.btn__arrow {
  position: relative;
  display: inline-flex;
  flex-shrink: 0;
  align-self: center;
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
  background: var(--black);
  color: var(--yellow);
  transition: color 0.4s var(--ease-smooth);
  font-size: 0;
  /* .btn's horizontal padding is larger than its vertical padding, so
     the circle sat with a bigger gap to the button's right edge than
     it has above/below. Pulling it in by that difference made the
     rectangular gap exactly equal on all three sides (confirmed via
     getBoundingClientRect: 26px/26px/26px) -- but it still visibly
     read as tighter on the right, because the pill's end is a curve,
     not a flat edge like the top/bottom: equal straight-line padding
     against a curved boundary looks smaller than the same padding
     against a flat one. The extra +8px is a purely optical
     correction, not a real measurement. */
  margin-right: calc(clamp(12px, 1.6vw, 18px) - clamp(40px, 5vw, 60px) + 8px);
}

.btn__arrow::before,
.btn__arrow::after {
  content: "";
  position: absolute;
  background: currentColor;
}

.btn__arrow::before {
  top: 50%;
  left: 33%;
  width: 32%;
  height: 2px;
  transform: translateY(-50%);
}

.btn__arrow::after {
  top: 50%;
  right: 33%;
  width: 7px;
  height: 7px;
  border-top: 2px solid currentColor;
  border-right: 2px solid currentColor;
  background: transparent;
  transform: translateY(-50%) rotate(45deg);
}

.btn--outline {
  background: transparent;
  border-color: var(--black);
  color: var(--black);
}

.btn--outline.on-dark {
  border-color: var(--white);
  color: var(--white);
}

/* ---------------- NAV ---------------- */

.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  height: var(--nav-h);
  display: flex;
  align-items: center;
  background: transparent;
  /* This bar spans the full width even though only the centred
     logo/countdown actually sits in it -- without this, the empty
     space to either side still captured clicks/taps meant for
     whatever's scrolled underneath (e.g. a card's +/- toggle passing
     behind the nav). Re-enabled on the actual interactive content
     below. */
  pointer-events: none;
}

.nav__logo,
.nav__burger,
.nav__links {
  pointer-events: auto;
}

/* Progressive blur/fade to white behind the nav, so the logo and
   countdown stay readable over whatever's scrolling underneath
   without needing a hard-edged solid bar. Extends a bit past the
   nav's own height (bottom: -50%) for a softer falloff, and the
   mask-image fades the blur itself out (not just the white tint) —
   without it, backdrop-filter would cut off sharply at the gradient's
   edge instead of tapering away. Chains the #nav-glass-warp SVG
   filter (feTurbulence + feDisplacementMap, defined inline near the
   top of the body) after the blur so the backdrop is gently refracted
   -- not just softened -- for a "liquid glass" look rather than flat
   frosted glass. The -webkit- fallback drops the warp (Safari's
   backdrop-filter doesn't reliably apply SVG filter references), so
   it degrades to plain blur there instead of losing the blur too. */
.nav::before {
  content: "";
  position: absolute;
  inset: 0;
  bottom: -50%;
  z-index: -1;
  backdrop-filter: blur(8px) url(#nav-glass-warp);
  -webkit-backdrop-filter: blur(8px);
  background: linear-gradient(
    to bottom,
    rgba(255, 255, 255, 0.45) 0%,
    rgba(255, 255, 255, 0.05) 45%,
    rgba(255, 255, 255, 0) 100%
  );
  mask-image: linear-gradient(to bottom, black 0%, black 45%, transparent 100%);
  -webkit-mask-image: linear-gradient(to bottom, black 0%, black 45%, transparent 100%);
  pointer-events: none;
}

.nav__inner {
  position: relative;
  width: 100%;
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 24px;
  display: flex;
  align-items: center;
  justify-content: flex-end;
}

/* Logo + countdown stacked as one unit, centered in the nav. */
.nav__center {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
}

.nav__logo img {
  height: clamp(42px, 4.2vw, 60px);
  width: auto;
}

/* Plain black — legible over every section the nav can be pinned
   above now that the progressive blur/fade (see .nav::before above)
   always lightens whatever's directly behind it, rather than the pink
   used in the (now-removed) hero countdown or the old black/white
   swap this used to need. */
.nav__countdown {
  display: flex;
  align-items: baseline;
  gap: clamp(10px, 1.6vw, 20px);
  color: var(--black);
}

.nav__countdown-item {
  display: flex;
  align-items: baseline;
  gap: 4px;
}

.nav__countdown-item strong {
  font-family: var(--font-accent);
  font-weight: 900;
  font-size: clamp(1.1rem, 2vw, 1.9rem);
  color: inherit;
}

.nav__countdown-item span {
  font-family: var(--font-accent);
  font-weight: 700;
  font-size: clamp(0.6rem, 0.8vw, 0.8rem);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  opacity: 0.6;
  color: inherit;
}

@media (max-width: 720px) {
  .nav__countdown-item span {
    display: none;
  }

  /* Nav no longer shows anything on mobile -- the logo is redundant
     with the WOS bubble graphic filling the hero right below it, and
     the countdown moves into the hero itself (.hero__countdown below)
     so it scrolls away with the page instead of staying fixed. */
  .nav__logo,
  .nav__countdown {
    display: none;
  }

  .nav::before {
    display: none;
  }
}

.nav__links {
  display: flex;
  align-items: center;
  gap: 32px;
  font-family: var(--font-accent);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-size: 0.95rem;
}

.nav__links a:not(.btn) {
  position: relative;
  padding: 4px 0;
  color: var(--black);
  transition: color 0.3s ease;
}

.nav__links a:not(.btn)::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -2px;
  height: 2px;
  background: transparent;
}

.nav__links a:not(.btn):hover::after {
  background: var(--pink);
}

.nav__links .btn {
  padding: 10px 22px;
  font-size: 0.85rem;
}

.nav__burger {
  display: none;
  width: 40px;
  height: 40px;
  border: none;
  background: transparent;
  cursor: pointer;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
}

.nav__burger span {
  display: block;
  height: 2px;
  background: var(--black);
  border-radius: 2px;
  transition: background 0.3s ease;
}

/* ---------------- LANDING BACKDROP ---------------- */

.landing-backdrop {
  position: relative;
  z-index: 10;
  overflow: hidden;
}

.landing-backdrop::before {
  content: "";
  position: absolute;
  inset: -30px;
  z-index: 0;
  background-image: url("../assets/img/backdrop-landing-baked.webp");
  background-repeat: no-repeat;
  background-position: center top -200px;
  background-size: cover;
  transform: scale(1.05);
}

.intro-backdrop {
  position: relative;
  overflow: visible;
  aspect-ratio: 2642 / 1760;
  margin-top: -175px;
  display: flex;
  align-items: center;
  /* Higher than .landing-backdrop's own z-index: 10 -- that's a
     separate stacking context wrapping the hero's WOS graphic and
     countdown, and now that this pulls up further into its territory
     on mobile (see the 900px breakpoint), it needs to paint above
     that whole context or the hero's higher-z-index content shows
     through on top of the intro copy instead of behind it. */
  z-index: 20;
}

.intro-backdrop::before {
  content: "";
  position: absolute;
  inset: -30px;
  z-index: 0;
  background-image: url("../assets/img/backdrop-landing-baked.webp");
  background-repeat: no-repeat;
  background-position: center top;
  background-size: 100% auto;
  transform: scale(1.05) scaleY(-1);
}

.event-stack {
  position: relative;
  /* Higher than .intro-backdrop's own z-index: 20 (bumped there to
     clear .landing-backdrop above it) -- otherwise the intro's splash
     backdrop paints over the card stack wherever they overlap.
     (This used to be scoped as `.intro-backdrop + .event-stack`, an
     adjacent-sibling selector that never actually matched -- despite
     appearing next to each other in the markup, .intro-backdrop is
     nested inside .hero-section while .event-stack is that section's
     sibling, not .intro-backdrop's, so they aren't adjacent siblings
     at all and the rule silently never applied.) */
  z-index: 30;
  margin-top: -140px;
}

/* ---------------- HERO (parallax) ---------------- */

.hero {
  position: relative;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  padding: var(--nav-h) 0 60px;
}

.hero__layer {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 100vh;
  z-index: 3;
  transform: translateY(-4vh);
}

/* Desktop keeps the countdown in the fixed nav; mobile moves it here
   instead (see the 720px breakpoint below) so it scrolls away with
   the page rather than staying pinned, sitting above the WOS graphic
   the same way .hero__date sits below it. */
.hero__countdown {
  display: none;
}

/* Entrance sequence: the WOS graphic (this .hero__layer pair) fades
   in first, then everything else (nav + the date/CTA below it) fades
   in a second later -- staggered on purpose so there's a beat for the
   splash backdrop image to actually finish loading in before the
   rest of the page appears on top of it. */
@keyframes page-fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.hero__layer--mid,
.hero__layer--top {
  opacity: 0;
  animation: page-fade-in 0.9s ease forwards;
}

.nav,
.hero__content,
.hero__sticky-cta {
  opacity: 0;
  animation: page-fade-in 0.9s ease forwards;
  animation-delay: 1s;
}

@media (prefers-reduced-motion: reduce) {
  .hero__layer--mid,
  .hero__layer--top,
  .nav,
  .hero__content,
  .hero__sticky-cta {
    opacity: 1;
    animation: none;
  }
}

.hero__layer--mid {
  display: flex;
  align-items: center;
  justify-content: center;
}

.hero__layer--mid img {
  width: min(92vw, 980px, 92vh);
}

.hero__layer--top {
  display: flex;
  align-items: center;
  justify-content: center;
}

.hero__layer--top img {
  width: min(70vw, 700px, 67vh);
  margin-top: 4vh;
}

.hero__content {
  position: relative;
  z-index: 5;
  text-align: center;
  /* Lower than 75vh would sit right under the fixed "Get Tickets"
     button pinned near the bottom of the viewport -- pulled up so the
     date clears it instead of the two overlapping. */
  margin-top: 56vh;
  padding: 0 20px;
}

/* Pinned to the viewport (not the hero) so "Get Tickets" stays
   reachable the whole way down the page, on mobile and desktop alike
   -- rather than only living in the hero, where it'd scroll out of
   reach the moment the intro copy or the card stack comes into view. */
.hero__sticky-cta {
  position: fixed;
  left: 50%;
  bottom: clamp(12px, 2.5vh, 26px);
  transform: translateX(-50%);
  z-index: 90;
  transition: background-color 0.4s var(--ease-smooth);
  padding-top: clamp(20px, 2.4vw, 28px);
  padding-bottom: clamp(20px, 2.4vw, 28px);
  box-shadow: none;
}

/* Swapped in by initStickyCtaContrast() (main.js) whenever the button
   is sitting over a yellow section (Day card, footer) where the
   default yellow button would otherwise disappear into it. */
.hero__sticky-cta--pink {
  background: rgb(255, 87, 251);
}

.hero__sticky-cta--pink .btn__arrow {
  color: rgb(255, 87, 251);
}

.hero__date {
  font-family: var(--font-accent);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-size: clamp(3.2rem, 6.6vw, 4.8rem);
  margin: 0 0 clamp(60px, 10vh, 140px);
}

.hero__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 14px 28px;
  margin-bottom: 30px;
  font-weight: 600;
}

.hero__meta span {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.hero__meta strong {
  font-family: var(--font-accent);
  color: var(--pink-deep);
  letter-spacing: 0.04em;
}

.hero__meta .dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--black);
  opacity: 0.4;
}

.hero__ctas {
  display: flex;
  gap: 16px;
  justify-content: center;
  flex-wrap: wrap;
}

.hero__scroll {
  margin: 40px auto 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  font-family: var(--font-accent);
  font-size: 0.8rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  opacity: 0.65;
}

.hero__scroll .line {
  width: 1px;
  height: 34px;
  background: var(--black);
}

/* ---------------- INTRO ---------------- */

.intro {
  position: relative;
  width: 100%;
  padding: 60px 0 200px;
  text-align: center;
}

.intro > .container {
  position: relative;
  z-index: 1;
}

.intro__meta {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  margin: 0 0 60px;
  font-weight: 700;
  text-transform: uppercase;
  font-size: clamp(0.85rem, 1.6vw, 1.05rem);
  letter-spacing: 0.04em;
}

.intro__meta-row {
  display: flex;
  align-items: center;
  gap: 14px;
  margin: 0;
}

.intro__meta-row--free {
  color: var(--black);
}

.intro__meta-row--paid {
  color: var(--pink);
}

.intro__meta-row .dot {
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.5;
}

.intro__copy {
  max-width: 1200px;
  margin: 0 auto;
  font-family: var(--font-accent);
  font-size: clamp(1.6rem, 5vw, 4.2rem);
  line-height: 1.05;
  color: var(--black);
  opacity: 1;
  text-wrap: balance;
}

/* ---------------- EVENT STACK ---------------- */

.event-stack {
  padding: 40px 0 0;
}

.stack-section {
  position: relative;
  width: 100%;
  overflow: visible;
  /* While the collapsed stack is docked low in the pinned frame (its
     approach state), there's empty space above it before it expands
     to fill the screen. That space used to be invisible when the
     base site color matched the Day card's yellow — now that the
     base is a neutral off-white, the same gap reads as a stark flat
     block instead of blending in. Filling it with the same splash
     texture used above (rather than reverting the base color) keeps
     it looking like the artwork continues through, not a void.
     Cards paint their own opaque backgrounds, so this only shows in
     the gaps around them. */
  background-image: url("../assets/img/backdrop-landing-baked.webp");
  background-repeat: no-repeat;
  background-position: center top;
  background-size: cover;
}

.stack-container {
  width: 100%;
  display: flex;
  flex-direction: column;
  position: relative;
}

.stack-card {
  position: relative;
  width: 100%;
  height: clamp(230px, 30vw, 330px);
  overflow: hidden;
  flex-shrink: 0;
  box-sizing: border-box;
  border-top-left-radius: 20px;
  border-top-right-radius: 20px;
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
  /* Cast a shadow upward onto the card above at the overlap seam. */
  box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.18);
  display: flex;
  flex-direction: column;
  /* Constant — never overridden for .is-expanded — so .bar__inner
     (the text) always sits at the same fixed spot regardless of the
     card's own height, instead of moving as it expands/collapses. */
  justify-content: flex-start;
  transition: height 0.8s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.3s var(--ease-smooth);
}

/* Card 2 (Pink) slides up over Card 1 (Yellow); Card 3 (Tickets)
   slides up over Card 2. Ascending z-index (each later card in front
   of the one before it) so each card's rounded TOP corner — and the
   shadow it casts upward — overhangs the card above it, visible
   rather than tucked underneath.

   Because each card only ever grows downward (pushing later siblings
   further down the flex column; earlier siblings never move), this
   resting order alone is enough for every seam regardless of which
   card is expanded — unlike the bottom-rounded-corner version this
   replaced, no per-card z-index bump is needed on .is-expanded. */
.stack-card:nth-child(1) {
  margin-top: 0;
  z-index: 10;
}

.stack-card:nth-child(2) {
  margin-top: -24px;
  z-index: 20;
}

.stack-card:nth-child(3) {
  margin-top: -24px;
  z-index: 30;
}

.stack-card:nth-child(4) {
  margin-top: -24px;
  z-index: 40;
}

.stack-card.is-expanded {
  height: clamp(600px, 75vw, 860px);
  /* Keeps the same upward seam shadow every card has at rest, plus a
     stronger downward one for the extra elevation while expanded --
     previously this replaced the seam shadow outright, which is why
     it visibly vanished at the top edge once a card grew. */
  box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.18), 0 24px 48px rgba(0, 0, 0, 0.3);
}

/* +/- toggle, corner-pinned on every card. The two bars forming the
   icon are the button's own ::before/::after — the vertical bar
   scales away to 0 on .is-expanded, turning the plus into a minus. */
.bar__toggle {
  position: absolute;
  top: 20px;
  right: 20px;
  z-index: 2;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1.5px solid currentColor;
  background: transparent;
  color: inherit;
  cursor: pointer;
  padding: 0;
}

.bar__toggle::before,
.bar__toggle::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  background: currentColor;
  transform: translate(-50%, -50%);
}

.bar__toggle::before {
  width: 16px;
  height: 2px;
}

.bar__toggle::after {
  width: 2px;
  height: 16px;
  transition: transform 0.3s var(--ease-smooth);
}

.stack-card.is-expanded .bar__toggle::after {
  transform: translate(-50%, -50%) scaleY(0);
}

.hero-section {
  position: relative;
  width: 100%;
  min-height: 100vh;
  /* Bleeds the hero's splash artwork down over the collapsed card
     stack during approach. Deliberately placed here rather than as a
     margin-top on .stack-section (the pinned trigger element) — a
     negative margin on the pin target gets hoisted onto GSAP's
     auto-generated pin-spacer, and that hoist landing in the same
     refresh pass that computes the trigger's start position produced
     a one-frame drift where the section visibly slid before locking
     into place. This achieves the same visual overlap without
     touching the pinned element at all. */
  margin-bottom: -60px;
}

.bar {
  position: relative;
  width: 100%;
}

.bar--free {
  background: rgb(255, 228, 0);
  color: rgb(123, 17, 137);
}

.bar--paid {
  background: rgb(255, 87, 251);
  color: var(--white);
}

/* ---------------- CARD ARTWORK (hover reveal) ----------------
   Sits behind .bar__inner at a low opacity so the card's own colour
   dominates at rest (matching the Figma collapsed variant's faint
   opacity-12 treatment), then fades up to full strength on hover as
   the card itself grows taller — the same illustration/photo, just
   more of it revealed and more vivid. */

.bar__art {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  /* Fixed at roughly half the expanded card height (see
     .stack-card.is-expanded below) rather than stretching to fill the
     whole card — the artwork should read as a banner across the
     bottom, not take over the entire expanded card. Anchored to the
     bottom (rather than the top) so it sits under the title/location
     text, which is now pinned to the top when expanded. */
  height: clamp(260px, 32.5vw, 380px);
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}

/* Night's banner sits lower than Day/Tickets' -- opens up more room
   above it for the lineup rising up from behind it. */
.card--night .bar__art {
  bottom: -60px;
}

.bar__art-img {
  position: absolute;
  top: 0;
  height: 100%;
  object-fit: cover;
  opacity: 0.07;
  transition: opacity 0.5s var(--ease-smooth);
}

.stack-card.is-expanded .bar__art-img {
  opacity: 1;
}

/* Day/Night's pop-art illustrations shrink to fit fully inside their
   half-height banner instead of cropping to fill it (object-fit:
   cover, the default above) -- unlike the Tickets card's video, which
   stays cover so it fills the frame edge-to-edge. */
.bar--free .bar__art-img,
.bar--paid .bar__art-img {
  object-fit: contain;
}

/* Day/Night's artwork scrolls left-right/right-left in step with page
   scroll direction (driven by initCardArtScroll() in main.js), rather
   than sitting static or auto-animating on a timer. The markup
   repeats the image (or image pair, for Day) four times in a row
   inside .bar__art-track, which JS shifts by a fraction of the
   scroll delta each frame — no transform here at rest; the script
   sets it inline. Four repeats (rather than the two a seamless loop
   strictly needs) is a safety margin so there's still enough width to
   cover very wide viewports without a gap showing before the loop
   wraps in either direction. */
.bar--free .bar__art-track,
.bar--paid .bar__art-track {
  display: flex;
  height: 100%;
  width: max-content;
}

.bar--free .bar__art-img,
.bar--paid .bar__art-img {
  position: static;
  height: 100%;
  width: auto;
  max-width: none;
  flex-shrink: 0;
}

.bar__art-img--full {
  left: 0;
  width: 100%;
}

/* Fixed position, same in both collapsed and expanded states — no
   movement, no transition. (A top/transform-based slide between
   "centered at rest" and "pinned at top expanded" was tried, but with
   the card's own height animating at the same time, the text's
   position was fighting two moving references at once and visibly
   dipped down then back up instead of moving in one direction.) */
.bar__inner {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 10px;
  /* Now that the location(s) live in their own corner-pinned pill
     stack rather than stacked under the title here, the title alone
     sits closer to the top than reads as centred in the collapsed
     card -- extra top padding nudges it down. */
  padding: clamp(90px, 11vw, 130px) clamp(48px, 14vw, 220px) clamp(32px, 5vw, 64px);
  width: 100%;
  text-align: center;
}

/* Corner-pinned on the left, mirroring .bar__toggle on the right —
   same 40px diameter/height so the two line up. */
.bar__pill {
  position: absolute;
  top: 20px;
  left: 20px;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 40px;
  padding: 0 20px;
  margin: 0;
  border-radius: 999px;
  border: 1.5px solid currentColor;
  font-family: var(--font-accent);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-size: clamp(0.95rem, 1.45vw, 1.15rem);
  line-height: 1;
  white-space: nowrap;
  opacity: 0.9;
}

/* Header label, centred between the time pill (left) and the
   +/- toggle (right) -- only appears once the card is expanded rather
   than sitting there at rest alongside the collapsed title. */
.bar__eyebrow {
  position: absolute;
  top: 20px;
  left: 0;
  right: 0;
  z-index: 2;
  text-align: center;
  margin: 0;
  font-family: var(--font-accent);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: clamp(0.95rem, 1.45vw, 1.15rem);
  line-height: 40px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.5s var(--ease-smooth);
}

.stack-card.is-expanded .bar__eyebrow {
  opacity: 0.9;
}

/* Stacked left-aligned pills directly under the time/date pill, on
   every viewport -- not part of the centred title block at all. */
.bar__locations {
  position: absolute;
  top: 72px;
  left: 20px;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
}

.bar__location-pill {
  display: inline-flex;
  align-items: center;
  height: 36px;
  padding: 0 16px;
  border-radius: 999px;
  border: 1.5px solid currentColor;
  font-family: var(--font-accent);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  font-size: clamp(0.85rem, 1.1vw, 1rem);
  line-height: 1;
  opacity: 0.95;
  white-space: nowrap;
}

/* At rest the artwork sits at 12% opacity, so the card's own solid
   colour already keeps the text legible. Expanded, the artwork goes
   to full strength and can get busy right behind the text — this
   scrim (each card's own colour, fading downward into the art below)
   keeps the title/location readable without flattening the reveal
   underneath it. */
.bar__inner::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  opacity: 0;
  transition: opacity 0.5s var(--ease-smooth);
}

/* Titles now fade out on expand (see .stack-card.is-expanded
   .bar__title above), so this scrim -- originally there just to keep
   the title readable over the artwork -- no longer has anything left
   to protect, and was showing through as a stray colour wash (e.g.
   pink over Night's lineup). Left at opacity: 0 in both states. */

.bar--free .bar__inner::before {
  background: linear-gradient(to bottom, rgba(255, 228, 0, 0.94), rgba(255, 228, 0, 0) 100%);
}

.bar--paid .bar__inner::before {
  background: linear-gradient(to bottom, rgba(255, 87, 251, 0.94), rgba(255, 87, 251, 0) 100%);
}

.bar--tickets .bar__inner::before {
  background: linear-gradient(to bottom, rgba(40, 6, 40, 0.9), rgba(40, 6, 40, 0) 100%);
}

.bar__title {
  font-family: var(--font-accent);
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.01em;
  font-size: clamp(2.8rem, 5vw, 4.6rem);
  line-height: 0.92;
  text-align: center;
  margin: 0;
  -webkit-text-stroke: 0.4px currentColor;
  text-shadow: 0.15px 0 currentColor, -0.15px 0 currentColor;
  transition: opacity 0.4s var(--ease-smooth);
}

/* Hides every card's title once expanded, handing the space over to
   whatever's revealed underneath (lineup, artwork, video, or the map
   legend/image). */
.stack-card.is-expanded .bar__title {
  opacity: 0;
}

/* Night's lineup -- positioned behind the pop-art banner (lower
   z-index than .bar__art) and anchored from the card's TOP edge
   (which never moves -- cards only ever grow downward) rather than
   its bottom. Anchoring from the bottom instead would tie its
   position to the same edge .bar__art is pinned to, which drags
   downward as the card's height animates open -- since that downward
   drag is much bigger than the lineup's own reposition, it visibly
   slid down instead of up. Anchored from the stationary top, its
   `top` transition is the only motion, so it cleanly rises while the
   bottom-pinned artwork is carried down by the same height change. */
.bar__lineup {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(clamp(600px, 75vw, 860px) - clamp(260px, 32.5vw, 380px) + 120px);
  z-index: -1;
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0;
  font-family: var(--font-accent);
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: -0.02em;
  font-size: clamp(4.6rem, 9.4vw, 8rem);
  line-height: 0.68;
  text-align: center;
  /* Neue Bit only ships one weight -- thickened with a stroke instead
     of a heavier font file, same technique used on .bar__title. */
  -webkit-text-stroke: 0.6px currentColor;
  text-shadow: 0.2px 0 currentColor, -0.2px 0 currentColor;
  opacity: 0;
  transition: opacity 0.6s var(--ease-smooth), top 0.8s var(--ease-smooth);
}

.stack-card.is-expanded .bar__lineup {
  top: calc(clamp(600px, 75vw, 860px) - clamp(260px, 32.5vw, 380px) - 310px);
  opacity: 1;
}

.bar__lineup li:not(:first-child) {
  color: #ffe400;
  -webkit-text-stroke-width: 0.3px;
  text-shadow: 0.1px 0 currentColor, -0.1px 0 currentColor;
}

.bar__lineup li:first-child {
  font-size: 1.15em;
  margin-bottom: 0.15em;
}

.bar__lineup li:not(:first-child) {
  font-size: 0.95em;
  margin-top: -0.1em;
}

/* Get Tickets / Event Map swap to their shorter forms (Tickets / Map)
   on narrow cards -- see the 720px breakpoint below. */
.bar__title-short {
  display: none;
}

/* Day's lineup isn't booked yet -- placeholder text filling the same
   empty middle space Night's lineup occupies, revealed on expand the
   same way. */
.bar__coming-soon {
  position: absolute;
  left: 0;
  right: 0;
  top: 35%;
  transform: translateY(-50%);
  z-index: 0;
  margin: 0;
  text-align: center;
  font-family: var(--font-accent);
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.01em;
  font-size: clamp(3.6rem, 7vw, 5.8rem);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.6s var(--ease-smooth);
}

.stack-card.is-expanded .bar__coming-soon {
  opacity: 1;
}

/* ---------------- GET TICKETS CARD ---------------- */

.bar--tickets {
  background: linear-gradient(160deg, #3c0a3c, #7b1189);
  color: var(--white);
}

/* Unlike Day/Night's illustrations, the Tickets card's video is the
   whole point of the reveal — let it fill the full expanded card
   instead of the half-height banner the other two cards use. */
.bar--tickets .bar__art {
  height: 100%;
}

/* Centered over the video, always present -- most visible/usable once
   the card is expanded and the video fills real space, but it's the
   same element at rest too rather than something that pops in only
   on expand. */
.bar__art-cta {
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 1;
  transform: translate(-50%, -50%);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s var(--ease-smooth);
}

.stack-card.is-expanded .bar__art-cta {
  opacity: 1;
  pointer-events: auto;
}

.bar--tickets .bar__art-img--full {
  opacity: 0.35;
}

.stack-card.is-expanded .bar--tickets .bar__art-img--full {
  opacity: 0.8;
}

.bar__title--tickets {
  position: relative;
  z-index: 1;
  text-shadow: 0.3px 0 currentColor, -0.3px 0 currentColor;
}

/* ---------------- SITE MAP CARD ---------------- */

.bar--map {
  background: #ffffff;
  color: #0b0b0b;
  /* Last card in the stack -- nothing below it to overhang, so unlike
     Day/Night/Tickets it also gets rounded bottom corners and a
     downward shadow of its own, on top of the shared upward one at
     its top seam with Tickets. */
  border-bottom-left-radius: 20px;
  border-bottom-right-radius: 20px;
  /* Bigger, darker downward shadow than the other cards get at their
     seams -- this is the one seam that lands over the flat-colour
     footer rather than another card, so it needs to read as a much
     more distinct overhang. */
  box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.18), 0 32px 56px rgba(0, 0, 0, 0.4);
}

/* Same splash artwork used behind the footer, instead of a flat white
   card -- everything else (title, pill, legend, map image) sits above
   it via z-index. */
.bar--map::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  background-image: url("../assets/img/backdrop-landing-baked.webp");
  background-repeat: no-repeat;
  background-position: center bottom;
  background-size: cover;
  /* Scaled up beyond the card's own bounds (clipped by .stack-card's
     overflow: hidden) so the splash bleeds past the edges instead of
     visibly running out right at the card boundary. */
  transform: scale(1.6);
}

.bar--map .bar__pill,
.bar--map .bar__toggle {
  z-index: 3;
}

.bar--map .map-content {
  z-index: 1;
}

/* The centred "Event Map" title stays put across both states -- only
   .map-content (the numbered legend + map image) appears/disappears
   around it, rather than swapping in a second, separate title. */

.map-content {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  align-items: stretch;
  justify-content: space-between;
  gap: clamp(24px, 4vw, 64px);
  padding: clamp(220px, 24vw, 300px) clamp(80px, 12vw, 220px) clamp(32px, 5vw, 80px);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.5s var(--ease-smooth);
}

.bar--map.is-expanded .map-content {
  opacity: 1;
  pointer-events: auto;
  /* The image is bottom/right-anchored inside this flex box, so while
     the card's own height is still animating (0.8s, see .stack-card)
     it visibly slides around under the fade. Waiting for that to
     finish before fading in avoids the zig-zag and lets it appear
     already settled in its final spot. */
  transition-delay: 0.6s;
}

.map-content__legend {
  flex-shrink: 0;
  align-self: flex-start;
  margin-left: clamp(80px, 12vw, 220px);
}

.map-legend {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0;
}

.map-legend li {
  display: flex;
  align-items: center;
  gap: 24px;
  font-family: var(--font-accent);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  font-size: clamp(1.9rem, 2.7vw, 2.5rem);
  white-space: nowrap;
}

.map-legend__pin {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 50px;
  height: 50px;
  border-radius: 50%;
  flex-shrink: 0;
  background: #ffe400;
  border: 4px solid #ff57fb;
  color: #000;
  font-size: 2.3rem;
  font-weight: 900;
}

.map-legend__pin--dark {
  background: #000;
  color: #ffe400;
}

.map-content__img {
  max-width: 88%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  object-position: bottom left;
  border-radius: 24px;
  align-self: flex-end;
  margin-right: clamp(90px, 13vw, 220px);
  margin-top: clamp(20px, 3vw, 50px);
}

.section-head {
  text-align: center;
  max-width: 640px;
  margin: 0 auto 56px;
}

.section-head .eyebrow {
  color: var(--pink-deep);
  margin-bottom: 12px;
}

.section-head h2 {
  font-family: var(--font-accent);
  font-weight: 700;
  text-transform: uppercase;
  font-size: clamp(2.2rem, 5vw, 3.6rem);
  line-height: 0.98;
  margin: 0 0 16px;
}

.section-head p {
  font-size: 1.05rem;
  line-height: 1.6;
  opacity: 0.75;
  margin: 0;
}

/* ---------------- SITE MAP + FOOTER ----------------
   Flat brand yellow instead of the splash texture image -- solid
   colour, no backdrop asset needed. */

.site-footer {
  position: relative;
  width: 100%;
  overflow: hidden;
  color: var(--white);
  background: rgb(255, 228, 0);
  /* Pulled up under the Event Map card's rounded bottom corners/shadow
     (rather than sitting flush beneath it) so the card visibly
     overhangs the footer instead of just meeting it edge-to-edge.
     Deliberately no z-index here -- the Event Map card already has a
     high one (see .stack-card:nth-child(4)) that keeps it above the
     footer where they overlap, and giving the footer its own negative
     z-index put it behind .stack-section's own fading backdrop too,
     letting the page's cream background show through as a stray tan
     band right above the yellow. */
  margin-top: -80px;
  padding-top: 80px;
}

.site-footer__content {
  position: relative;
  z-index: 1;
}

/* Grid rather than flex -- with flex + justify-content: center, the
   whole Partners/logo/Socials group centers as one block, so the logo
   only sits at the midpoint of that block, not the true page centre,
   whenever the two side columns' content widths differ (which they
   do: three partner names vs. three shorter social links). A
   1fr/auto/1fr grid gives both side columns equal, symmetric space no
   matter how much content either holds, so the middle column -- the
   logo -- lands on the actual centre. */
.site-footer__row {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: clamp(24px, 4vw, 64px);
  padding: clamp(140px, 18vw, 220px) clamp(24px, 8vw, 140px);
  text-align: center;
}

.site-footer__col--left {
  text-align: left;
  display: flex;
  gap: clamp(40px, 6vw, 80px);
}

.site-footer__col--left .site-footer__list {
  align-items: flex-start;
}

.site-footer__col--right {
  text-align: right;
}

.site-footer__col--right .site-footer__list {
  align-items: flex-end;
}

.site-footer__heading {
  font-family: var(--font-accent);
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  font-size: clamp(1.1rem, 1.8vw, 1.4rem);
  color: #1a1200;
  margin: 0 0 20px;
}

.site-footer__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.site-footer__list li,
.site-footer__list a {
  font-family: var(--font-accent);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  font-size: clamp(0.9rem, 1.3vw, 1.05rem);
  color: #1a1200;
  opacity: 0.85;
}

.site-footer__list a {
  text-decoration: none;
  transition: opacity 0.2s var(--ease-smooth);
}

.site-footer__list a:hover {
  opacity: 1;
  text-decoration: underline;
}

.site-footer__logo {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.site-footer__logo img {
  width: min(30vw, 260px);
}

/* ---------------- PAGE HERO (Tickets / Program) ---------------- */

.page-hero {
  position: relative;
  padding: calc(var(--nav-h) + 120px) 0 100px;
  text-align: center;
  overflow: hidden;
  background-image: url("../assets/img/backdrop-top.webp");
  background-repeat: no-repeat;
  background-position: top center;
  background-size: 140% auto;
}

.page-hero__eyebrow {
  color: var(--pink-deep);
  margin-bottom: 16px;
}

.page-hero h1 {
  font-family: var(--font-accent);
  font-weight: 700;
  text-transform: uppercase;
  font-size: clamp(3rem, 9vw, 7rem);
  line-height: 0.92;
  margin: 0 0 20px;
}

.page-hero p {
  max-width: 560px;
  margin: 0 auto;
  font-size: 1.1rem;
  line-height: 1.6;
  opacity: 0.75;
}

/* FAQ */

.faq {
  padding: 20px 0 120px;
}

.faq-list {
  max-width: 780px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.faq-item {
  border: 2px solid var(--black);
  border-radius: 18px;
  overflow: hidden;
  background: var(--white);
}

.faq-item__q {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 22px 26px;
  background: none;
  border: none;
  cursor: pointer;
  text-align: left;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 1.05rem;
}

.faq-item__q .plus {
  font-family: var(--font-accent);
  font-size: 1.6rem;
  flex-shrink: 0;
}

.faq-item.is-open .plus {
  transform: rotate(45deg);
}

.faq-item__a {
  max-height: 0;
  overflow: hidden;
}

.faq-item__a p {
  margin: 0;
  padding: 0 26px 24px;
  line-height: 1.6;
  opacity: 0.78;
}

/* ---------------- PROGRAM PAGE ---------------- */

.schedule {
  padding: 20px 0 100px;
}

.schedule-block {
  max-width: 900px;
  margin: 0 auto 60px;
  border: 3px solid var(--black);
  border-radius: 26px;
  overflow: hidden;
}

.schedule-block__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 14px;
  padding: 28px 34px;
  font-family: var(--font-accent);
  text-transform: uppercase;
}

.schedule-block--festival .schedule-block__head {
  background: var(--yellow);
  color: var(--black);
}

.schedule-block--party .schedule-block__head {
  background: var(--pink);
  color: var(--white);
}

.schedule-block__head h3 {
  font-size: clamp(1.8rem, 3.4vw, 2.6rem);
  margin: 0;
}

.schedule-rows {
  background: var(--white);
}

.schedule-row {
  display: flex;
  align-items: center;
  gap: 24px;
  padding: 20px 34px;
  border-top: 1px solid rgba(17, 17, 17, 0.12);
}

.schedule-row__time {
  font-family: var(--font-accent);
  font-weight: 700;
  min-width: 130px;
  color: var(--pink-deep);
}

.schedule-row__info strong {
  display: block;
  font-size: 1.05rem;
  margin-bottom: 2px;
}

.schedule-row__info span {
  font-size: 0.9rem;
  opacity: 0.65;
}

.sitemap {
  padding: 20px 0 120px;
}

.sitemap-diagram {
  max-width: 900px;
  margin: 0 auto;
  border: 3px solid var(--black);
  border-radius: 28px;
  padding: 28px;
  background: var(--white);
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: 110px 110px 90px 90px;
  grid-template-areas:
    "entry stage stage"
    "market market seating"
    "market market info"
    "block block block";
  gap: 12px;
}

.zone {
  border: 2px solid var(--black);
  border-radius: 16px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  font-family: var(--font-accent);
  text-transform: uppercase;
  letter-spacing: 0.02em;
  gap: 4px;
  padding: 10px;
}

.zone span {
  font-family: var(--font-body);
  font-weight: 600;
  text-transform: none;
  font-size: 0.78rem;
  opacity: 0.6;
  letter-spacing: 0;
}

.zone--stage {
  grid-area: stage;
  background: var(--pink);
  color: var(--white);
}

.zone--entry {
  grid-area: entry;
  background: var(--black);
  color: var(--white);
}

.zone--market {
  grid-area: market;
  background: var(--yellow);
}

.zone--seating {
  grid-area: seating;
  background: var(--cream);
  border-style: dashed;
}

.zone--block {
  grid-area: block;
  background: var(--black);
  color: var(--white);
}

.zone--info {
  grid-area: info;
  background: var(--cream);
  border-style: dashed;
}

.sitemap-note {
  max-width: 700px;
  margin: 34px auto 0;
  text-align: center;
  font-size: 0.9rem;
  opacity: 0.6;
  line-height: 1.6;
}

/* ---------------- RESPONSIVE ---------------- */

@media (max-width: 900px) {
  .ticket-grid {
    grid-template-columns: 1fr;
  }
  .intro-backdrop::before {
    background-position: center top;
    background-size: cover;
  }
  /* The fixed aspect-ratio is dropped -- it made this box far shorter
     than .intro's own content (several wrapped lines plus its own
     top/bottom padding), and since .intro-backdrop centers that
     content with overflow: visible, the overflow above/below the
     short box wasn't covered by the backdrop image at all, exposing
     the page's plain background there instead. Auto height (matching
     .intro's real height exactly) fixes that.

     -175px (the desktop pull-up) was scaled back here to -60px
     because it used to drag the intro copy into the CTA that lived in
     .hero__content right above it -- but that CTA is a viewport-fixed
     element elsewhere in the DOM now (see .hero__sticky-cta), not a
     sibling here, so that collision risk is gone. Pulled up much
     further instead, closing the visible gap between the hero's own
     backdrop (which fades to plain near its bottom) and this one. */
  .intro-backdrop {
    aspect-ratio: auto;
    margin-top: -260px;
  }
}

@media (max-width: 720px) {
  /* Both layers centre their image in their own full 100vh box, which
     sits lower than it needs to on a narrow/tall mobile viewport where
     there's a lot of empty height above and below. Shifting both up
     together (they need to move as one pair, or the bubble and
     wordmark fall out of alignment with each other) brings the
     graphic closer to the nav instead of sitting mid-screen. */
  .hero__layer--mid,
  .hero__layer--top {
    transform: translateY(-18vh);
  }

  /* Sits above the WOS graphic, roughly the same distance from it as
     .hero__date sits below -- scrolls away with the page instead of
     staying pinned like the old nav countdown did. */
  .hero__countdown {
    position: absolute;
    /* Below the date now, rather than between the wordmark and the
       date. .hero__content's own top offset from #hero is #hero's
       padding-top (var(--nav-h)) plus its own margin-top (25vh, see
       below) -- the previous attempt at this only accounted for the
       25vh and landed ~130px too high, still above the date. Adding
       var(--nav-h) plus enough extra to clear the date's own text
       height puts it below instead. */
    top: calc(var(--nav-h) + 25vh + 100px);
    left: 50%;
    transform: translateX(-50%);
    z-index: 5;
    display: flex;
    align-items: baseline;
    /* Same width as the WEST OF SPADINA wordmark above it (see
       .hero__layer--top img), spread edge-to-edge across it instead
       of a fixed gap between digits. */
    width: min(70vw, 700px, 67vh);
    color: var(--black);
  }

  /* Each number gets an equal-width column (rather than space-between
     on the row, which let a digit going from single to double digits
     push every number after it sideways) so they hold their positions
     as the count ticks down. font-variant-numeric keeps the digits
     themselves from shifting the item's own centre too. */
  .hero__countdown .nav__countdown-item {
    flex: 1;
    justify-content: center;
  }

  .hero__countdown .nav__countdown-item strong {
    font-size: 3.4rem;
    font-variant-numeric: tabular-nums;
  }

  /* The 30vw term barely contributes at narrow widths, so
     .stack-card was pinned to its 230px clamp() minimum on mobile —
     shorter fixed height here instead. */
  .stack-card {
    height: 190px;
  }

  /* Smaller and lower on narrow cards -- the desktop size/position was
     tuned against a wider banner and sat too big and too high,
     crowding the pill/toggle and title above it. */
  .bar__lineup {
    font-size: clamp(2.7rem, 9.8vw, 3.6rem);
  }

  /* Mele's 1.5x/others' 0.75x split (tuned for the desktop banner)
     reads as too extreme a jump on a narrow card -- narrower the gap
     here instead. */
  .bar__lineup li:first-child {
    font-size: 1.15em;
  }

  .bar__lineup li:not(:first-child) {
    font-size: 0.9em;
  }

  .stack-card.is-expanded .bar__lineup {
    top: calc(clamp(600px, 75vw, 860px) - clamp(260px, 32.5vw, 380px) - 210px);
  }

  /* The -60px push used on wider viewports (see .card--night .bar__art
     above) crops too much of the building off the bottom of a short
     mobile viewport -- back to flush with the card's own bottom edge
     here instead. */
  .card--night .bar__art {
    bottom: 50px;
  }

  /* Site Map's legend-beside-image layout doesn't fit a narrow
     viewport -- stack the map on top and the numbered legend below it,
     and let the card grow tall enough (with its own scroll) to hold
     both instead of the fixed desktop expanded height. */
  .bar--map.is-expanded {
    height: min(85vh, 720px);
  }

  /* Signals there's more of the scrollable legend below the fold,
     fading it out under a soft blur instead of cutting it off with a
     hard edge. */
  .bar--map.is-expanded::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 36px;
    z-index: 4;
    pointer-events: none;
    background: linear-gradient(to bottom, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.92));
    backdrop-filter: blur(1.5px);
    -webkit-backdrop-filter: blur(1.5px);
    /* Masks the blur itself so it ramps in gradually top-to-bottom
       (matching the white gradient above it) instead of the flat,
       uniformly-blurred band a plain backdrop-filter produces. */
    mask-image: linear-gradient(to bottom, transparent, black 75%);
    -webkit-mask-image: linear-gradient(to bottom, transparent, black 75%);
    border-bottom-left-radius: 20px;
    border-bottom-right-radius: 20px;
  }

  .map-content {
    flex-direction: column;
    justify-content: flex-start;
    align-items: stretch;
    overflow-y: auto;
    /* Title now fades out on expand (see .stack-card.is-expanded
       .bar__title) rather than staying put, so this no longer needs
       clearance for it -- just enough for the pill/toggle row. */
    padding: 56px 24px 24px;
    gap: 16px;
  }

  .map-content__img {
    order: -1;
    max-height: 34vh;
    max-width: 100%;
    width: 100%;
    align-self: center;
    margin: 0;
    object-position: center;
  }

  .map-content__legend {
    width: 100%;
    margin-left: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
  }

  .map-legend {
    gap: 0;
    align-items: flex-start;
  }

  .map-legend li {
    gap: 16px;
    font-size: 1.55rem;
  }

  .map-legend__pin {
    width: 42px;
    height: 42px;
    border-width: 3px;
    font-size: 1.25rem;
  }

  /* 75vh was tuned against the desktop hero, where the WOS graphic
     fills much more of that space -- on a narrow/tall mobile
     viewport it's comparatively small, leaving a big empty gap before
     the date/CTA below. Pulling this up brings them closer to the
     logo instead of stranding them near the bottom of the screen. */
  .hero__content {
    margin-top: 25vh;
  }

  /* Both were pinned to their clamp() minimums on mobile since the vw
     component barely contributes at narrow widths -- bumped up so
     they read as more substantial on a phone screen. */
  .hero__date {
    font-size: 1.85rem;
  }

  /* The clamp()'s vw term barely contributes at narrow widths, so
     the copy sat near its small end and read as sparse, half-empty
     lines -- bumped up so it wraps into fuller, more substantial
     lines on a phone screen. */
  .intro__copy {
    font-size: 1.95rem;
    line-height: 1;
  }

  .intro {
    padding-top: 20px;
  }

  .hero__sticky-cta {
    padding: 16px 36px;
    font-size: 1.3rem;
    bottom: 16px;
  }

  /* Now that .bar__locations has moved out into its own corner-pinned
     pill stack, .bar__inner only holds the title -- nudge it down from
     the collapsed card's top edge so it reads as vertically centred
     instead of sitting flush against the top padding. */
  .bar__inner {
    padding-top: 60px;
  }

  .bar__title-full {
    display: none;
  }

  .bar__title-short {
    display: inline;
  }

  /* Tighter offsets/sizing to match the smaller pill/card dimensions
     set below for narrow viewports. */
  .bar__locations {
    top: 56px;
    left: 14px;
    gap: 6px;
  }

  .bar__location-pill {
    height: 28px;
    padding: 0 12px;
    font-size: 0.7rem;
  }

  .bar__pill {
    top: 14px;
    left: 14px;
    height: 34px;
    font-size: 0.95rem;
    padding: 0 12px;
  }

  .bar__toggle {
    top: 14px;
    right: 14px;
    width: 32px;
    height: 32px;
  }

  .nav__links {
    position: fixed;
    top: var(--nav-h);
    left: 0;
    right: 0;
    bottom: 0;
    background: var(--cream);
    flex-direction: column;
    justify-content: center;
    gap: 28px;
    font-size: 1.4rem;
    display: none;
  }
  .nav__links.is-open {
    display: flex;
  }
  .nav__burger {
    display: flex;
  }
  .site-footer__row {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 40px;
    padding: 80px 24px;
  }

  .site-footer__logo {
    width: 100%;
  }

  .site-footer__logo img {
    display: block;
    margin: 0 auto;
  }

  .site-footer__col--left,
  .site-footer__col--right {
    text-align: center;
  }

  .site-footer__col--left {
    flex-direction: column;
    gap: 32px;
  }

  .site-footer__col--left .site-footer__list,
  .site-footer__col--right .site-footer__list {
    align-items: center;
  }

  .sitemap-diagram {
    grid-template-columns: 1fr 1fr;
    grid-template-rows: 90px 110px 110px 90px 90px;
    grid-template-areas:
      "entry entry"
      "stage stage"
      "market seating"
      "market info"
      "block block";
  }
}
