/* ── 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;
  max-height: 920px;
  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.) */
@media (min-width: 621px) and (max-width: 1599px) 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-width: 1599px) and (max-height: 830px) {
  .home-hero__logo {
    width: clamp(260px, 36vw, 520px);
  }
}

/* ── Editorial split: ultra-wide, or letterboxed ── */
/* Two-column row: type lives in the left column, photo fills a bounded right panel.
   Ultra-wide windows get it because there is room to spare.

   The second trigger is an aspect ratio, not a height. The hero's `min-height: 620px`
   means a window shorter than ~683px stops shrinking the hero, so absolute height says
   nothing about how the composition reads past that point — what matters is how much
   of the hero is above the fold, and that scales with width. Past 1.9:1 the visible
   slice is a letterbox band and the overlay's bottom-anchored type sits below it
   entirely; the split centers the type in the hero instead, so the logo and CTAs stay
   in view.

   1.9 specifically, not a rounder number: browser chrome (tab strip, toolbar,
   bookmarks bar, fullscreen or not) moves the viewport height by ~100px on a fixed
   screen, which sweeps a 16:10 laptop across roughly 1.63–1.92. A threshold inside
   that range flips the hero when someone toggles a bookmarks bar. 1.9 clears the
   16:10 laptop band, so those windows hold the overlay and only a deliberately
   squashed window takes the split. (1366×768 laptops sit at 1.92–2.16 and are the
   one class still near the line; ~2.25 would clear every class, at the cost of the
   split showing up far more rarely.)

   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: 1600px), (min-width: 1100px) and (min-aspect-ratio: 19 / 10) {
  .home-hero {
    align-items: stretch;
    justify-content: flex-start;
  }

  /* Left column: type, left-aligned */
  .home-hero__content {
    order: 0;
    flex: 1 1 auto;
    min-width: 0;
    width: auto;
    max-width: none;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: flex-start;
    text-align: left;
    padding: 0 clamp(2.5rem, 3vw, 3.75rem) 0 clamp(3.75rem, 6vw, 8rem);
  }

  .home-hero__text {
    align-items: flex-start;
    max-width: 540px;
    margin-left: auto;
  }

  .home-hero__logo {
    width: min(520px, 100%);
  }

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

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

  /* Right panel: bounded photo, no longer full-bleed */
  .home-hero__photo {
    order: 1;
    position: relative;
    inset: auto;
    left: auto;
    right: auto;
    transform: none;
    flex: 0 0 clamp(700px, 52vw, 1080px);
    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;
  }
}
