/* ==========================================================================
   Jeremias & Arias — press kit
   Palette measured from the duo's own photo (see CLAUDE.md for the numbers).
   Type: Anton / Bebas Neue / Montserrat — the three faces used in their PDF.
   ========================================================================== */

@font-face{font-family:Anton;src:url(../fonts/anton-latin.woff2) format("woff2");font-weight:400;font-style:normal;font-display:swap;unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2122,U+2212,U+FEFF,U+FFFD}
@font-face{font-family:"Bebas Neue";src:url(../fonts/bebasneue-latin.woff2) format("woff2");font-weight:400;font-style:normal;font-display:swap;unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2122,U+2212,U+FEFF,U+FFFD}
@font-face{font-family:Montserrat;src:url(../fonts/montserrat-latin.woff2) format("woff2");font-weight:400 700;font-style:normal;font-display:swap;unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+20AC,U+2122,U+2212,U+FEFF,U+FFFD}

:root{
  /* Sampled from the photo the artists nominated. 98.8% of its chromatic pixels
     are red, orange or amber; hue rotates 356°→42° as luminance rises, the way
     incandescent light actually behaves. Each stop below is the median colour of
     one luminance band of that photo, with its share of the frame.
     Only --ink (deepest tone taken down in value, hue kept) and the two text
     colours are derived rather than sampled. */
  --ink:#140003;            /* page ground, hue 356° */
  --surface:#3B0004;        /* 27.5% */
  --surface-2:#580A06;      /* 16.3% */
  --line:#720C00;           /*  7.2% */
  --ember:#9C1B00;          /* 10.7% */
  --red:#CE3104;            /* 22.6% — the dominant chromatic tone */
  --orange:#F96B05;         /*  9.4% */
  --amber:#FFA420;          /*  3.8% */
  --gold:#FFC94D;           /*  2.6% */
  --bone:#F7EFE8;           /* 17.91:1 on --ink */
  --muted:#B29790;          /*  7.49:1 on --ink — warm, never grey */

  --wrap:1180px;
  --gut:clamp(1.25rem,5vw,3rem);
  --sec-y:clamp(5rem,10vw,8.5rem);
  --radius:2px;
  --ease:cubic-bezier(.22,.61,.36,1);
  --out:cubic-bezier(.16,1,.3,1);
}

*,*::before,*::after{box-sizing:border-box}
/* color-scheme keeps native form UI (date picker, calendar icon, autofill) dark */
/* scrollbar-gutter fixes a real shift, not a hypothetical one: opening the
   lightbox sets body{overflow:hidden}, which removes the classic scrollbar on
   desktop and widens the viewport by ~15px — every .wrap reflows and the
   full-bleed backgrounds resize, at exactly the moment someone is looking at a
   photograph. It never showed in the CLS number because mobile uses overlay
   scrollbars. Reserving the track costs nothing and removes the jolt. */
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth;scroll-padding-top:5rem;
  color-scheme:dark;scrollbar-gutter:stable}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}

body{
  margin:0;
  background:var(--ink);
  color:var(--bone);
  font-family:Montserrat,system-ui,-apple-system,"Segoe UI",sans-serif;
  font-size:clamp(.95rem,.9rem + .2vw,1.0625rem);
  line-height:1.7;
  overflow-x:hidden;             /* belt-and-braces: nothing should overflow anyway */
  -webkit-font-smoothing:antialiased;
}

img,picture,svg,iframe{display:block;max-width:100%}
img{height:auto}
/* dominant colour of each photo, emitted by tools/build_assets.py. A lazy image
   opens as its own average tone instead of a black hole while the file lands. */
.ph-hero{background-color:#241C1A}
.ph-crowd{background-color:#151616}
.ph-stage{background-color:#04070C}
.ph-live{background-color:#161616}
.ph-booth{background-color:#181713}
.ph-portrait{background-color:#47464B}
.ph-decks{background-color:#0E1514}
.ph-wall{background-color:#24201C}
.ph-set{background-color:#C30603}
a{color:inherit}
button{font:inherit;color:inherit}

h1,h2,h3{font-family:Anton,Impact,sans-serif;font-weight:400;line-height:.95;
  text-transform:uppercase;letter-spacing:.01em;margin:0}
h2{font-size:clamp(2.1rem,1.5rem + 2.6vw,3.6rem)}
h3{font-family:"Bebas Neue",Impact,sans-serif;font-size:1.5rem;letter-spacing:.06em;line-height:1.1}
p{margin:0 0 1.1em}

/* ── typographic detail ─────────────────────────────────────────────────────
   Nothing here moves layout except the tracking clamps, and tighter tracking
   only ever removes a line, never adds one. */
/* balance is capped at a few lines by the engines, so it belongs on headings;
   pretty is for running copy, where it only fixes the last line. Firefox has no
   `pretty` as of 2026 and simply wraps normally — a clean fallback, not a bug. */
h2,h3,.press__name,.site-foot__brand{text-wrap:balance}
.lead,.bio p,.press__note,.shows__note,.rider__note,.set figcaption{text-wrap:pretty}
/* A heavy condensed face needs tighter tracking as it grows. Holding one value
   across a clamp() size range is the usual tell of display type nobody drew. */
h2{letter-spacing:clamp(-.02em,-.005em - .12vw,.01em)}
/* the date column and the file-size column are read as columns: proportional
   digits make their edges ripple under a scanning eye */
.shows__date,.press__spec,.facts dd{font-variant-numeric:tabular-nums}
/* The ramp contains no blue and no neutral grey. The OS defaults for selection
   and scrollbar contain both, and they were the only two places on the page
   still showing a colour that is not the duo's. */
::selection{background:var(--amber);color:var(--ink)}   /* the measured 10.26:1 pairing */
html{scrollbar-color:var(--ember) var(--ink);scrollbar-width:thin}

.wrap{width:100%;max-width:var(--wrap);margin-inline:auto;padding-inline:var(--gut)}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}

.skip{position:absolute;left:.5rem;top:-4rem;z-index:200;background:var(--amber);color:var(--ink);
  padding:.7rem 1.1rem;font-family:"Bebas Neue",sans-serif;letter-spacing:.08em;transition:top .2s}
.skip:focus{top:.5rem}

/* Two-tone ring. A bare amber outline is amber-on-amber on the primary button,
   the nav CTA and the skip link, and over the hero photograph the 3px offset gap
   shows image rather than ground, so the ring can vanish into it. The ink halo
   guarantees the outline is legible on any surface. Lighthouse does not test
   focus-ring contrast, which is why this survived a 100 a11y score. */
:where(a,button,input,textarea,[tabindex]):focus-visible{
  outline:3px solid var(--amber);outline-offset:3px;border-radius:var(--radius);
  box-shadow:0 0 0 6px var(--ink)}

/* ── header ─────────────────────────────────────────────────────────────── */
.site-head{
  position:fixed;inset:0 0 auto;z-index:100;
  display:flex;align-items:center;justify-content:space-between;gap:1rem;
  padding:.85rem var(--gut);
  background:color-mix(in srgb,var(--ink) 82%,transparent);
  backdrop-filter:blur(14px);
  border-bottom:1px solid var(--line);
}
/* padding-block buys the hit area, not height: the bar's tallest item is the
   Book-us CTA at ~38px, so a 19px wordmark growing to ~30px changes no layout.
   Measured 134x19 before — a fiddly target on a phone even where WCAG's spacing
   exception lets it pass. */
.brand{font-family:Anton,sans-serif;text-transform:uppercase;text-decoration:none;
  font-size:clamp(1rem,.85rem + .5vw,1.3rem);letter-spacing:.02em;line-height:1;white-space:nowrap;
  padding-block:.35rem}
.brand span:last-of-type{color:var(--amber)}

.nav ul{display:flex;align-items:center;gap:clamp(.9rem,1.6vw,1.9rem);
  list-style:none;margin:0;padding:0}
.nav a{font-family:"Bebas Neue",sans-serif;font-size:1.0625rem;letter-spacing:.09em;
  text-transform:uppercase;text-decoration:none;color:var(--bone);
  display:flex;align-items:baseline;gap:.4em;padding:.25rem 0;position:relative;white-space:nowrap}
.nav a::after{content:"";position:absolute;left:0;right:100%;bottom:-2px;height:1px;
  background:var(--amber);transition:right .35s var(--ease)}
.nav a:hover::after,.nav a[aria-current]::after{right:0}
.nav .nav-cta{background:var(--amber);color:var(--ink);padding:.42rem .9rem}
.nav .nav-cta::after{display:none}
.nav .nav-cta:hover{background:var(--bone)}

/* shown only below 900px, where the in-menu CTA is hidden instead */
.nav-cta--bar{display:none;align-items:center;background:var(--amber);color:var(--ink);
  text-decoration:none;font-family:"Bebas Neue",sans-serif;font-size:1.0625rem;
  letter-spacing:.09em;text-transform:uppercase;padding:.55rem .95rem;
  margin-left:auto;white-space:nowrap;transition:background .2s var(--ease)}
.nav-cta--bar:hover{background:var(--bone)}

.nav-toggle{display:none;background:none;border:1px solid var(--line);
  width:2.75rem;height:2.75rem;padding:0;cursor:pointer;position:relative}
.nav-toggle__bars,.nav-toggle__bars::before,.nav-toggle__bars::after{
  position:absolute;left:50%;width:1.15rem;height:2px;background:var(--bone);
  transform:translateX(-50%);transition:transform .25s var(--ease),opacity .2s}
.nav-toggle__bars{top:50%;margin-top:-1px}
.nav-toggle__bars::before{content:"";top:-6px}
.nav-toggle__bars::after{content:"";top:6px}
.nav-toggle[aria-expanded=true] .nav-toggle__bars{background:transparent}
.nav-toggle[aria-expanded=true] .nav-toggle__bars::before{transform:translateX(-50%) translateY(6px) rotate(45deg)}
.nav-toggle[aria-expanded=true] .nav-toggle__bars::after{transform:translateX(-50%) translateY(-6px) rotate(-45deg)}

@media (max-width:900px){
  .nav-toggle{display:block}
  .nav-cta--bar{display:inline-flex}
  .nav li:has(.nav-cta){display:none}   /* the bar carries it now */
  /* grid-template-rows animates on the compositor; max-height would thrash layout */
  .nav{position:fixed;inset:4.4rem 0 auto;background:var(--ink);
    border-bottom:1px solid var(--line);overflow:hidden;
    display:grid;grid-template-rows:0fr;transition:grid-template-rows .35s var(--ease)}
  .nav:not([data-open=true]){border-bottom-color:transparent}
  /* The collapsing item must carry NO padding: with box-sizing:border-box a box
     cannot be shorter than its own padding, which would floor the 0fr track and
     leak the first link below the header. Spacing lives on the links instead. */
  .nav>ul{overflow:hidden;min-height:0;padding:0;max-height:min(75vh,32rem)}
  .nav[data-open=true]{grid-template-rows:1fr}
  .nav[data-open=true]>ul{overflow-y:auto}
  .nav ul{flex-direction:column;align-items:stretch;gap:0}
  .nav a{padding:.95rem var(--gut);border-bottom:1px solid var(--surface-2);font-size:1.35rem}
  .nav li:first-child a{padding-top:1.35rem}
  .nav .nav-cta{margin:1.1rem var(--gut) 1.6rem;justify-content:center;padding:.95rem;border-bottom:0}
}

/* ── buttons ────────────────────────────────────────────────────────────── */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:.5em;
  font-family:"Bebas Neue",sans-serif;font-size:1.15rem;letter-spacing:.1em;
  text-transform:uppercase;text-decoration:none;cursor:pointer;
  padding:.85rem 1.9rem;border:1px solid transparent;border-radius:var(--radius);
  transition:background .25s var(--ease),color .25s var(--ease),border-color .25s var(--ease)}
/* amber on ink measures 10.26:1 — bone on amber is 1.74:1, so never do that */
/* Hover lights the button the way a fixture lights a surface: the glow is a
   box-shadow on the shape, never a text-shadow on the glyphs — glowing type
   loses the contrast this palette was measured for. */
.btn--primary{background:var(--amber);color:var(--ink);border-color:var(--amber)}
.btn--primary:hover{background:var(--bone);border-color:var(--bone);
  box-shadow:0 0 0 1px color-mix(in srgb,var(--orange) 55%,transparent),
             0 0 18px color-mix(in srgb,var(--red) 62%,transparent),
             0 0 46px color-mix(in srgb,var(--red) 34%,transparent)}
.btn--ghost{background:transparent;color:var(--bone);border-color:color-mix(in srgb,var(--bone) 45%,transparent)}
.btn--ghost:hover{border-color:var(--amber);color:var(--amber);
  box-shadow:0 0 16px color-mix(in srgb,var(--red) 45%,transparent),
             0 0 40px color-mix(in srgb,var(--ember) 40%,transparent)}
.btn[disabled]{opacity:.55;cursor:not-allowed}

/* ── hero ───────────────────────────────────────────────────────────────── */
.hero{position:relative;min-height:100svh;display:flex;align-items:flex-end;
  padding:8rem var(--gut) clamp(3rem,7vw,5.5rem);isolation:isolate;overflow:hidden}
.hero__bg{position:absolute;inset:0;z-index:-2}
.hero__bg img{width:100%;height:100%;object-fit:cover;object-position:50% 42%}
/* Scrim: measured against the real photo, not against the base colour.
   Weighted horizontally, because the text only ever occupies the left column —
   that buys AA over the copy while leaving the right of the frame readable. */
/* Scrim only. Decorative stage-light beams were added here and then removed at
   the client's request: the photograph already carries the room's own lasers,
   and a painted beam on top of a real one reads as a filter, not as lighting.
   If it ever comes back, it belongs UNDER these gradients, and the hero must be
   re-measured with verificacion/herocontrast.mjs. */
.hero::before{content:"";position:absolute;inset:0;z-index:-1;
  background:
    linear-gradient(to right,rgba(20,0,3,.95) 0%,rgba(20,0,3,.92) 34%,rgba(20,0,3,.6) 58%,rgba(20,0,3,.28) 100%),
    linear-gradient(to top,rgba(20,0,3,.86) 0%,rgba(20,0,3,.62) 34%,rgba(20,0,3,.3) 62%,rgba(20,0,3,.22) 82%,rgba(20,0,3,.5) 100%)}

.hero__inner{position:relative;width:100%;max-width:var(--wrap);margin-inline:auto}
.hero__inner>*{max-width:min(100%,34rem)}
/* tracking clamped on the same curve as the size: −.008em at 3rem, −.03em at 6rem.
   Safe against the hero contrast reading because the h1 is hand-broken with <br>
   and cannot reflow to a different line count — but re-measure anyway. */
.hero h1{font-size:clamp(3rem,1.4rem + 6.4vw,6rem);
  letter-spacing:clamp(-.03em,-.012em - .18vw,-.008em)}
.hero h1 .amp{color:var(--orange)}
.hero__tagline{max-width:26ch;margin:1.5rem 0 .9rem;font-size:clamp(1.15rem,1rem + .6vw,1.6rem);
  line-height:1.35;color:var(--bone)}
.hero__meta{margin:0 0 2.4rem;font-family:"Bebas Neue",sans-serif;letter-spacing:.16em;
  text-transform:uppercase;font-size:clamp(.85rem,.8rem + .2vw,1rem);color:var(--amber)}
.hero__actions{display:flex;flex-wrap:wrap;gap:.85rem;margin:0}

/* ── sections ───────────────────────────────────────────────────────────── */
.section{padding-block:var(--sec-y);position:relative}
/* A band, not a flood. --surface at full strength across a whole section made the
   photographs sit in a wine-coloured field and lose their own contrast; at ~36%
   it still reads warm and separates the bands without competing with the images. */
/* Mixed with transparent, not with --ink. Over the page ground the composite is
   identical - 0.36 surface + 0.64 ink either way - so the measured band tone is
   unchanged, but the word field behind shows through at 64% instead of being
   hidden by an opaque fill. Music, Gallery and Press carry this class and were
   the only three sections with no texture at all.
   These bands were briefly cut on a diagonal to break the stack of rectangles.
   Removed: once the word field was showing through, the angled edge stopped
   reading as a deliberate cut and started reading as a rendering fault,
   especially where Press meets Booking. The texture is doing that job now. */
.section--alt{background:color-mix(in srgb,var(--surface) 36%,transparent)}

/* -- background word field --------------------------------------------------
   One field per section, never two stacked. A page-wide fixed field plus a
   per-band field meant the three tinted sections carried BOTH, and the two
   rotations crossed into a lattice - legible as a mistake, not as texture.
   Now every section owns exactly one field and the rotation alternates from
   section to section, so the direction still flips at every boundary but no
   two layers ever cross.
   Generated content, never a text node: Lighthouse audits the colour contrast
   of real text even under aria-hidden, and a watermark by definition cannot
   pass. A pseudo-element has nothing to measure, and it stays out of the
   reading order and out of a copy-paste of the bio for free.
   ::after, not ::before - .booking::before is already its photo scrim.
   Oversized on all four sides so the rotation never exposes a corner; the
   section clips it. One shared content string for the whole page: it is the
   largest non-font item in this file, so it is declared exactly once.
   Words are separated by spaces only. A middle-dot separator was tried and
   read as noise at this size rather than as punctuation.
   Booking is excluded - it already has a photograph for a ground. */
.section{overflow:hidden}
.section>.wrap{position:relative;z-index:1}
.section:not(.booking)::after{content:"Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B   Groove   Dance   Soul   Freedom   Tech house   Afro house   Latin   Rhythm   Booth   B2B";
  position:absolute;top:-30%;height:160%;left:-35%;right:-35%;z-index:0;
  pointer-events:none;user-select:none;overflow:hidden;
  transform:rotate(18deg);
  font-family:"Bebas Neue",Impact,sans-serif;text-transform:uppercase;
  font-size:clamp(.8rem,1.3vw,1.15rem);letter-spacing:.4em;word-spacing:.55em;
  line-height:4;text-align:center;
  color:color-mix(in srgb,var(--surface-2) 38%,transparent)}
/* the tinted bands asked to be denser than the plain ones; they are also the
   only sections whose own tint sits between the field and the eye. */
.section--alt::after{color:color-mix(in srgb,var(--surface-2) 62%,transparent)}
/* alternate the angle section by section. nth-of-type counts the hero as 1, so
   about/shows/rider/booking take -24deg and music/gallery/press keep +18deg. */
main>section:nth-of-type(2n)::after{transform:rotate(-24deg)}
@media (prefers-reduced-transparency:reduce){.section::after{display:none}}
/* A slow ambient drift was added here and removed the same session. CLAUDE.md
   rations motion to the hero's settle, and the rooms band's marquee had already
   been cut once because a promoter cannot scan text that moves. Six word fields
   animating continuously also keep six composited layers awake on mobile for an
   effect nobody consciously sees. The field stays still. */
/* a hairline of the photo's own red opens each band instead of a number label.
   :not(.hero) rather than .section+.section, because the marquee sits between two
   sections and would otherwise leave the gallery as the one band with no rule. */
main>section+section{border-top:1px solid var(--line)}
.lead{font-size:clamp(1.05rem,1rem + .4vw,1.3rem);line-height:1.6;max-width:62ch;margin-top:1.6rem}
.lead--tight{margin-top:1rem;color:var(--muted)}

/* ── about ──────────────────────────────────────────────────────────────── */
.about{display:grid;grid-template-columns:1fr;gap:clamp(2.5rem,5vw,4.5rem);align-items:start}
/* .52 not .62: with the facts moved out to their own full-width band the text
   column got shorter, and the taller portrait left a dead gap beside it. Narrower
   column = shorter photo = both columns land together. Do not crop the portrait
   to fix this instead — the heads sit high in the frame. */
@media (min-width:900px){.about{grid-template-columns:1fr minmax(0,.52fr)}}
.about__text{min-width:0}
.bio{display:grid;grid-template-rows:0fr;transition:grid-template-rows .45s var(--ease);
  margin-top:.6rem}
/* exactly one grid item, and it carries no padding — see the .nav note above */
.bio__inner{overflow:hidden;min-height:0;padding:0}
.bio[data-open=true]{grid-template-rows:1fr}
.bio p{margin:0 0 1.1em;color:var(--muted)}
.bio p:first-child{margin-top:.9rem}
.bio p:last-child{margin-bottom:.2em}
.bio-toggle{background:none;border:0;padding:.4rem 0;cursor:pointer;
  font-family:"Bebas Neue",sans-serif;font-size:1.05rem;letter-spacing:.12em;
  text-transform:uppercase;color:var(--amber);display:inline-flex;align-items:center;gap:.5rem}
.bio-toggle::after{content:"↓";transition:transform .3s var(--ease)}
.bio-toggle[aria-expanded=true]::after{transform:rotate(180deg)}

/* exactly four facts, so a fixed 2×2 never leaves a bare gap cell showing through */
/* hairline rules rather than a boxed grid: reads as a spec sheet, not a table */
/* One rule per fact: label left, value right. Reads as a spec sheet a promoter
   scans down, and it fills the text column instead of boxing into a 2×2. */
.facts{margin:2.5rem 0 0;border-top:1px solid var(--line)}
.facts>div{display:grid;gap:.15rem .75rem;grid-template-columns:1fr;
  padding:.95rem .25rem;border-bottom:1px solid var(--line);min-width:0}
@media (min-width:560px){
  .facts>div{grid-template-columns:8rem minmax(0,1fr);align-items:baseline}
  .facts dd{text-align:right}
}
.facts dt{font-family:"Bebas Neue",sans-serif;letter-spacing:.16em;text-transform:uppercase;
  font-size:.8rem;color:var(--muted)}
.facts dd{margin:0;font-weight:600;font-size:.98rem;line-height:1.35;min-width:0}

.about__photo{margin:0}
.about__photo img{width:100%;border:1px solid var(--line)}

/* ── music ──────────────────────────────────────────────────────────────── */
/* the set: the only piece of moving evidence on the page, so it leads the section */
.set{margin:2.5rem 0 0}
.video{position:relative;border:1px solid var(--line);overflow:hidden;background:var(--surface)}
.video__btn{display:block;width:100%;padding:0;border:0;background:none;cursor:pointer;
  position:relative;aspect-ratio:16/9}
.video__btn img{width:100%;height:100%;object-fit:cover;
  transition:transform .9s var(--out)}
.video__btn::after{content:"";position:absolute;inset:0;
  background:linear-gradient(to top,rgba(20,0,3,.55),rgba(20,0,3,.14) 60%);
  transition:opacity .4s var(--ease)}
.video__play{position:absolute;left:50%;top:50%;z-index:2;
  transform:translate(-50%,-50%);
  width:clamp(3.75rem,6.5vw,5.25rem);aspect-ratio:1;border-radius:50%;
  background:var(--bone);display:grid;place-items:center;
  transition:transform .4s var(--out),background .25s var(--ease)}
.video__play::before{content:"";width:0;height:0;margin-left:.22em;
  border-left:1.05em solid var(--ink);
  border-top:.62em solid transparent;border-bottom:.62em solid transparent}
.video__btn:hover img,.video__btn:focus-visible img{transform:scale(1.035)}
.video__btn:hover::after,.video__btn:focus-visible::after{opacity:.65}
.video__btn:hover .video__play,.video__btn:focus-visible .video__play{
  transform:translate(-50%,-50%) scale(1.09);background:var(--amber);
  box-shadow:0 0 24px color-mix(in srgb,var(--red) 65%,transparent),
             0 0 64px color-mix(in srgb,var(--red) 38%,transparent)}
.video iframe{width:100%;aspect-ratio:16/9;border:0;display:block}
.set figcaption{display:flex;flex-wrap:wrap;align-items:baseline;gap:.5rem 1rem;
  margin-top:.9rem;color:var(--muted);font-size:.92rem}
/* --ember is a 2.4:1 text colour on this band; --orange clears AA at 6.5:1 */
.set figcaption a{font-family:"Bebas Neue",sans-serif;letter-spacing:.14em;
  text-transform:uppercase;font-size:.8rem;color:var(--orange);text-decoration:none}
.set figcaption a:hover,.set figcaption a:focus-visible{color:var(--amber);text-decoration:underline}

/* single column: the set carries the section, so the player is a bar under it
   rather than a half-width panel standing in a 352px void */
.music{margin-top:clamp(2rem,4vw,2.75rem)}
.player__tabs{display:flex;flex-wrap:wrap;gap:0;border:1px solid var(--line);border-bottom:0}
.player__tabs [role=tab]{flex:1 1 8rem;min-width:0;background:none;border:0;cursor:pointer;
  padding:.85rem 1rem;color:var(--muted);
  font-family:"Bebas Neue",sans-serif;font-size:1.05rem;letter-spacing:.11em;text-transform:uppercase;
  border-bottom:2px solid transparent;
  transition:color .2s var(--ease),background .2s var(--ease),border-color .2s var(--ease)}
.player__tabs [role=tab]+[role=tab]{border-left:1px solid var(--line)}
.player__tabs [role=tab]:hover{color:var(--bone);background:var(--surface)}
.player__tabs [role=tab][aria-selected=true]{color:var(--amber);border-bottom-color:var(--amber);
  background:var(--surface)}
/* narrow screens: three equal rows, not a 2+1 wrap with one orphan tab.
   flex-basis must reset to auto or the 8rem basis becomes row HEIGHT here. */
@media (max-width:519px){
  .player__tabs{flex-direction:column}
  .player__tabs [role=tab]{flex:0 0 auto}
  .player__tabs [role=tab]+[role=tab]{border-left:0;border-top:1px solid var(--line)}
}
.music__player{min-width:0;border:1px solid var(--line);background:var(--surface)}
.music__player iframe{width:100%;border:0;min-height:352px}
.facade{display:flex;align-items:center;gap:1.1rem;width:100%;min-width:0;
  padding:1.2rem 1.4rem;background:none;border:0;cursor:pointer;text-align:left;
  transition:background .25s var(--ease)}
.facade:hover{background:var(--surface-2)}
.facade__icon{flex:none;width:3.1rem;height:3.1rem;display:grid;place-items:center;
  background:var(--amber);color:var(--ink);font-size:1.1rem;padding-left:.15em}
.facade__text{min-width:0;display:grid;gap:.2rem}
.facade__text b{font-family:"Bebas Neue",sans-serif;font-weight:400;font-size:1.35rem;letter-spacing:.08em;text-transform:uppercase}
.facade__text em{font-style:normal;color:var(--muted);font-size:.85rem;line-height:1.45}

/* one row of destinations across the full measure, not a tall thin column */
/* explicit counts, not auto-fit: five items in an auto-fit track produced a sixth
   empty column at 1440 and a half-width orphan row on mobile */
.platforms{list-style:none;margin:2.25rem 0 0;padding:0;
  display:grid;grid-template-columns:1fr;border-top:1px solid var(--line)}
@media (min-width:900px){.platforms{grid-template-columns:repeat(5,minmax(0,1fr))}}
.platforms a{display:flex;align-items:center;gap:.7rem;
  padding:1.1rem 1rem 1.1rem 0;border-bottom:1px solid var(--line);text-decoration:none;
  font-family:"Bebas Neue",sans-serif;font-size:1.2rem;letter-spacing:.08em;text-transform:uppercase;
  transition:color .25s var(--ease)}
.platforms__name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* the arrow nudges outward instead of the row sliding: transform, not padding */
.platforms__go{margin-left:auto;color:var(--amber);font-size:.85em;
  transition:transform .25s var(--ease)}
.platforms a:hover{color:var(--amber)}
.platforms a:hover .platforms__go,.platforms a:focus-visible .platforms__go{transform:translate(.3rem,-.3rem)}

/* official brand paths (Simple Icons), one family: 24px box, filled, one colour.
   Sized smaller than the old stroked marks: a solid glyph reads heavier than an
   outlined one at the same box, so 1.35em looked oversized once they were filled. */
.ico{flex:none;width:1.05em;height:1.05em;fill:currentColor;color:var(--orange);
  transition:color .25s var(--ease)}
.platforms a:hover .ico,.platforms a:focus-visible .ico{color:var(--amber)}

/* ── shows ──────────────────────────────────────────────────────────────── */
.shows{list-style:none;margin:2.5rem 0 0;padding:0;border-top:1px solid var(--line)}
.shows li{display:grid;gap:.15rem 1.5rem;padding:1.15rem .25rem;
  border-bottom:1px solid var(--line);align-items:baseline;
  grid-template-columns:1fr;
  transition:background .25s var(--ease)}
/* The nav already owns this gesture — a rule that wipes in from the left. Using
   it here too is free coherence: one hand made both. scaleX rather than the
   nav's `right` animation, because a transform runs on the compositor. */
.shows li{position:relative}
.shows li::after{content:"";position:absolute;left:0;right:0;bottom:-1px;height:1px;
  background:var(--amber);transform:scaleX(0);transform-origin:left;
  transition:transform .45s var(--ease)}
.shows li:hover::after{transform:scaleX(1)}
.shows li:hover{background:var(--surface)}
@media (min-width:760px){
  .shows li{grid-template-columns:8.5rem minmax(0,1fr) minmax(0,11rem) minmax(0,10rem)}
}
/* The event is what a promoter reads first, so it carries the size; the date is
   metadata beside it. Reversing this was the reference's clearest lesson. */
.shows__date{font-family:"Bebas Neue",sans-serif;font-size:.95rem;letter-spacing:.16em;
  color:var(--amber);text-transform:uppercase}
.shows__event{font-weight:600;min-width:0;font-size:clamp(1.05rem,.85rem + .5vw,1.35rem);
  line-height:1.25;letter-spacing:-.01em}
.shows__event em{font-style:normal;color:var(--amber);font-weight:400}
.shows__venue,.shows__city{color:var(--muted);font-size:.92rem;min-width:0}
/* These shows are the duo's credential, so they are shown at full strength: no
   strikethrough, no dimming. The .shows--past hook stays for future use. */

/* The two group headings carry real heading weight, not the metadata weight of
   .rooms__title: this section is the track record, so it gets the emphasis.
   "Next up" takes the amber so the live date is the first thing the eye lands on.
   The adjacent rule drops the list's own border, otherwise the heading rule and
   the list rule stack into a double line. */
.shows__group{font-family:Anton,Impact,sans-serif;font-weight:400;
  font-size:clamp(1.45rem,1.1rem + 1.5vw,2.2rem);line-height:1;
  letter-spacing:.02em;text-transform:uppercase;color:var(--bone);
  margin:2.75rem 0 0;padding-top:1.6rem;border-top:1px solid var(--line)}
.shows__group--next{color:var(--amber)}
.shows__group + .shows{margin-top:1.25rem;border-top:0}
/* Rows carry .25rem of side padding so the hover surface is not flush with the
   text. Pulling the list out by the same amount puts the date column back on the
   section's optical edge, level with the headings and the h2 above them. */
.shows{margin-left:-.25rem;margin-right:-.25rem}

/* The next date is the one actionable line in the section: a promoter checking
   availability and a fan buying a ticket both stop here. It gets a wash of the
   accent and a step up in type so it reads as the section's headline rather
   than the first row of a list. No accent bar, no card — the surface and the
   scale carry it. */
.shows--next li{background:color-mix(in srgb,var(--amber) 8%,transparent);
  padding-top:1.75rem;padding-bottom:1.75rem}
.shows--next li:hover{background:color-mix(in srgb,var(--amber) 14%,transparent)}
.shows--next .shows__date{font-size:1.2rem;color:var(--gold)}
.shows--next .shows__event{font-size:clamp(1.2rem,.95rem + .8vw,1.65rem)}
.shows__note{margin-top:1.6rem;color:var(--muted);font-size:.95rem}
.shows__note a{color:var(--amber)}

/* ── rooms & collectives ────────────────────────────────────────────────────
   Was a scrolling ticker. A moving strip reads as a widget, not as credits, and
   a promoter cannot scan it. Static and typeset instead. */
.rooms{margin-top:clamp(3rem,6vw,4.5rem);display:grid;gap:.75rem 3rem;
  grid-template-columns:1fr}
@media (min-width:820px){.rooms{grid-template-columns:9rem minmax(0,1fr);align-items:start}}
.rooms__title{font-family:"Bebas Neue",sans-serif;font-size:.9rem;letter-spacing:.18em;
  text-transform:uppercase;color:var(--muted);margin:1.25rem 0 0;
  padding-top:1.25rem;border-top:1px solid var(--line)}
.rooms__title:first-child{margin-top:0}
.rooms__list{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;
  gap:.35rem 0;font-family:"Bebas Neue",sans-serif;letter-spacing:.1em;
  text-transform:uppercase;font-size:1.1rem;color:var(--bone)}
.rooms__list li{padding-right:1.15rem}
.rooms__list li:not(:last-child)::after{content:"·";color:var(--red);margin-left:1.15rem}
/* Two columns, one hairline per row — and both segments must be collinear.
   Two separate bugs put them 13.6px apart, measured at 1440:
   1. The base .rooms__list rule above resets margin and padding, and it used to
      sit BELOW this media query. Same specificity, later source wins, so the
      padding-top and margin-top declared here were silently cancelled and the
      list's rule sat at its own box top with no padding. Keep that base rule
      above this block.
   2. align-items was `baseline`, which aligns the two text baselines — and a
      .9rem label against a 1.1rem list can then never put its border-top on the
      same line. `start` aligns the box tops, so the two rules are collinear and
      the label still lands within 0.8px of the list's first row. */
@media (min-width:820px){
  .rooms__title{padding-top:1.35rem}
  .rooms__list{padding-top:1.35rem;border-top:1px solid var(--line);margin-top:1.25rem}
  .rooms__list:nth-of-type(1){margin-top:0}
}

/* ── gallery ────────────────────────────────────────────────────────────── */
/* each tile owns its aspect ratio, so the button always has a height to fill and
   no photo can letterbox inside its cell */
.gallery{list-style:none;margin:2.5rem 0 0;padding:0;align-items:start;
  display:grid;gap:clamp(.6rem,1.4vw,1rem);grid-template-columns:1fr}
.gallery__item{min-width:0;aspect-ratio:4/3}
.gallery__item--tall{aspect-ratio:3/4}
@media (min-width:760px){
  .gallery{grid-template-columns:repeat(2,minmax(0,1fr))}
  .gallery__item--wide{grid-column:1/-1;aspect-ratio:21/9}
}
.gallery__btn{display:block;width:100%;height:100%;padding:0;border:1px solid var(--line);
  background:var(--surface);cursor:pointer;position:relative;overflow:hidden}
/* The <picture> must fill the cell too, or the img's height:100% resolves against
   an auto-height parent and collapses to the photo's own aspect. Portrait sources
   hid this for months because their aspect already matched the tall cell; the
   first landscape source dropped in floated with gaps above and below. */
/* Hover with intent: the tile you are on stays lit and its neighbours recede,
   so the existing 1.045 scale reads as focus rather than as a wobble. Keyboard
   gets it too, via :has(:focus-visible). opacity is compositor-only, so no
   repaint and no TBT. Guarded to hover:hover because :hover sticks after a tap.
   Deliberately NOT extended to .shows or .platforms: those rows are text at a
   measured 7.49:1 and 17.91:1, and a 0.5 multiplier would drop them under AA. */
@media (hover:hover){
  .gallery:is(:hover,:has(:focus-visible)) .gallery__item:not(:hover):not(:has(:focus-visible)){
    opacity:.5}
  .gallery__item{transition:opacity .4s var(--ease)}
}
.gallery__btn picture{display:block;width:100%;height:100%}
.gallery__btn img{width:100%;height:100%;object-fit:cover;
  transition:transform .6s var(--ease),filter .4s var(--ease)}
.gallery__btn::after{content:"";position:absolute;inset:0;
  background:linear-gradient(to top,rgba(20,0,3,.5),transparent 55%);
  opacity:0;transition:opacity .4s var(--ease)}
.gallery__btn:hover img,.gallery__btn:focus-visible img{transform:scale(1.045)}
.gallery__btn:hover::after,.gallery__btn:focus-visible::after{opacity:1}
.gallery__zoom{position:absolute;right:.7rem;bottom:.7rem;z-index:2;
  width:2.35rem;height:2.35rem;display:grid;place-items:center;
  background:var(--amber);color:var(--ink);font-size:1.1rem;line-height:1;
  opacity:0;transform:translateY(6px);transition:opacity .3s var(--ease),transform .3s var(--ease)}
.gallery__btn:hover .gallery__zoom,.gallery__btn:focus-visible .gallery__zoom{opacity:1;transform:none}
@media (max-width:759px){.gallery__zoom{opacity:1;transform:none}}

/* ── rider ──────────────────────────────────────────────────────────────── */
.rider{display:grid;gap:clamp(2rem,4vw,3.5rem);margin-top:2.5rem;grid-template-columns:1fr}
@media (min-width:760px){.rider{grid-template-columns:repeat(2,minmax(0,1fr))}}
.rider__col{min-width:0}
.rider__col h3{color:var(--amber);padding-bottom:.7rem;border-bottom:1px solid var(--line)}
.spec{list-style:none;margin:0;padding:0}
.spec li{display:grid;gap:.1rem .5rem;padding:.95rem 0;border-bottom:1px solid var(--surface-2);
  grid-template-columns:1fr}
@media (min-width:520px){.spec li{grid-template-columns:7rem minmax(0,1fr)}}
.spec b{font-family:"Bebas Neue",sans-serif;font-weight:400;letter-spacing:.12em;
  text-transform:uppercase;font-size:.95rem;color:var(--muted)}
.spec span{min-width:0;font-size:.97rem;line-height:1.5}

/* The booth-layout diagram lived here and was removed at the client's request.
   It was pure CSS with no bitmap ceiling; if it ever returns, do NOT put the
   707px PDF bitmap back — that was the worst under-provisioned asset on the site. */
.rider__note{margin:clamp(2rem,4vw,2.75rem) 0 0;color:var(--muted);font-size:.88rem;
  padding-top:1.35rem;border-top:1px solid var(--line)}
.rider__get{margin-top:clamp(2rem,4vw,2.75rem)}

/* ── press kit ──────────────────────────────────────────────────────────── */
.press{list-style:none;margin:2.5rem 0 0;padding:0;border-top:1px solid var(--line)}
.press a{display:grid;gap:.2rem 1.5rem;padding:1.5rem .25rem 1.5rem 3rem;
  border-bottom:1px solid var(--line);text-decoration:none;position:relative;
  grid-template-columns:1fr;align-items:baseline;
  transition:background .25s var(--ease)}
@media (min-width:720px){
  .press a{grid-template-columns:minmax(0,1fr) minmax(0,10rem);padding-right:.5rem}
  .press__spec{grid-row:1/3;grid-column:2;justify-self:end;align-self:center}
}
.press a::before{content:"↓";position:absolute;left:.4rem;top:1.5rem;color:var(--orange);
  font-size:1.2rem;line-height:1.2;transition:transform .3s var(--out)}
.press a:hover,.press a:focus-visible{background:var(--surface-2)}
.press a:hover::before,.press a:focus-visible::before{transform:translateY(.3rem)}
.press__name{font-family:Anton,sans-serif;text-transform:uppercase;font-size:clamp(1.3rem,1.1rem + .7vw,1.7rem);line-height:1.1}
.press__note{color:var(--muted);font-size:.92rem;line-height:1.55;min-width:0}
.press__spec{font-family:"Bebas Neue",sans-serif;letter-spacing:.12em;font-size:.95rem;
  color:var(--amber);white-space:nowrap}

/* short bio, sized for a promoter to lift straight into a listing */
.quote{margin:clamp(2.5rem,5vw,3.5rem) 0 0;max-width:62ch;
  border-left:1px solid var(--ember);padding-left:clamp(1rem,3vw,1.75rem)}
.quote blockquote{margin:0}
.quote p{margin:0;font-size:clamp(1.05rem,1rem + .35vw,1.25rem);line-height:1.6}
.quote figcaption{display:flex;flex-wrap:wrap;align-items:center;gap:.75rem 1.25rem;
  margin-top:1.1rem;color:var(--muted);font-size:.85rem}
.copy{font-family:"Bebas Neue",sans-serif;letter-spacing:.12em;text-transform:uppercase;
  font-size:.9rem;background:none;color:var(--amber);cursor:pointer;
  border:1px solid var(--line);border-radius:var(--radius);padding:.35rem .9rem;
  transition:border-color .25s var(--ease),color .25s var(--ease)}
.copy:hover{border-color:var(--amber)}
.copy[data-done]{color:var(--gold);border-color:var(--ember)}

/* ── booking ────────────────────────────────────────────────────────────── */
.booking{isolation:isolate;overflow:hidden}
.booking__bg{position:absolute;inset:0;z-index:-2}
.booking__bg img{width:100%;height:100%;object-fit:cover}
.booking::before{content:"";position:absolute;inset:0;z-index:-1;
  background:linear-gradient(to bottom,rgba(20,0,3,.94),rgba(20,0,3,.97))}
.booking__inner{display:grid;gap:clamp(2.5rem,5vw,4rem);grid-template-columns:1fr}
@media (min-width:900px){.booking__inner{grid-template-columns:minmax(0,1fr) minmax(0,1.05fr)}}
.booking__intro{min-width:0}

/* No rules in this block at all: not under each value and not between the rows.
   The label column already separates the three, and the section reads calmer
   without a ladder of lines under a heading this size. */
.contact{list-style:none;margin:2.25rem 0 0;padding:0}
.contact li{display:grid;grid-template-columns:1fr;gap:.1rem;padding:.7rem 0}
@media (min-width:420px){.contact li{grid-template-columns:6.5rem minmax(0,1fr);align-items:baseline;gap:1rem}}
.contact span{font-family:"Bebas Neue",sans-serif;letter-spacing:.14em;text-transform:uppercase;
  font-size:.85rem;color:var(--muted)}
/* no rule under the value: the row separator already divides these three, and a
   second line directly under each one read as clutter. Hover carries the
   affordance instead — these are the only links in the section, and the amber
   shift is the same signal the nav and the platform rows use. */
.contact a{color:var(--bone);text-decoration:none;
  word-break:break-word;transition:color .25s var(--ease)}
.contact a:hover,.contact a:focus-visible{color:var(--amber)}

/* ── form ───────────────────────────────────────────────────────────────── */
.form{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:1.1rem;
  background:color-mix(in srgb,var(--ink) 72%,transparent);
  border:1px solid var(--line);padding:clamp(1.25rem,3vw,2.25rem);min-width:0}
.field{display:flex;flex-direction:column;gap:.45rem;grid-column:1/-1;min-width:0}
@media (min-width:520px){.field--half{grid-column:span 1}}
.field label{font-family:"Bebas Neue",sans-serif;letter-spacing:.13em;text-transform:uppercase;
  font-size:.9rem;color:var(--muted)}
.req{color:var(--amber)}
.field input,.field textarea{
  width:100%;max-width:100%;min-width:0;
  background:var(--ink);color:var(--bone);
  border:1px solid var(--line);border-radius:var(--radius);
  padding:.8rem .9rem;font-family:inherit;font-size:1rem;line-height:1.4;
  transition:border-color .25s var(--ease)}
.field textarea{resize:vertical;min-height:6.5rem}
.field input:hover,.field textarea:hover{border-color:var(--ember)}
.field input:focus,.field textarea:focus{border-color:var(--amber);outline-offset:1px}
.field input[aria-invalid=true],.field textarea[aria-invalid=true]{border-color:var(--red)}
.err{margin:0;font-size:.85rem;color:var(--amber);line-height:1.4}
.form .btn{grid-column:1/-1;justify-self:start}
.form__status{grid-column:1/-1;margin:0;font-size:.95rem;line-height:1.5;min-height:1.5rem}
.form__status[data-state=ok]{color:var(--amber)}
.form__status[data-state=err]{color:#FF8A6B}   /* 6.9:1 on --ink; --red alone is only 4.0:1 */
/* honeypot: off-screen but not display:none, so bots still fill it */
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

/* ── footer ─────────────────────────────────────────────────────────────── */
.site-foot{border-top:1px solid var(--line);padding-block:clamp(2.5rem,5vw,4rem);background:var(--ink)}
.site-foot__inner{display:grid;gap:1.75rem}
.site-foot__brand{font-family:Anton,sans-serif;text-transform:uppercase;
  font-size:clamp(1.6rem,1rem + 2.4vw,2.6rem);margin:0;line-height:1}
.site-foot__social{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:.6rem 1.6rem}
/* inline-block and nothing else. As an inline box the hit area was the 22px font
   box, but the <li> around it was already 28.6px of line box — so the row height
   the eye sees was never 22px. inline-block just hands that existing line box to
   the pointer: target 22px -> 29px, footer height and row pitch both unchanged.
   Padding was tried first and cost 6px of footer for no extra hit area. */
.site-foot__social a{font-family:"Bebas Neue",sans-serif;letter-spacing:.1em;text-transform:uppercase;
  font-size:1.05rem;text-decoration:none;color:var(--muted);transition:color .25s var(--ease);
  display:inline-block}
.site-foot__social a:hover{color:var(--amber)}
.site-foot__legal{display:flex;flex-wrap:wrap;gap:.5rem 1.5rem;justify-content:space-between;
  margin:0;padding-top:1.5rem;border-top:1px solid var(--line);
  color:var(--muted);font-size:.85rem}
.site-foot__legal a{color:var(--muted)}
.site-foot__legal a:hover{color:var(--amber)}

/* ── lightbox ───────────────────────────────────────────────────────────── */
.lb{position:fixed;inset:0;z-index:300;display:grid;
  grid-template-columns:auto 1fr auto;align-items:center;gap:.5rem;
  padding:clamp(3.5rem,6vw,4.5rem) clamp(.5rem,2vw,2rem);
  background:rgba(20,0,3,.97)}
.lb[hidden]{display:none}
.lb__figure{grid-column:2;margin:0;display:flex;flex-direction:column;align-items:center;
  gap:1rem;min-width:0;max-height:100%}
.lb__media{display:flex;min-width:0;min-height:0}
.lb__figure img{max-width:100%;max-height:calc(100svh - 12rem);width:auto;object-fit:contain}
.lb__figure figcaption{color:var(--muted);font-size:.88rem;text-align:center;max-width:60ch;line-height:1.5}
.lb__close,.lb__nav{background:none;border:1px solid var(--line);color:var(--bone);
  width:2.9rem;height:2.9rem;display:grid;place-items:center;cursor:pointer;padding:0;
  font-size:1.5rem;line-height:1;transition:border-color .25s var(--ease),color .25s var(--ease)}
.lb__close:hover,.lb__nav:hover{border-color:var(--amber);color:var(--amber)}
.lb__close{position:absolute;top:clamp(.75rem,2vw,1.5rem);right:clamp(.75rem,2vw,1.5rem);font-size:1.1rem}
.lb__nav--prev{grid-column:1}
.lb__nav--next{grid-column:3}
body[data-lb-open]{overflow:hidden}

/* ── the one authored moment ────────────────────────────────────────────────
   The hero photograph settles as the page arrives. Nothing else animates in on
   scroll: text is painted at full opacity from the first frame, which keeps LCP
   honest and stops every section sharing one identical entrance. */
@media (prefers-reduced-motion:no-preference){
  .hero__bg img{animation:settle 1.8s var(--out) both}
}
@keyframes settle{from{transform:scale(1.055)}to{transform:none}}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;
    transition-duration:.001ms!important}
}
