/* ── Full-bleed hero ── */
.home-hero {
  position: relative;
  isolation: isolate;
  /* Opaque ink so the grain overlay blends against the same backdrop on both
     hero halves — without this the ultra-wide split's type column sits on
     transparency and the grain washes it lighter than the photo panel. */
  background: var(--bg);
  height: calc(100vh - var(--header-h));
  /* Don't lower this floor to fit short windows. Letting the hero track the
     window below 620px crops the photo past the point where its focal point
     still reads — the band loses its heads and the frame becomes a strip of
     torsos. A short window scrolls instead; the split layout (below) is what
     keeps the type in view when the window is letterboxed. */
  min-height: 620px;
  /* The flat 920px cap is a laptop-era number: on a 4K desktop it leaves the
     hero a 920px strip across a 2160px window, and `cover` answers that shape
     by fitting the 2400×1600 photo to the width — the whole frame zoomed out,
     band small, stage swallowing it. Letting the cap track width keeps the hero
     a comparable slice of the window at any size. Below 2190px, 42vw is under
     920px and the flat cap still owns it — they meet exactly at the crossover,
     so nothing jumps — and the window's own height still wins over both. */
  max-height: max(920px, 42vw);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  overflow: hidden;
}

/* Full-bleed band photo.
   The image and its focal point arrive as CSS vars from data/hero.toml
   (set inline on the element). `cover` + a percentage position pins the
   focal point to the same relative spot in the frame at every screen size
   and for any image aspect — swap the photo, update the focus, done. */
.home-hero__photo {
  position: absolute;
  inset: 0;
  z-index: -1;
  /* Top/bottom vignette, side edge-fade, radial darken, film grain handled by .grain */
  background:
    /* side edge-fade */
    linear-gradient(
      90deg,
      rgb(var(--bg-rgb) / 0.7) 0%,
      transparent 18%,
      transparent 82%,
      rgb(var(--bg-rgb) / 0.7) 100%
    ),
    /* bottom vignette */
      linear-gradient(to top, var(--bg) 0%, rgb(var(--bg-rgb) / 0.55) 30%, transparent 60%),
    /* top vignette */ linear-gradient(to bottom, rgb(var(--bg-rgb) / 0.5) 0%, transparent 30%),
    /* radial darken center */
      radial-gradient(120% 100% at 50% 50%, transparent 40%, rgb(var(--bg-rgb) / 0.4) 100%),
    var(--hero-image) var(--hero-focus-x, 50%) var(--hero-focus-y, 40%) / cover no-repeat;
  max-width: 2300px;
  margin: 0 auto;
  left: 50%;
  right: auto;
  width: 100%;
  transform: translateX(-50%);
}

/* Default layout: content centered at bottom.
   The bottom padding's floor (4.5rem) is what keeps the third CTA line clear of
   the scroll cue, which is pinned at bottom: 1.6rem + 26px tall: 8vh shrinks with
   the window while the cue does not, so a 3rem floor collided with the booking bar
   below ~730px of window height. Overridden entirely by the ≥1600 split and ≤620
   stacked layouts, both of which drop the cue. */
.home-hero__content {
  position: relative;
  z-index: 2;
  width: min(100%, var(--container));
  padding: 0 var(--gutter) clamp(4.5rem, 8vh, 5rem);
  text-align: center;
}

.home-hero__text {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.home-hero__logo {
  /* Capped so the type block stays below the photo's focal point (the faces)
     on laptop-height screens instead of covering it. */
  width: clamp(260px, 46vw, 720px);
  height: auto;
  filter: drop-shadow(0 0 22px rgb(var(--amber-rgb) / 0.55))
    drop-shadow(0 0 56px rgb(var(--red-rgb) / 0.35));
  animation:
    heroIntro 0.9s ease both,
    glitchTwitch 7s 4s ease-in-out infinite;
}

.home-hero__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.75rem;
  margin-top: 2rem;
  animation: heroIntro 0.9s 0.2s ease both;
}

/* Third CTA line: booking at ghost weight, one step later in the entrance so the
   two buttons land first. Red stays on "Out now" — this reads as meta. */
.home-hero__booking {
  display: flex;
  justify-content: center;
  margin-top: 1.125rem;
  animation: heroIntro 0.9s 0.35s ease both;
}

/* Scroll cue: animated vertical line */
.scroll-cue {
  position: absolute;
  left: 50%;
  bottom: 1.6rem;
  z-index: 2;
  width: 1px;
  height: 26px;
  overflow: hidden;
  background: transparent;
}

.scroll-cue::after {
  content: "";
  position: absolute;
  inset: 0;
  width: 1px;
  background: var(--text-dim);
  border-radius: var(--radius-pill);
  animation: scrollCueSlide 1.8s ease-in-out infinite;
}

/* Short viewports (typical laptops) in the overlay layout: shrink the logo so
   the photo's focal point (the faces) stays clear of the type instead of
   hiding behind it. (The split block below has to come after these so its logo
   width wins where both queries match.) No upper width bound — the overlay now
   runs at every width that isn't letterboxed, so a short-but-wide window needs
   these just as much as a laptop does. */
@media (min-width: 621px) and (max-height: 980px) {
  .home-hero__logo {
    width: clamp(260px, 40vw, 600px);
  }
}

/* The shortest laptops need the logo a notch smaller still */
@media (min-width: 621px) and (max-height: 830px) {
  .home-hero__logo {
    width: clamp(260px, 36vw, 520px);
  }
}

/* ── Editorial split: letterboxed and short windows ── */
/* Two-column row: type lives in the left column, photo fills a bounded right panel.

   This used to fire on `min-width: 1600px` too, on the theory that a wide window has
   room to spare. It does — but two columns cannot overlap, so every pixel of
   breathing room between the type and the photo pushes them further apart, and past
   ~2500px they read as two objects drifting to opposite edges rather than one
   composition. Wide windows take the overlay instead, where the type sits *on* the
   photo and width buys presence rather than distance.

   What is left is the case the overlay cannot do. The hero floors at
   `min-height: 620px`, so once the window is shorter than that plus the 63px header
   it stops shrinking and the overlay's bottom-anchored type falls below the fold.
   The split centres the type beside the photo instead, so the logo and CTAs stay in
   view.

   That is a height question, not an aspect-ratio one. The old trigger was 1.9:1,
   which caught 3440×1440 ultrawides — plenty of height, no problem to solve — while
   a squashed 1600×600 window needed it. The height threshold fires exactly where the
   hero stops fitting and nowhere else. It also keeps the split away from the big
   desktop screens, which is the whole point of the overlay above.

   The 1100px floor keeps the split off windows too narrow to seat the 700px photo
   panel next to a usable type column. */
@media (min-width: 1100px) and (max-height: 683px) {
  .home-hero {
    align-items: stretch;
    justify-content: flex-start;
  }

  /* Half the window, type parked against the seam. `align-items: flex-end` plus the
     padding is what sets the distance between the two: the type block hugs the seam
     and the padding holds it off by a set gap, rather than floating in the middle of
     its half.

     The height is the visible band, not the column's natural full height. The hero
     floors at 620px while these windows may only show 288px of it, so centring the
     block against the hero — the obvious move — drops the CTAs below the fold on
     exactly the windows this block exists to rescue. */
  .home-hero__content {
    order: 0;
    flex: 0 1 auto;
    min-width: 0;
    max-width: none;
    width: 50%;
    height: calc(100vh - var(--header-h));
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: flex-end;
    text-align: left;
    /* The left gutter only bites near 1100px, where the photo's 700px floor squeezes
       this column to ~400px and the type would otherwise sit flush against the window
       edge. Wider than that, the block is right-aligned well clear of it. */
    padding: 0 clamp(4rem, 7vw, 17rem) 0 var(--gutter);
  }

  /* Right-aligned as a block; the type inside it still runs left-to-right off its own
     left edge, so the logo, buttons and booking bar stay flush with each other. */
  .home-hero__text {
    align-items: flex-start;
    max-width: 760px;
  }

  /* Two caps, because two axes run out. max-width (not min(…, 100%) on the width)
     keeps the block hugging its content instead of stretching to the column, which
     would put the logo back adrift; the vh term answers the short axis, which is the
     one that actually ran out here — at 1255×351 there are 288 visible pixels for a
     logo plus two CTA lines, and a 503px logo alone eats 226 of them. */
  .home-hero__logo {
    width: min(clamp(520px, 24vw, 760px), 80vh);
    max-width: 100%;
  }

  .home-hero__actions {
    justify-content: flex-start;
  }

  .home-hero__booking {
    justify-content: flex-start;
  }

  /* Right panel: bounded photo, no longer full-bleed. Takes whatever the type column
     leaves, so the seam sits just past the type at every width — a fixed
     `clamp(700px, 52vw, 1080px)` basis let the two drift apart instead. The 700px
     floor still wins near 1100px, where the column gives way. */
  .home-hero__photo {
    order: 1;
    position: relative;
    inset: auto;
    left: auto;
    right: auto;
    transform: none;
    flex: 1 1 auto;
    min-width: 700px;
    width: auto;
    max-width: none;
    align-self: stretch;
    z-index: 0;
    background:
      /* left edge-fade into ink — wide, multi-stop ramp so the seam dissolves */
      linear-gradient(
        90deg,
        var(--bg) 0%,
        rgb(var(--bg-rgb) / 0.92) 10%,
        rgb(var(--bg-rgb) / 0.55) 24%,
        rgb(var(--bg-rgb) / 0) 46%
      ),
      /* top + bottom vignette — both resolve to full opaque ink so the panel
         melts into the header above and the section below (no horizontal seam) */
        linear-gradient(
          180deg,
          var(--bg) 0%,
          rgb(var(--bg-rgb) / 0.15) 8%,
          rgb(var(--bg-rgb) / 0) 24%,
          rgb(var(--bg-rgb) / 0.14) 54%,
          rgb(var(--bg-rgb) / 0.55) 80%,
          var(--bg) 100%
        ),
      var(--hero-image) var(--hero-focus-x, 50%) var(--hero-focus-y, 40%) / cover no-repeat;
  }

  /* Scroll cue would float over the split; drop it */
  .scroll-cue {
    display: none;
  }
}

/* ── Shared home section wrapper ── */
.home-section {
  width: min(100%, var(--container));
  margin: 0 auto;
  padding: var(--section) var(--gutter) 0;
}

/* ── Section header: red tab + h2 + "All dates" link ── */
.section-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0;
  flex-wrap: wrap;
}

.section-head__tab {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.55rem;
}

.section-head__tab h2 {
  margin: 0;
  color: var(--text);
  font-family: var(--font-display);
  font-size: clamp(1.75rem, 4vw, 2.75rem);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.025em;
  text-transform: uppercase;
}

.section-head__more {
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding-bottom: 0.2rem;
  transition: color 0.14s ease;
}

/* Upcoming reuses the shared event-list; the section wrapper already provides
   the container and gutter, so strip the list's own. */
.event-list--home {
  margin-top: 1.25rem;
  margin-bottom: 0;
  padding-inline: 0;
}

/* ── Latest release ── */
.release {
  display: grid;
  grid-template-columns: minmax(0, 340px) minmax(0, 1fr);
  gap: clamp(1.875rem, 5vw, 3rem);
  align-items: center;
  padding-bottom: var(--section);
}

/* Image tile — same hairline edge as .press-card (press.css). Not Flare red;
   the cover isn't interactive and red is reserved for actions. The hatch is the
   placeholder, visible only when `artwork` is unset in data/release.toml. */
.release-art {
  aspect-ratio: 1;
  border: 1px solid var(--line);
  overflow: hidden;
  background: repeating-linear-gradient(135deg, var(--coal) 0 14px, var(--soot) 14px 28px);
}

.release-art img {
  /* Block, not inline: an inline img sits on the baseline and the descender gap
     lets the tile background show as a seam along the bottom edge. */
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.release-info {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  min-width: 0;
}

.release-title {
  margin: 0.5rem 0 0;
  color: var(--text);
  font-family: var(--font-display);
  font-size: clamp(2.125rem, 5vw, 4rem);
  font-weight: 800;
  line-height: 0.95;
  letter-spacing: -0.025em;
  text-transform: uppercase;
  overflow-wrap: break-word;
}

.release-description {
  max-width: 48ch;
  margin: 0.75rem 0 0;
  color: var(--text-body);
  font-size: 0.95rem;
  line-height: 1.65;
}

.release-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 1.75rem;
}

/* ── Animations ── */
@keyframes heroIntro {
  from {
    opacity: 0;
    transform: translateY(16px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes glitchTwitch {
  0%,
  94%,
  100% {
    transform: none;
    filter: drop-shadow(0 0 22px rgb(var(--amber-rgb) / 0.55))
      drop-shadow(0 0 56px rgb(var(--red-rgb) / 0.35));
  }
  95% {
    transform: translateX(-3px) skewX(-1deg);
    filter: drop-shadow(3px 0 0 rgb(var(--red-rgb) / 0.8))
      drop-shadow(-3px 0 0 rgb(var(--signal-rgb) / 0.4));
  }
  96% {
    transform: translateX(2px);
    filter: drop-shadow(0 0 22px rgb(var(--amber-rgb) / 0.55))
      drop-shadow(0 0 56px rgb(var(--red-rgb) / 0.35));
  }
  97% {
    transform: translateX(-1px) skewX(0.5deg);
    filter: drop-shadow(2px 0 0 rgb(var(--red-rgb) / 0.6));
  }
  98% {
    transform: none;
  }
}

@keyframes scrollCueSlide {
  0% {
    transform: translateY(-100%);
    opacity: 0;
  }
  20% {
    opacity: 1;
  }
  80% {
    opacity: 1;
  }
  100% {
    transform: translateY(200%);
    opacity: 0;
  }
}

/* ── Layout-class swap: replay an entrance when the hero crosses a breakpoint
   (stacked ↔ overlay ↔ split). Triggered by `is-swapping` from main.js. ── */
@keyframes heroSwapIn {
  0% {
    opacity: 0;
    transform: translateY(16px) scale(0.985);
    filter: blur(7px);
  }
  55% {
    filter: blur(0);
  }
  100% {
    opacity: 1;
    transform: none;
    filter: blur(0);
  }
}

@keyframes heroPhotoSwapIn {
  from {
    opacity: 0.45;
  }
  to {
    opacity: 1;
  }
}

.home-hero.is-swapping .home-hero__content {
  animation: heroSwapIn 0.55s cubic-bezier(0.2, 0.7, 0.2, 1) both;
}

.home-hero.is-swapping .home-hero__photo {
  animation: heroPhotoSwapIn 0.6s ease both;
}

@media (prefers-reduced-motion: reduce) {
  .home-hero.is-swapping .home-hero__content,
  .home-hero.is-swapping .home-hero__photo {
    animation: none;
  }
}

/* ── 880px: hero side edge-fade off, release stacks ── */
@media (max-width: 880px) {
  /* Use the `background` shorthand (not `background-image`) so the band layer
     keeps its --hero-focus-x/--hero-focus-y position and `cover` size — a
     longhand override here desyncs the per-layer position/size lists and drops
     the image to 0% 0%/auto. */
  .home-hero__photo {
    background:
      linear-gradient(to top, var(--bg) 0%, rgb(var(--bg-rgb) / 0.45) 35%, transparent 65%),
      linear-gradient(to bottom, rgb(var(--bg-rgb) / 0.45) 0%, transparent 25%),
      var(--hero-image) var(--hero-focus-x, 50%) var(--hero-focus-y, 40%) / cover no-repeat;
  }

  .release {
    grid-template-columns: 1fr;
  }

  .release-art {
    width: min(100%, 300px);
    margin: 0 auto;
  }

  .release-actions {
    justify-content: center;
  }
}

/* ── 620px: hero stacks — photo banner on top, type below (image always visible) ── */
@media (max-width: 620px) {
  .home-hero {
    display: block;
    height: auto;
    min-height: 0;
    max-height: none;
    overflow: visible;
  }

  /* Photo becomes an in-flow banner instead of an absolute full-bleed layer */
  .home-hero__photo {
    position: relative;
    inset: auto;
    left: auto;
    right: auto;
    transform: none;
    width: 100%;
    max-width: none;
    height: 50vh;
    min-height: 300px;
    z-index: 0;
    background:
      /* bottom edge-fade into ink — gentle plateau-free ramp, no dark shelf */
      linear-gradient(
        to top,
        var(--bg) 0%,
        var(--bg) 4%,
        rgb(var(--bg-rgb) / 0.55) 20%,
        rgb(var(--bg-rgb) / 0.2) 40%,
        rgb(var(--bg-rgb) / 0) 62%
      ),
      var(--hero-image) var(--hero-focus-x, 50%) var(--hero-focus-y, 40%) / cover no-repeat;
  }

  /* Pull the type block up into the photo's ink fade so the logo glow bridges
     the two — one continuous composition instead of photo-block + type-block. */
  .home-hero__content {
    width: 100%;
    text-align: center;
    margin-top: clamp(-3.5rem, -8vw, -2rem);
    padding: 0 var(--gutter) clamp(2rem, 6vw, 3rem);
  }

  .scroll-cue {
    display: none;
  }
}

@media (max-width: 480px) {
  /* The two buttons stack and share one edge at 85% of the column — .home-hero__text
     centers shrink-to-fit children, so the width is set here and the parent's
     align-items: center does the centering. The booking bar is deliberately left
     unconstrained: stretching a meta-weight line to button width reads as a third
     equal action, so it stays at its natural size, centered under them. */
  .home-hero__actions {
    width: 85%;
    flex-direction: column;
    align-items: stretch;
  }

  .home-hero__actions .button {
    justify-content: center;
  }
}
