/* ============================================================
   HOUSE CIRCUIT — HOME
   Stage (hero with the circuit title + upcoming nights ⇄ The Name,
   crossfading over one wave field), the circuit wrapper, the stop map
   and the ticket rail. The sections below live in home-stops.css.
============================================================ */

/* ------------------------------------------------------------
   STAGE — the hero and The Name share one pinned screen. home.js
   sets, from scroll progress through the stage: --hero-a (hero
   opacity) and --next-a / --next-t (The Name's fade + settle, 0..1).
   Nothing moves up the screen: the layers crossfade (the hero comes
   back on the way up; The Name's settle happens once). The scroll
   length is the crossfade (first 64%, XF_SHARE in home.js) plus a
   hold on The Name. Without motion it is the hero followed by The Name.
------------------------------------------------------------ */
.stage {
  --xf-d: 140svh;   /* scroll length: ~90svh crossfade + ~50svh hold on The Name */
  position: relative;
  background: var(--ink);
  overflow-x: clip;   /* the settle zoom never widens the page (clip keeps sticky working) */
}
.stage-pin { position: relative; }

.motion .stage::after {
  content: '';
  display: block;
  height: var(--xf-d);
}
.motion .stage-pin {
  position: sticky;
  top: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);   /* the ticket rail must not widen the stage */
}
.motion .stage-pin > .hero,
.motion .stage-pin > .stage-next { grid-area: 1 / 1; }

/* The crossfade values are set (home.js) on the layers that use them and
   registered as non-inherited, so a scroll frame restyles those layers,
   not the hero's or The Name's whole contents (unregistered where
   @property isn't supported: still correct, just less economical). */
@property --hero-a { syntax: '<number>'; inherits: false; initial-value: 1; }
@property --next-a { syntax: '<number>'; inherits: false; initial-value: 0; }

/* The crossfading layers get their own compositor layers, so the fade is
   a GPU blend instead of a repaint of the big shadowed title each frame. */
.motion .stage .hero-media { opacity: var(--hero-a, 1); will-change: opacity; }
.motion .stage .hero-inner {
  opacity: var(--hero-a, 1);
  transform: scale(calc(1 - (1 - var(--hero-a, 1)) * 0.04));
  will-change: opacity, transform;
}
.motion .stage-next {
  will-change: opacity, transform;
  opacity: var(--next-a, 0);
  transform: scale(calc(1.05 - 0.05 * var(--next-t, 0)));
  transform-origin: 50% 40%;
}
/* The hidden layer never takes clicks. */
.motion .stage:not(.is-next) .stage-next,
.motion .stage.is-next .hero { pointer-events: none; }

/* The Name's pieces settle in with the fade (scrubbed, reversible). */
.motion .stage-next .xf-1,
.motion .stage-next .xf-3 {
  transform: translate3d(0, calc((1 - var(--next-t, 0)) * 24px), 0);
}
.motion .stage-next .xf-2 .line > span {
  transform: translate3d(0, calc((1 - var(--next-t, 0)) * (70% + var(--i, 0) * 30%)), 0);
}
.motion .stage-next .xf-card {
  --kt: clamp(0, calc(var(--next-t, 0) * 1.6 - var(--k, 0) * 0.2), 1);
  opacity: var(--kt);
  transform: translate3d(0, calc((1 - var(--kt)) * 48px), 0);
}

.stage-next {
  position: relative;
  z-index: 3;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: safe center;   /* never push tall content up under the header */
  padding-top: calc(var(--header-h) + clamp(20px, 4vh, 48px));
  padding-bottom: clamp(32px, 6vh, 64px);
}
html:not(.motion) .stage-next { min-height: 0; }

/* ------------------------------------------------------------
   HERO
------------------------------------------------------------ */
.hero {
  position: relative;
  min-height: max(100svh, 560px);
  overflow: hidden;
  background: var(--ink);
}

.hero-media {
  position: absolute;
  inset: 0;
  z-index: 0;   /* own stacking context: its tint/shade layers stay under the waves */
  transform-origin: 50% 40%;
}
.hero-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
  opacity: 0;
  filter: grayscale(1) contrast(1.2) brightness(0.62);
  transition: opacity 1.4s ease;
}
.hero-video.is-active { opacity: 1; }
.hero-video::-webkit-media-controls { display: none !important; }

/* Duotone: green multiplied over greyscale footage, then shaded. */
.hero-media::before,
.hero-media::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
}
.hero-media::after { z-index: 2; }
.hero-media::before {
  background: linear-gradient(160deg, #39ff7f 0%, #0d6b33 55%, #03170a 100%);
  mix-blend-mode: multiply;
  opacity: 0.85;
}
.hero-media::after {
  background:
    linear-gradient(180deg, rgba(5, 7, 6, 0.55) 0%, rgba(5, 7, 6, 0) 28%, rgba(5, 7, 6, 0.1) 55%, rgba(5, 7, 6, 0.94) 100%),
    linear-gradient(90deg, rgba(5, 7, 6, 0.55) 0%, rgba(5, 7, 6, 0) 60%);
}

/* 3D wave field (waves.js): fills the hero between the video and the
   text. waves.js dims the lines behind every text block, so they never
   compete with the copy. */
.hero-waves {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 1;
  width: 100%;
  height: max(100svh, 560px);
  pointer-events: none;
}

/* Layout: the title and pitch centred on the left; the HCE logo with
   the upcoming nights under it, centred on the right. Phones and
   tablets (<960px): one row of the logo then the title, centred as a
   pair, with the upcoming nights full width under it. */
.hero-inner {
  position: relative;
  z-index: 2;
  min-height: max(100svh, 560px);
  display: grid;
  padding: calc(var(--header-h) + clamp(12px, 3vh, 32px)) var(--gutter) clamp(20px, 4vh, 48px);
}

.hero-main {
  display: grid;
  align-content: center;
  gap: clamp(22px, 4vh, 44px);
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
}
.hero-left {
  display: grid;
  justify-items: center;
  align-content: center;
  gap: clamp(18px, 3vh, 32px);
  text-align: center;
}
.hero-right {
  display: grid;
  justify-items: center;
  align-content: center;
  gap: clamp(12px, 2.4vh, 28px);
  min-width: 0;
}
.hero-upcoming { justify-self: stretch; }   /* phones: a full-width strip (desktop centres it below) */
@media (min-width: 960px) {
  .hero-main {
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
    align-items: center;
    column-gap: clamp(32px, 5vw, 96px);
  }
}
/* The two columns dissolve into one grid: [logo | title] centred by the
   flexible outer tracks, the upcoming nights across all four. The title
   column is exactly the mark's width; --hero-f is set here (the title
   inherits it) from the width left beside the logo, and from the
   height so landscape phones still fit. */
@media (max-width: 959px) {
  .hero-left,
  .hero-right { display: contents; }
  .hero-main {
    --logo-w: clamp(84px, min(30vw, 30svh), 200px);
    --logo-gap: clamp(10px, 3.5vw, 24px);
    --hero-f: clamp(40px, min(calc((100vw - 2 * var(--gutter) - var(--logo-w) - var(--logo-gap)) / 2.94), 17svh), 130px);
    grid-template-columns: 1fr auto minmax(0, calc(var(--hero-f) * 2.94)) 1fr;
    grid-template-areas: ". logo title ." "up up up up";
    align-items: center;
    column-gap: 0;
  }
  .hero-logo { grid-area: logo; margin-right: var(--logo-gap); }
  .hero-main .hero-title { grid-area: title; --hero-f: inherit; --events-min: 11px; }   /* "Events" stays inside the title column */
  .hero-upcoming { grid-area: up; }
}

/* The logo: beside the title on phones, over the upcoming nights on desktop. */
.hero-logo {
  width: var(--logo-w);
  height: auto;
  -webkit-user-select: none;
  user-select: none;
  filter: drop-shadow(0 0 24px rgba(57, 255, 127, 0.35)) drop-shadow(0 2px 12px rgba(0, 0, 0, 0.8));
}
@media (min-width: 960px) {
  .hero-logo { width: auto; height: clamp(110px, 25svh, 320px); }
}

/* Legibility over the moving waves and the video. */
.hero-pitch .lead,
.up-title { text-shadow: 0 2px 24px rgba(0, 0, 0, 0.75), 0 0 2px rgba(0, 0, 0, 0.6); }

/* The title: "House / Circuit" drawn as a white circuit (.hero-mark: a
   dark body, traces and pads inside the letters, a softly glowing
   edge; green sparks of signal run round it), "Events" under it. --hero-f is the size the name would have
   as type; the mark is sized from it (its 500×290 viewBox holds two
   lines of 170-unit caps), so the layout scales exactly as before. */
.hero-title {
  --hero-f: clamp(56px, min(21vw, 15svh), 300px);
  display: grid;
  justify-self: stretch;   /* full column width: the mark sizes from it */
  justify-items: center;
  margin: 0;
  font-size: var(--hero-f);
  line-height: 1;
}
@media (min-width: 960px) {
  .hero-title { --hero-f: clamp(80px, min(13.5vw, 26svh), 340px); }
}
.hero-mark {
  position: relative;
  display: block;
  width: min(100%, calc(var(--hero-f) * 2.94));
  aspect-ratio: 500 / 290;
}
.hero-mark svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}
.hm-base { filter: drop-shadow(0 2px 18px rgba(0, 0, 0, 0.7)); }
.hm-spark { will-change: transform; pointer-events: none; }   /* own layer: only the sparks repaint */
.hm-text {
  font-family: var(--f-display);
  font-weight: 900;
  font-size: 170px;
}
.hm-pour { fill: rgba(8, 12, 10, 0.72); }
.hm-traces { fill: url(#hm-traces); }
.hm-copper { fill: none; stroke: rgba(233, 243, 236, 0.5); stroke-width: 1.6; stroke-linejoin: round; }
.hm-via { fill: none; stroke: rgba(233, 243, 236, 0.6); stroke-width: 1.6; }
.hm-pad { fill: rgba(233, 243, 236, 0.72); }
.hm-edge {
  fill: none;
  stroke: var(--text);
  stroke-width: 2.2;
  stroke-linejoin: round;
  filter: drop-shadow(0 0 6px rgba(233, 243, 236, 0.35));
}
.hm-pulse { fill: none; }   /* motion only (below) */

/* Load-in: the body fades up, the copper edge draws itself in, the
   traces light, then sparks of signal run round the letters. The
   sparks pause once The Name has taken over or the hero is off screen
   (.is-offscreen, site.js). The sparks are signal green, so they read
   against the white edge. */
.motion .hm-pour { animation: hm-fade 0.8s ease 0.1s both; }
.motion .hm-edge { animation: hm-draw 2.4s var(--ease-in-out) 0.15s backwards; }
.motion .hm-traces { animation: hm-fade 1.4s ease 1.1s both; }
.motion .hm-pulse {
  stroke: var(--signal);
  stroke-width: 2.6;
  stroke-linecap: round;
  stroke-dasharray: 10 250;
  animation: hm-fade 0.8s ease 2.4s both, hm-pulse 3.2s linear infinite;
}
.motion .stage.is-next .hm-pulse { animation-play-state: paused; }
/* The dash exists only while the edge draws in (fill-mode backwards):
   left on, WebKit (iPhone), which dashes text outlines differently from
   Chrome, showed gaps in the longer letter outlines. */
@keyframes hm-draw {
  from { stroke-dasharray: 720; stroke-dashoffset: 720; }
  to   { stroke-dasharray: 720; stroke-dashoffset: 0; }
}
@keyframes hm-fade {
  from { opacity: 0; }
}
@keyframes hm-pulse {
  to { stroke-dashoffset: -260; }
}
/* "Events": a wide-tracked mono line under the name, scaled with it,
   between two signal lines. */
.hero-events {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.55em;
  margin-top: 0.34em;
  font-family: var(--f-mono);
  font-size: max(var(--events-min, 16px), 0.17em);
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0.6em;
  text-transform: uppercase;
  color: var(--text);
}
.hero-events::before,
.hero-events::after {
  content: '';
  width: 2.2em;
  height: 2px;
  background: var(--signal);
  box-shadow: 0 0 12px var(--signal-glow);
}
.hero-events::after { margin-left: -0.6em; }   /* the tracking after the last letter */

.hero-pitch { display: grid; justify-items: center; max-width: 520px; }
.hero-pitch .lead { font-size: clamp(17px, 1.3vw, 22px); color: var(--text); }
@media (max-width: 959px) {
  .hero-pitch { display: none; }   /* phones: the tickets take the room */
}

/* Upcoming nights inside the hero. Desktop: a window one ticket wide,
   centred in its column (the arrows page through the rest). Phones: a
   full-width swipe strip. */
.hero-upcoming { display: grid; gap: 12px; min-width: 0; }
.up-head { display: flex; align-items: center; justify-content: space-between; gap: 12px 20px; }
.up-title { color: var(--text); }
.hero-upcoming .rail-controls { margin-top: 0; }
.hero-upcoming .rail-btn { width: 42px; height: 42px; font-size: 16px; background: rgba(5, 7, 6, 0.6); }
.hero-upcoming .rail {
  --poster-h: clamp(128px, 24svh, 300px);
  grid-auto-columns: min(calc(var(--poster-h) * 0.8 + 220px), 86vw);
  justify-content: safe center;   /* one or two nights sit centred; more scroll from the start */
  padding-bottom: 12px;
}
@media (min-width: 960px) {
  .hero-upcoming {
    --poster-h: clamp(150px, 26svh, 330px);
    --card-w: calc(var(--poster-h) * 0.8 + 240px);
    justify-self: center;
    width: min(100%, var(--card-w));
  }
  .hero-upcoming .rail {
    --poster-h: inherit;
    grid-auto-columns: min(var(--card-w), 100%);
    margin-inline: 0;
    padding-inline: 0;
    scroll-padding-inline: 0;
  }
  .hero-upcoming:has(.empty) { width: min(100%, 560px); }
}
/* Near-opaque instead of a backdrop blur: the waves under them change
   every frame, and a blur would be recomputed every frame too. */
.hero-upcoming .ticket,
.hero-upcoming .empty { background: rgba(10, 14, 12, 0.9); }
.hero-upcoming .empty { max-width: 560px; justify-self: center; justify-items: center; text-align: center; }

/* Short phones: everything still fits one screen. */
@media (max-width: 959px) and (max-height: 720px) {
  .hero-inner {
    padding-top: calc(var(--header-h) + 10px);
    padding-bottom: 14px;
  }
  .hero-main { gap: 12px; }
  .hero-upcoming { gap: 8px; }
  .hero-upcoming .rail { --poster-h: 118px; padding-bottom: 8px; }
  .hero-upcoming .rail-btn { width: 36px; height: 36px; }
}

/* Load-in: pure CSS (no JS needed), only under html.motion. */
.motion [data-intro] {
  animation: intro-rise 1.2s var(--ease-out) both;
}
.motion [data-intro="1"] { animation-delay: 0.1s; }
.motion [data-intro="2"] { animation-delay: 0.22s; }
.motion [data-intro="3"] { animation-delay: 0.5s; }
.motion [data-intro="4"] { animation-delay: 0.62s; }
.motion [data-intro="5"] { animation-delay: 0.78s; }
@keyframes intro-rise {
  from { opacity: 0; transform: translate3d(0, 36px, 0); }
}

/* ------------------------------------------------------------
   THE CIRCUIT — everything after the hero, slid up over it.
------------------------------------------------------------ */
.circuit {
  position: relative;
  z-index: 1;
  background: var(--ink);
}
.circuit > .tape { z-index: 3; }

/* ------------------------------------------------------------
   THE LINE — fixed stop map (desktop). Collapsed to the dots and
   the track so it stays out of the way; hovering it (or tabbing
   into it) slides the labels out over a dark panel. Dots + labels
   are greyed until reached (.is-reached), the current stop glows
   (.is-current), and the track fills between stops (home.js).
------------------------------------------------------------ */
.line-map { display: none; }

@media (min-width: 1100px) {
  .line-map {
    --lm-gap: clamp(26px, 5vh, 48px);
    --lm-row: 26px;
    display: block;
    position: fixed;
    z-index: 40;
    left: clamp(20px, 2.2vw, 40px);
    top: 50%;
    transform: translateY(-50%);
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.45s var(--ease-out), visibility 0s linear 0.45s;
  }
  .line-map.is-shown {
    opacity: 1;
    visibility: visible;
    transition: opacity 0.45s var(--ease-out), visibility 0s;
  }
  .line-map ol {
    position: relative;
    display: grid;
    gap: var(--lm-gap);
  }
  .line-map a {
    display: flex;
    align-items: center;
    gap: 14px;
    min-height: var(--lm-row);
    font-family: var(--f-mono);
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.14em;
    line-height: 1.2;
    text-transform: uppercase;
    white-space: nowrap;
    color: var(--text-3);
    opacity: 0.55;
    transition: color var(--t-mid), opacity var(--t-mid);
  }
  .lm-dot {
    position: relative;
    z-index: 1;
    flex-shrink: 0;
    width: 13px;
    height: 13px;
    border: 1px solid var(--text-3);
    border-radius: 50%;
    background: var(--ink);
    transition: background-color var(--t-mid), border-color var(--t-mid), box-shadow var(--t-mid), transform var(--t-mid) var(--ease-out);
  }
  /* Collapsed: labels take no room and no pointer; open on hover/focus. */
  .lm-label {
    display: inline-block;
    max-width: 0;
    overflow: hidden;
    opacity: 0;
    transform: translate3d(-6px, 0, 0);
    transition: max-width 0.35s var(--ease-out) 0.12s, opacity 0.2s ease, transform 0.35s var(--ease-out);
  }
  .line-map a { gap: 0; transition: color var(--t-mid), opacity var(--t-mid), gap 0.35s var(--ease-out) 0.12s; }
  .line-map:hover a,
  .line-map:focus-within a { gap: 14px; transition-delay: 0s; }
  .line-map:hover .lm-label,
  .line-map:focus-within .lm-label {
    max-width: 16em;
    opacity: 1;
    transform: none;
    transition: max-width 0.4s var(--ease-out), opacity 0.3s ease 0.08s, transform 0.4s var(--ease-out);
  }
  /* The panel behind the open labels */
  .line-map::before {
    content: '';
    position: absolute;
    z-index: -1;
    inset: -18px -22px -18px -16px;
    border: 1px solid var(--line-2);
    background: rgba(5, 7, 6, 0.84);
    -webkit-backdrop-filter: blur(12px);
            backdrop-filter: blur(12px);
    opacity: 0;
    transform: scaleX(0.3);
    transform-origin: left center;
    transition: opacity 0.25s ease 0.1s, transform 0.4s var(--ease-out) 0.1s;
  }
  .line-map:hover::before,
  .line-map:focus-within::before { opacity: 1; transform: none; transition-delay: 0s; }

  /* Track runs from the first dot's centre to the last one's. */
  .lm-track {
    position: absolute;
    left: 6px;
    top: calc(var(--lm-row) / 2);
    bottom: calc(var(--lm-row) / 2);
    width: 1px;
    background: var(--line-2);
  }
  .lm-fill {
    position: absolute;
    inset: 0;
    background: var(--signal);
    box-shadow: 0 0 10px var(--signal-glow);
    transform-origin: top;
    transform: scaleY(var(--lm-p, 0));
  }
  /* The spark rides a full-height carrier moved with a transform (a %
     of its own height = the track's), so the fill never triggers layout. */
  .lm-spark {
    position: absolute;
    left: 0;
    top: 0;
    width: 1px;
    height: 100%;
    transform: translate3d(0, calc(var(--lm-p, 0) * 100%), 0);
    opacity: var(--lm-spark, 0);
  }
  .lm-spark::before {
    content: '';
    position: absolute;
    left: -3px;
    top: -3.5px;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: #e3ffec;
    box-shadow: 0 0 8px #fff, 0 0 18px var(--signal);
  }

  .line-map a.is-reached { color: var(--text-2); opacity: 1; }
  .line-map a.is-reached .lm-dot {
    border-color: var(--signal);
    background: var(--signal);
    box-shadow: 0 0 10px var(--signal-glow);
  }
  .line-map a.is-current { color: var(--signal); }
  .line-map a.is-current .lm-dot { transform: scale(1.35); }
  .line-map a:hover,
  .line-map a:focus-visible { color: var(--text); opacity: 1; }
  .line-map a:hover .lm-dot { border-color: var(--signal); }

  /* Content clears the collapsed map (the open one floats over it). */
  .circuit .wrap,
  .stage-next .wrap { padding-left: max(var(--gutter), 88px); }
}

/* Jump landing (home.js): the target section is shown in its final
   state, no reveal mid-flight. */
.is-instant,
.is-instant * { transition: none !important; }

/* ------------------------------------------------------------
   UPCOMING RAIL (in the hero)
------------------------------------------------------------ */
.rail {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: min(78vw, 300px);
  gap: clamp(14px, 1.6vw, 24px);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: var(--gutter);
  margin-inline: calc(var(--gutter) * -1);
  padding: 4px var(--gutter) 20px;
  scrollbar-width: thin;
  scrollbar-color: var(--signal) var(--ink-3);
}
@media (min-width: 1100px) {
  .rail { margin-inline: 0; padding-inline: 0; scroll-padding-inline: 0; }
}
.rail:focus-visible { outline-offset: -2px; }
.rail-item { scroll-snap-align: start; }
.rail-item .ticket { height: 100%; }

.ticket-poster-empty {
  width: 100%;
  height: 100%;
  display: grid;
  place-items: center;
  background:
    radial-gradient(circle at center, rgba(57, 255, 127, 0.12), transparent 60%),
    repeating-linear-gradient(0deg, transparent 0 23px, var(--line) 23px 24px),
    repeating-linear-gradient(90deg, transparent 0 23px, var(--line) 23px 24px);
}
.ticket-poster-empty img { width: 40%; opacity: 0.8; }

.rail-controls { display: flex; gap: 8px; margin-top: 20px; }
.rail-btn {
  width: 52px;
  height: 52px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line-2);
  border-radius: 50%;
  background: none;
  color: var(--text);
  font-size: 18px;
  transition: border-color var(--t-fast), color var(--t-fast), background-color var(--t-fast);
}
.rail-btn:hover { border-color: var(--signal); color: var(--signal); background: var(--signal-soft); }
.rail-btn:disabled { opacity: 0.3; pointer-events: none; }

.empty {
  display: grid;
  gap: 16px;
  justify-items: start;
  max-width: 560px;
  padding: clamp(28px, 4vw, 48px);
  border: 1px dashed var(--line-2);
}
.empty-line { color: var(--text-2); }

/* Tickets sit sideways (poster beside the details), sized to the
   viewport height so the whole upcoming stop fits one screen. */
.rail {
  --poster-h: clamp(150px, 22svh, 260px);
  grid-auto-columns: min(calc(var(--poster-h) * 0.8 + 220px), 88vw);
}
@media (min-width: 1100px) {
  .rail {
    --poster-h: clamp(220px, 34svh, 340px);
    grid-auto-columns: calc(var(--poster-h) * 0.8 + 250px);
  }
}
.rail .ticket {
  grid-template-columns: calc(var(--poster-h) * 0.8) minmax(0, 1fr);   /* a portrait frame, like most posters */
  grid-template-rows: none;
}
/* Phones: the details take only the width they need (up to 62%) and the
   poster the rest, so narrow cards keep a decent poster. */
@media (max-width: 699px) {
  .rail .ticket { grid-template-columns: minmax(0, 1fr) fit-content(62%); }
}
.rail .ticket-poster {
  height: auto;
  min-height: var(--poster-h);   /* the full card height, even when the details run taller */
  aspect-ratio: auto;
  border-bottom: 0;
  border-right: 1px dashed var(--line-2);
}
/* Pinned to the frame, so the poster's own shape never sets the card height. */
.rail .ticket-poster-img { position: absolute; inset: 0; }
.rail .ticket-poster::before,
.rail .ticket-poster::after { bottom: auto; left: auto; right: calc(var(--notch) / -2 - 1px); }
.rail .ticket-poster::before { top: calc(var(--notch) / -2 - 1px); }
.rail .ticket-poster::after { bottom: calc(var(--notch) / -2 - 1px); }
.rail .ticket-body { align-content: start; grid-template-columns: 1fr; gap: 6px; padding: 18px; }
.rail .ticket-date {
  grid-row: auto;
  justify-self: start;
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 6px 10px;
}
.rail .ticket-date strong { font-size: 26px; }
.rail .ticket-actions { flex-direction: column; margin-top: auto; }
.rail .ticket-body { grid-template-rows: auto auto auto 1fr; }
.rail .ticket-actions .btn { width: 100%; white-space: nowrap; padding-inline: 10px; gap: 6px; }   /* one line, even on narrow phones */
@media (max-width: 420px) {
  .rail .btn-get { display: none; }   /* "Tickets ↗": the narrow details column stays narrow */
}
@media (max-width: 1099px) {
  .rail .ticket-body { padding: 14px; }
  .rail .ticket-title { font-size: clamp(19px, 5vw, 24px); }
}
@media (min-width: 1100px) {
  /* The footer clears the stop map on the home page. */
  .page-home .footer-top,
  .page-home .footer-bottom { padding-left: max(0px, calc(88px - var(--gutter))); }
}

/* Browsers without small-viewport units: the key svh sizes in vh. */
@supports not (height: 1svh) {
  .stage { --xf-d: 140vh; }
  .stage-next { min-height: 100vh; }
  .hero,
  .hero-inner { min-height: max(100vh, 560px); }
  .hero-waves { height: max(100vh, 560px); }
  .hero-title { --hero-f: clamp(56px, min(21vw, 15vh), 300px); }
  .rail { --poster-h: clamp(150px, 22vh, 260px); }
  @media (max-width: 959px) {
    .hero-upcoming .rail { --poster-h: clamp(128px, 24vh, 300px); }
    .hero-main {
      --logo-w: clamp(84px, min(30vw, 30vh), 200px);
      --hero-f: clamp(40px, min(calc((100vw - 2 * var(--gutter) - var(--logo-w) - var(--logo-gap)) / 2.94), 17vh), 130px);
    }
  }
  .track-title { font-size: clamp(19px, min(1.6vw, 3.2vh), 28px); }
  @media (min-width: 960px) {
    .hero-title { --hero-f: clamp(80px, min(13.5vw, 26vh), 340px); }
    .hero-logo { height: clamp(110px, 25vh, 320px); }
    .hero-upcoming { --poster-h: clamp(150px, 26vh, 330px); }
  }
}
