/* ============================================================
   International Brussels Tattoo Convention — design system
   Colours sampled from the live brand: black ground, plum accent,
   warm blush ink, brass for prizes, acid for the EUR 1 pass.
   ============================================================ */

/* Sampled off brusselstattooconvention.be: the ground is pure black, the
   accent is the logotype plum #8F4E83 and the type is a warm blush #F6E0DA
   rather than white — that warmth is what stops an all-black page reading
   as a default dark theme. White on --plum is 5.8:1, so it carries button
   text unaltered (Malaga's magenta had to be darkened for the same job). */
:root {
  /* Dark base — the accents only read as neon against near-black.
     --ink is the TEXT colour; --void/--surface are backgrounds. */
  --ink: #F6E0DA;          /* primary text — warm blush, 15.6:1 on --void */
  --ink-soft: #D3BDB9;     /* secondary text */
  --void: #0A080C;         /* page background — black with a violet cast */
  --surface: #16111B;      /* card surface */
  --deep: #050406;         /* deepest panels: footer, modal, cookie */
  --surface-2: #1E1826;    /* alternating section */

  /* Plum is the brand. It is the one colour on the poster, the logotype and
     the stage lighting, so it carries every primary action. */
  --plum: #8F4E83;
  --plum-lit: #C77BB8;     /* links/accents on dark — 6.5:1 */
  --plum-deep: #6B3A62;

  /* Brass = money and trophies: contest prizes, the arena, winner callouts.
     Deliberately kept off navigation so it stays meaningful. */
  --brass: #D9A441;
  --amber: #C98A2E;
  --amber-lit: #E8B45C;
  --amber-deep: #8A5C17;

  /* Acid is the price tag. One colour, one job — the EUR 1 pass. */
  --acid: #E3E496;
  --rose: #E8657A;
  --rose-deep: #B02338;
  --gray: #9A8A94;

  /* Neon layer — hotter than the text palette, for glow and hover only.
     Body text keeps the AA-safe colours above so legibility never depends
     on a glow being visible. */
  --neon-plum: #E85FD0;
  --neon-amber: #FFC84D;
  --neon-brass: #FFD98A;
  --neon-rose: #FF5C7A;
  --glow-sm: 0 0 12px;
  --glow-md: 0 0 26px;
  --glow-lg: 0 0 60px;
  --line: rgba(246, 224, 218, 0.15);
  --line-light: rgba(246, 224, 218, 0.18);

  --font-display: "Archivo Black", "Archivo", sans-serif;
  --font-body: "Archivo", sans-serif;
  --font-mono: "IBM Plex Mono", monospace;

  --container: 1180px;
  --radius: 14px;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

/* Form controls do not inherit type by default — the UA stylesheet *declares*
   a font on them, which beats inheritance. Without this every <button> renders
   in Arial while an <a class="btn"> next to it renders in Archivo, and the two
   sit side by side all over this site. Component rules set their own
   font-size/family afterwards and still win on specificity. */
button, input, select, textarea { font: inherit; color: inherit; }

/* The marquee and hero splat deliberately extend past the viewport;
   clip on both html and body so they never create a horizontal scrollbar. */
html { scroll-behavior: smooth; overflow-x: clip; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; }
}

body {
  font-family: var(--font-body);
  font-size: 1.0625rem;
  line-height: 1.6;
  color: var(--ink);
  background: var(--void);
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}

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

.mono { font-family: var(--font-mono); }
.container { max-width: var(--container); margin: 0 auto; padding: 0 24px; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

.skip-link {
  position: absolute; left: 16px; top: -60px; z-index: 200;
  background: var(--neon-plum); color: #0A141A; padding: 10px 16px; border-radius: 8px;
  text-decoration: none; transition: top 0.2s;
}
.skip-link:focus { top: 12px; }

:focus-visible { outline: 3px solid var(--plum); outline-offset: 3px; }

/* ============ type ============ */
h1, h2, h3 { font-family: var(--font-display); font-weight: 400; line-height: 1.02; text-transform: uppercase; letter-spacing: -0.01em; }
h2 { font-size: clamp(2rem, 4.4vw, 3.4rem); }
h3 { font-size: 1.15rem; letter-spacing: 0.02em; }

.eyebrow {
  display: inline-block; font-size: 0.78rem; font-weight: 500;
  text-transform: uppercase; letter-spacing: 0.14em; color: var(--plum-lit);
  border: 1.5px solid currentColor; padding: 4px 12px; border-radius: 999px;
  margin-bottom: 18px;
}
.section-lede { max-width: 54ch; color: var(--gray); margin-top: 16px; }
.section-dark .section-lede { color: var(--gray); }
.accent { color: var(--plum-lit); }

/* ============ header ============ */
.site-header {
  position: sticky; top: 0; z-index: 100;
  background: rgba(15, 28, 36, 0.86);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line);
  transition: box-shadow 0.3s ease, background 0.3s ease;
}
.site-header.is-stuck {
  background: rgba(15, 28, 36, 0.96);
  box-shadow: 0 6px 26px rgba(0, 0, 0, 0.45);
}
.header-inner {
  max-width: var(--container); margin: 0 auto; padding: 14px 24px;
  display: flex; align-items: center; justify-content: space-between; gap: 24px;
}
.brand { display: flex; align-items: center; text-decoration: none; }
.brand-logo {
  /* Taller than a plain wordmark would need: this logotype is fine ornate
     script, and below ~44px the strokes close up into a blur. */
  width: auto; height: 30px;
  transition: opacity 0.15s ease;
}
.brand:hover .brand-logo { opacity: 0.72; }

.site-nav { display: flex; align-items: center; gap: 26px; }
.nav-foot { display: contents; }        /* desktop: children stay inline in the bar */
.nav-contact { display: none; }         /* mobile-only detail */
.site-nav a {
  text-decoration: none; font-weight: 600; font-size: 0.85rem;
  text-transform: uppercase; letter-spacing: 0.07em;
}
.site-nav a:not(.nav-cta):hover { color: var(--plum-lit); }
.nav-cta {
  background: var(--plum); color: #fff; padding: 9px 18px; border-radius: 999px;
  white-space: nowrap;              /* "€1 pass" must never break onto two lines */
  transition: transform 0.15s ease, background 0.15s ease;
}
.site-nav > a, .nav-trigger, .lang-btn { white-space: nowrap; }
.nav-cta:hover { background: var(--neon-plum); color: #0A141A; transform: rotate(-2deg); }

/* ---- dropdown groups ---- */
.nav-group { position: relative; }
.nav-trigger {
  display: inline-flex; align-items: center; gap: 6px;
  font: inherit; font-weight: 600; font-size: 0.85rem;
  text-transform: uppercase; letter-spacing: 0.07em;
  background: none; border: 0; padding: 0; cursor: pointer; color: inherit;
}
.nav-trigger::after {
  content: ""; width: 6px; height: 6px; margin-top: -3px;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(45deg); transition: transform 0.2s var(--ease-out);
}
.nav-group[data-open="true"] .nav-trigger { color: var(--plum-lit); }
.nav-group[data-open="true"] .nav-trigger::after { transform: rotate(-135deg); margin-top: 2px; }

.nav-menu {
  position: absolute; top: calc(100% + 14px); left: -14px; z-index: 120;
  min-width: 208px; padding: 8px;
  background: var(--deep); border: 1.5px solid rgba(232, 95, 208, 0.3); border-radius: 14px;
  box-shadow: 0 14px 34px rgba(20, 38, 46, 0.16);
  opacity: 0; visibility: hidden; transform: translateY(-6px);
  transition: opacity 0.18s var(--ease-out), transform 0.18s var(--ease-out), visibility 0.18s;
}
.nav-group[data-open="true"] .nav-menu { opacity: 1; visibility: visible; transform: none; }
.nav-menu a {
  display: block; padding: 10px 14px; border-radius: 9px;
  font-size: 0.82rem; letter-spacing: 0.05em;
}
.nav-menu a:hover { background: var(--plum); color: #fff; }
.nav-menu a[aria-current="page"] { color: var(--plum-lit); }

/* ---- language switcher ---- */
.lang-switch { display: flex; gap: 2px; padding: 3px; border: 1.5px solid var(--line); border-radius: 999px; }
.lang-btn {
  display: inline-flex; align-items: center; gap: 5px;
  font: inherit; font-family: var(--font-mono); font-size: 0.72rem; font-weight: 600;
  letter-spacing: 0.06em; padding: 6px 10px; border: 0; border-radius: 999px;
  background: none; color: var(--gray); cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
/* Flags render as regional-indicator pairs; Windows shows the letters
   instead, which is why the EN/ES/FR label always stays alongside. */
.lang-flag {
  font-size: 0.95em; line-height: 1;
  font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif;
}
.lang-btn:hover { color: var(--ink); }
.lang-btn.is-active { background: var(--plum); color: #fff; }

.nav-toggle { display: none; background: none; border: 0; cursor: pointer; padding: 8px; }
.nav-toggle span { display: block; width: 24px; height: 2.5px; background: var(--ink); margin: 5px 0; border-radius: 2px; transition: transform 0.2s, opacity 0.2s; }

/* ============ hero video ============
   Footage sits behind the copy under a tinted gradient so the headline
   keeps its contrast no matter which frame is on screen. */
/* The footage is decoration behind a tint and must never take a tap. iOS draws
   its own play button over a paused video (Low Power Mode blocks autoplay),
   and tapping that native control hands playback to the fullscreen player —
   making the element inert means the tap falls through to the page instead,
   where the gesture handler in main.js starts it inline. */
.hero-video { position: absolute; inset: 0; z-index: 0; overflow: hidden; pointer-events: none; }
.hero-video video {
  width: 100%; height: 100%; object-fit: cover;
  filter: saturate(1.15) contrast(1.05);
  pointer-events: none;
}
.hero-video video::-webkit-media-controls,
.hero-video video::-webkit-media-controls-start-playback-button {
  display: none !important;
  -webkit-appearance: none;
}
.hero-video-tint {
  position: absolute; inset: 0;
  background:
    /* Bottom stop is near-opaque so the footage dissolves into the page
       instead of ending on a visible seam at the section edge. */
    linear-gradient(180deg, rgba(10,8,12,0.80) 0%, rgba(10,8,12,0.62) 42%, rgba(10,8,12,0.98) 100%),
    linear-gradient(105deg, rgba(143, 78, 131,0.42) 0%, transparent 48%, rgba(199, 123, 184,0.30) 100%);
  mix-blend-mode: normal;
}
/* faint scanline texture ties the footage to the poster-print feel */
.hero-video-tint::after {
  content: ""; position: absolute; inset: 0; opacity: 0.16;
  background: repeating-linear-gradient(0deg, rgba(0,0,0,0.5) 0 1px, transparent 1px 3px);
}

/* ============ hero ============ */
.hero {
  position: relative; overflow: hidden;
  padding: clamp(56px, 11vh, 130px) 0 clamp(52px, 8vh, 100px);
  text-align: center;
}
/* A plum wash bleeding from the top so the black never reads as an empty
   canvas, and the hero has somewhere to sit. */
.hero::before {
  content: ""; position: absolute; inset: -30% 0 auto; height: 90%;
  background:
    radial-gradient(52% 60% at 50% 8%, rgba(143, 78, 131, 0.34), transparent 68%),
    radial-gradient(40% 46% at 82% 26%, rgba(217, 164, 65, 0.10), transparent 70%);
  pointer-events: none; z-index: 1;
}
.hero-inner {
  max-width: 960px; margin: 0 auto; padding: 0 24px;
  position: relative; z-index: 2;
  display: flex; flex-direction: column; align-items: center;
}
.hero-inner .eyebrow { margin-bottom: 26px; }
.hero-inner h1 { font-size: clamp(2.6rem, 7.4vw, 5.4rem); line-height: 0.94; }
.hero-inner .hero-blurb { max-width: 52ch; margin: 0 auto; }
.hero-inner .hero-actions { justify-content: center; }

/* Stats: the three numbers that answer "is this worth the trip". */
.hero-stats {
  list-style: none; display: flex; flex-wrap: wrap; justify-content: center;
  gap: clamp(24px, 6vw, 72px); margin-top: clamp(34px, 5vh, 56px);
  padding-top: clamp(26px, 4vh, 40px); border-top: 1px solid var(--line);
  width: 100%;
}
.hero-stats li { display: flex; flex-direction: column; gap: 4px; }
.hero-stats strong {
  font-family: var(--font-display); font-size: clamp(1.9rem, 4.4vw, 3rem);
  line-height: 1; color: var(--ink);
}
.hero-stats li:last-child strong { color: var(--acid); }
.hero-stats span {
  font-family: var(--font-mono); font-size: 0.72rem; text-transform: uppercase;
  letter-spacing: 0.16em; color: var(--gray);
}

.hero-kicker { text-shadow: 0 1px 12px rgba(0,0,0,0.6); font-size: 0.82rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--gray); margin-bottom: 22px; }

.hero-title {
  text-shadow: 0 4px 40px rgba(0,0,0,0.5);
  font-size: clamp(3.5rem, 9vw, 8.5rem);
  line-height: 0.86; letter-spacing: -0.02em;
}
.hero-title .line { display: block; }
.line-outline {
  color: transparent;
  -webkit-text-stroke: 3px var(--neon-amber);
  text-stroke: 3px var(--neon-amber);
}
.title-dot { color: var(--plum-lit); }

.hero-meta {
  display: grid; grid-template-columns: auto 1fr; gap: 40px; align-items: end;
  margin-top: clamp(28px, 4vh, 48px); max-width: 980px;
}
.hero-dates { font-family: var(--font-display); font-size: clamp(1rem, 2.2vw, 1.3rem); letter-spacing: 0.02em; color: var(--plum-lit); margin: 18px 0 20px; }
.hero-dates span { color: var(--ink); }
.date-num { font-size: clamp(2.4rem, 5vw, 4rem); }
.date-sep { color: var(--plum-lit); font-size: clamp(1.6rem, 3vw, 2.6rem); }
.date-month {
  font-family: var(--font-mono); font-size: 0.85rem; text-transform: uppercase;
  letter-spacing: 0.12em; line-height: 1.3; margin-left: 10px; color: var(--gray);
}
.hero-blurb { color: var(--ink-soft); max-width: 46ch; text-shadow: 0 1px 10px rgba(0,0,0,0.55); }
.hero-actions { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 26px; grid-column: 1 / -1; }

/* buttons */
.btn {
  display: inline-flex; align-items: center; gap: 10px;
  font-weight: 700; font-size: 0.9rem; text-transform: uppercase; letter-spacing: 0.06em;
  text-decoration: none; padding: 15px 28px; border-radius: 999px; border: 2px solid transparent;
  cursor: pointer; transition: transform 0.15s ease, background 0.15s ease, color 0.15s ease;
}
.btn-primary { background: var(--plum); color: #fff; }
.btn-primary:hover { background: var(--neon-plum); color: #0A141A; transform: translateY(-2px) rotate(-1deg); }
.btn-ghost { border-color: var(--ink); color: var(--ink); background: transparent; }
.btn-ghost:hover { background: var(--ink); color: var(--void); border-color: var(--ink); }
.btn-ghost-light { border-color: var(--ink); color: var(--ink); }
.btn-ghost-light:hover { background: var(--ink); color: var(--deep); }
.btn-lg { padding: 18px 34px; font-size: 1rem; }

/* spray splat */
.hero-splat {
  position: absolute; z-index: 1; pointer-events: none;
  width: 560px; height: 560px; right: -140px; bottom: -220px;
  background: radial-gradient(circle at 40% 40%, rgba(31,185,165,0.35), transparent 62%);
  filter: blur(2px);
}

/* ============ ticker ============ */
.ticker { background: var(--deep); color: var(--ink); overflow: hidden; padding: 14px 0; border-block: 3px solid var(--deep); }
.ticker-track {
  display: flex; gap: 28px; align-items: center; width: max-content;
  animation: ticker 26s linear infinite;
  font-family: var(--font-display); text-transform: uppercase; font-size: 1.05rem; letter-spacing: 0.04em;
  white-space: nowrap;
}
.ticker-track i { color: var(--plum-lit); font-style: normal; }
@keyframes ticker { to { transform: translateX(-50%); } }

/* ============ stats band ============
   The poster's teal used at full-surface scale. */
.stats-band { background: var(--amber); color: #0A141A; padding: clamp(44px, 6vh, 76px) 0; }
.stats {
  list-style: none; display: grid; grid-template-columns: repeat(3, 1fr);
  gap: 24px; text-align: center;
}
.stat { position: relative; }
.stat + .stat::before {
  content: ""; position: absolute; left: -12px; top: 12%; bottom: 12%;
  width: 1.5px; background: rgba(20, 38, 46, 0.22);
}
.stat-num {
  display: block;
  font-family: var(--font-display); line-height: 0.94;
  font-size: clamp(2.6rem, 7vw, 5rem);
  font-variant-numeric: tabular-nums;   /* stops digits jittering while counting */
  letter-spacing: -0.02em;
}
.stat-label {
  display: block; margin-top: 12px;
  font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.16em;
  color: rgba(10, 20, 26, 0.78);
}

/* ============ sections ============ */
.section { padding: clamp(64px, 10vh, 120px) 0; }
.section-head { margin-bottom: clamp(36px, 5vh, 56px); }
.section-dark {
  background: var(--surface-2); color: var(--ink);
  position: relative; isolation: isolate;
}
/* Slow-drifting colour wash so dark sections aren't flat black */
.section-dark::before {
  content: ""; position: absolute; inset: -20% -10%; z-index: -1; pointer-events: none;
  background:
    radial-gradient(38% 44% at 12% 18%, rgba(232, 95, 208, 0.20), transparent 70%),
    radial-gradient(34% 40% at 88% 26%, rgba(232, 95, 208, 0.16), transparent 70%),
    radial-gradient(40% 46% at 62% 88%, rgba(255, 208, 61, 0.12), transparent 70%);
  filter: blur(28px);
  animation: aurora 26s ease-in-out infinite alternate;
}
@keyframes aurora {
  0%   { transform: translate3d(0, 0, 0) scale(1); }
  50%  { transform: translate3d(2%, -3%, 0) scale(1.08); }
  100% { transform: translate3d(-2%, 2%, 0) scale(1.04); }
}
.section-dark .eyebrow { color: var(--amber-lit); }

/* pillars */
.pillars { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; }
.pillar {
  display: flex; flex-direction: column; text-decoration: none; color: inherit;
  background: var(--surface); border: 1.5px solid var(--line); border-radius: var(--radius);
  padding: 28px 24px 26px; position: relative; overflow: hidden;
}
.pillar-more {
  margin-top: auto; padding-top: 18px;
  font-family: var(--font-mono); font-size: 0.72rem;
  text-transform: uppercase; letter-spacing: 0.12em; color: var(--plum-lit);
  display: inline-flex; align-items: center; gap: 7px;
  transition: gap 0.18s var(--ease-out);
}
.pillar:hover .pillar-more { gap: 13px; }
.pillar::before {
  content: ""; position: absolute; inset: 0 auto auto 0; width: 100%; height: 5px;
  background: var(--plum);
  transform: scaleX(0); transform-origin: left; transition: transform 0.25s ease;
}
.pillar:nth-child(2)::before { background: var(--amber); }
.pillar:nth-child(3)::before { background: var(--plum-lit); }
.pillar:nth-child(4)::before { background: var(--rose); }
.pillar:hover { border-color: var(--ink); }
.pillar:hover::before { transform: scaleX(1); }
.pillar h3 { margin-bottom: 12px; text-wrap: balance; }
/* The arena pillar carries a full event name rather than a one-word label —
   step it down so four cards still read as a set. */
.pillar h3.is-long { font-size: 1rem; line-height: 1.14; }
.pillar p { color: var(--gray); font-size: 0.97rem; }

/* ============ value strip ============ */
.value-strip { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.value {
  border: 1.5px solid var(--line-light); border-radius: var(--radius);
  padding: 28px 26px 30px;
}
.value:hover { border-color: var(--acid); }
.value-label {
  font-family: var(--font-mono); font-size: 0.72rem; text-transform: uppercase;
  letter-spacing: 0.16em; color: var(--acid); margin-bottom: 14px;
}
.value h3 { font-size: clamp(1.05rem, 1.7vw, 1.4rem); line-height: 1.12; }

/* ============ artists ============ */
/* Search sits above the country chips: with 170+ names, scanning the grid
   for one person is the slow path. The two narrow together — a query is
   applied within whatever country chip is active. */
.artist-search { position: relative; max-width: 440px; margin-bottom: 14px; }
.artist-search-input {
  width: 100%; box-sizing: border-box;
  font-family: var(--font-mono); font-size: 0.85rem; letter-spacing: 0.02em;
  padding: 13px 44px 13px 44px; border-radius: 999px;
  border: 1.5px solid var(--line); background: rgba(255, 255, 255, 0.03);
  color: var(--ink);
  transition: border-color 0.15s, box-shadow 0.15s, background 0.15s;
}
.artist-search-input::placeholder { color: var(--gray); }
.artist-search-input:hover { border-color: var(--ink-soft); }
.artist-search-input:focus {
  outline: none; border-color: var(--amber-lit);
  background: rgba(255, 255, 255, 0.05);
  box-shadow: var(--glow-sm) rgba(199, 123, 184, 0.35);
}
/* The browser's own clear affordance is inconsistent across engines and
   ignores the pill shape — we draw our own below. */
.artist-search-input::-webkit-search-decoration,
.artist-search-input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }

.artist-search-icon {
  position: absolute; left: 16px; top: 50%; transform: translateY(-50%);
  width: 17px; height: 17px; color: var(--gray); pointer-events: none;
  stroke-linecap: round;
}
/* :focus-within, not a sibling selector — the icon precedes the input. */
.artist-search:focus-within .artist-search-icon { color: var(--amber-lit); }

.artist-search-clear {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  width: 30px; height: 30px; display: flex; align-items: center; justify-content: center;
  border: 0; border-radius: 50%; background: transparent;
  color: var(--gray); font-size: 1.4rem; line-height: 1; cursor: pointer;
  transition: color 0.15s, background 0.15s;
}
.artist-search-clear:hover { color: var(--ink); background: rgba(255, 255, 255, 0.08); }

/* Empty state — spans the whole grid rather than sitting in column one. */
.artist-none {
  grid-column: 1 / -1; text-align: center; padding: 54px 20px;
  border: 1.5px dashed var(--line); border-radius: 14px;
}
.artist-none strong {
  display: block; font-family: var(--font-display);
  font-size: 1.1rem; text-transform: uppercase; margin-bottom: 8px; color: var(--ink);
}
.artist-none span { color: var(--gray); font-size: 0.9rem; }

.filter-bar { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 34px; }
.chip {
  font-family: var(--font-mono); font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.08em;
  padding: 9px 18px; border-radius: 999px; border: 1.5px solid var(--line);
  background: transparent; color: var(--ink); cursor: pointer;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.chip:hover { border-color: var(--ink); }
.chip-n { opacity: 0.5; font-size: 0.9em; margin-left: 2px; }
.chip.is-active .chip-n { opacity: 0.7; }
.chip.is-active { background: var(--plum); color: #fff; border-color: var(--plum); }

.artist-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
.artist-card {
  display: block; text-decoration: none; color: inherit;
  width: 100%; padding: 0; font: inherit; text-align: left; cursor: pointer;
  background: var(--surface); border: 1.5px solid var(--line); border-radius: var(--radius);
  overflow: hidden;
}
.artist-card:hover, .artist-card:focus-visible { border-color: var(--plum); }
.artist-photo { position: relative; aspect-ratio: 1; overflow: hidden; background: var(--ink-soft); }
/* Two stacked layers so a shot change cross-fades instead of flashing white
   while the next file decodes. Only the top layer is ever swapped. */
.artist-photo img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
  opacity: 0; transition: opacity 900ms var(--ease-out);
}
.artist-photo img.is-on { opacity: 1; }

/* Progress pips — three faint marks so it reads as a set, not a glitch. */
.shot-pips {
  position: absolute; left: 0; right: 0; bottom: 8px; z-index: 2;
  display: flex; justify-content: center; gap: 5px;
  opacity: 0; transition: opacity 0.3s ease; pointer-events: none;
}
.artist-card.is-cycling .shot-pips { opacity: 1; }
.shot-pips i {
  width: 4px; height: 4px; border-radius: 50%;
  background: rgba(255, 255, 255, 0.4);
  box-shadow: 0 0 0 1px rgba(10, 20, 26, 0.35);
  transition: background 0.4s ease, box-shadow 0.4s ease;
}
.shot-pips i.is-on {
  background: var(--neon-plum);
  box-shadow: 0 0 6px rgba(232, 95, 208, 0.9);
}
@media (prefers-reduced-motion: reduce) {
  .artist-photo img { transition: none; }
  .shot-pips { display: none; }
}

.artist-info { padding: 14px 16px 16px; }
.artist-info h3 {
  font-family: var(--font-body); font-weight: 700; font-size: 0.95rem;
  text-transform: none; letter-spacing: 0; line-height: 1.25;
}
.artist-info p {
  font-family: var(--font-mono); font-size: 0.7rem; color: var(--gray);
  text-transform: uppercase; letter-spacing: 0.06em; margin-top: 6px; line-height: 1.4;
}

.grid-footer {
  display: flex; flex-direction: column; align-items: center; gap: 12px;
  margin-top: 36px;
}
.grid-count { font-size: 0.75rem; color: var(--gray); text-transform: uppercase; letter-spacing: 0.12em; }
.grid-note { margin-top: 22px; text-align: center; font-size: 0.8rem; color: var(--gray); text-transform: uppercase; letter-spacing: 0.08em; }
.grid-note a { color: var(--plum-lit); }

/* ============ program ============ */
.day-tabs { display: flex; gap: 12px; margin-bottom: 36px; flex-wrap: wrap; }
.day-tab {
  flex: 1 1 160px; text-align: left; cursor: pointer;
  background: transparent; color: var(--ink);
  border: 1.5px solid var(--line-light); border-radius: var(--radius);
  padding: 18px 22px; transition: background 0.15s, border-color 0.15s;
}
.day-tab .day-name { display: block; font-family: var(--font-display); text-transform: uppercase; font-size: 1.2rem; }
.day-tab .day-hours { display: block; font-size: 0.78rem; color: rgba(246, 224, 218,0.55); margin-top: 6px; letter-spacing: 0.08em; }
.day-tab:hover { border-color: var(--ink); }
.day-tab.is-active { background: var(--plum); border-color: var(--plum); }
.day-tab.is-active .day-hours { color: rgba(255,255,255,0.8); }

.timetable { list-style: none; border-top: 1px solid var(--line-light); }
/* Three columns: time, event, kind. The kind tag is the third — without its
   own track it wrapped under the time and doubled every row's height. */
.timetable li {
  display: grid; grid-template-columns: 92px 1fr auto; gap: 24px; align-items: baseline;
  padding: 16px 8px; border-bottom: 1px solid var(--line-light);
}
.timetable .tt-time { font-family: var(--font-mono); font-weight: 600; color: var(--amber-lit); font-size: 0.95rem; }
.timetable .tt-event { font-weight: 500; }
.timetable li:hover { background: rgba(246, 224, 218, 0.03); }

/* ============ tickets ============ */
.tickets-card {
  display: grid; grid-template-columns: 1.2fr 1fr; gap: clamp(32px, 5vw, 72px);
  background: var(--surface); border: 2px solid var(--plum); border-radius: 22px;
  padding: clamp(32px, 5vw, 64px);
  position: relative; overflow: hidden;
}
.tickets-card::after {
  content: ""; position: absolute; right: -80px; top: -80px; width: 260px; height: 260px;
  background: radial-gradient(circle, rgba(255,210,63,0.5), transparent 65%);
}
.tickets-copy .btn { margin-top: 28px; }
.fine-print { font-size: 0.75rem; color: var(--gray); margin-top: 16px; text-transform: uppercase; letter-spacing: 0.08em; }

.tickets-facts { list-style: none; display: grid; gap: 14px; align-content: center; position: relative; z-index: 1; }
.tickets-facts li {
  border: 1.5px solid var(--line); border-radius: var(--radius); padding: 16px 20px;
  display: grid; gap: 2px; background: var(--void);
}
.tickets-facts strong { font-family: var(--font-display); text-transform: uppercase; font-size: 0.95rem; }
.tickets-facts span { color: var(--gray); font-size: 0.92rem; }
/* ============ faq ============ */
.faq-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; }
.faq-col { background: var(--surface); border: 1.5px solid var(--line); border-radius: var(--radius); padding: 28px; }
.faq-col-title {
  display: inline-block; font-size: 1.4rem; padding: 6px 18px; border-radius: 10px; margin-bottom: 20px;
  transform: rotate(-1.5deg);
}
.faq-col-title.yes { background: var(--amber-deep); color: #fff; }
.faq-col-title.no { background: var(--plum); color: #fff; }
.faq-list { list-style: none; }
.faq-list li {
  padding: 12px 0 12px 26px; border-bottom: 1px solid var(--line);
  position: relative; font-size: 0.97rem; color: var(--ink-soft);
}
.faq-list li:last-child { border-bottom: 0; }
.faq-list li::before { content: "—"; position: absolute; left: 0; color: var(--gray); }

/* ============ newsletter ============ */
/* Malaga put this on a full-bleed pale panel. Here the ground stays black and
   the section earns attention with a bordered plum-lit card instead — acid is
   reserved for the price tag, so spending it on a whole background would blunt
   the one place it means something. */
.newsletter { background: var(--surface-2); text-align: center; }
/* Centred and narrow: it is a single ask at the end of the page, and left-
   aligning it against a full-width section left a void the eye reads as a
   missing column. */
.newsletter .container { max-width: 680px; }
.newsletter .section-head { margin-bottom: 30px; }
.newsletter .section-lede { margin-left: auto; margin-right: auto; }
.newsletter .signup-form { margin: 0 auto; justify-content: center; }
.newsletter .fine-print { margin-top: 20px; }

.signup-form {
  display: flex; flex-wrap: wrap; gap: 12px; align-items: center;
  max-width: 560px;
}
.signup-form input[type="email"] {
  flex: 1 1 260px; min-width: 0; font: inherit; font-size: 1rem;
  padding: 15px 22px; border-radius: 999px; color: var(--ink);
  border: 1.5px solid var(--line); background: rgba(255, 255, 255, 0.04);
  transition: border-color 0.15s, box-shadow 0.15s, background 0.15s;
}
.signup-form input[type="email"]::placeholder { color: var(--gray); }
.signup-form input[type="email"]:hover { border-color: var(--ink-soft); }
.signup-form input[type="email"]:focus {
  outline: none; border-color: var(--plum-lit);
  background: rgba(255, 255, 255, 0.06);
  box-shadow: var(--glow-sm) rgba(199, 123, 184, 0.4);
}
.signup-form .btn { flex: 0 0 auto; }
/* The status line takes the full row so a long message never squeezes the
   input, and it holds its height so the form does not jump when one appears. */
.signup-form .form-note { flex: 1 0 100%; margin: 2px 0 0; min-height: 1.2em; }

/* ============ prose (privacy, hostess) ============ */
.prose { max-width: 74ch; }
.prose h2 {
  font-size: clamp(1.15rem, 2.2vw, 1.45rem); margin: 42px 0 14px;
  padding-top: 22px; border-top: 1px solid var(--line);
}
.prose h2:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
.prose p { color: var(--ink-soft); line-height: 1.8; margin-bottom: 16px; }
.prose ul { margin: 0 0 18px 20px; }
.prose li { color: var(--ink-soft); line-height: 1.8; margin-bottom: 8px; }
.prose a { color: var(--plum-lit); }
.prose strong { color: var(--ink); }
.prose code {
  font-family: var(--font-mono); font-size: 0.86em;
  padding: 2px 6px; border-radius: 5px;
  background: rgba(246, 224, 218, 0.08); color: var(--amber-lit);
}
.prose .btn { margin-top: 8px; }

/* ============ address blocks ============ */
.venue-address {
  font-style: normal; font-size: 1.02rem; line-height: 1.85;
  color: var(--ink-soft); margin: 4px 0 26px;
  padding-left: 18px; border-left: 2px solid var(--plum);
}

/* ============ footer ============ */
.site-footer { background: var(--deep); color: var(--ink); padding: 64px 0 32px; }
.footer-grid { display: grid; grid-template-columns: 1.3fr 1fr 1fr 1.2fr; gap: 40px; padding-bottom: 48px; border-bottom: 1px solid var(--line-light); }
.footer-logo { width: auto; height: 40px; margin-bottom: 4px; }
.footer-tag { margin-top: 16px; color: rgba(246, 224, 218, 0.65); font-size: 0.95rem; }
.footer-grid h4 { font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.14em; color: var(--amber-lit); margin-bottom: 16px; font-weight: 500; }
.footer-grid a { display: block; text-decoration: none; padding: 5px 0; color: rgba(246, 224, 218,0.85); font-size: 0.95rem; }
.footer-grid a:hover { color: var(--plum-lit); }
.footer-addr { color: rgba(246, 224, 218,0.55); font-size: 0.85rem; margin-top: 10px; line-height: 1.7; }
.footer-legal { display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; padding-top: 24px; font-size: 0.82rem; color: rgba(246, 224, 218,0.5); }
.footer-legal a { color: rgba(246, 224, 218,0.7); }
/* Sits inside the copyright line rather than beside it, so the organiser reads
   as a credit on this show and not as another navigation link. */
.footer-parent { text-decoration: none; border-bottom: 1px solid rgba(246, 224, 218, 0.22); }
.footer-parent:hover { color: var(--plum-lit); border-bottom-color: currentColor; }

/* ============ page hero (subpages) ============ */
.page-hero {
  position: relative; overflow: hidden;
  padding: clamp(48px, 7vh, 92px) 0 clamp(36px, 5vh, 60px);
  border-bottom: 1.5px solid var(--line);
}
.page-hero h1 { font-size: clamp(2.5rem, 7.5vw, 5.4rem); line-height: 0.94; }
.page-hero .hero-blurb { margin-top: 22px; }
.page-hero .hero-actions { margin-top: 28px; }
.page-hero::after {
  content: ""; position: absolute; pointer-events: none;
  width: 420px; height: 420px; right: -150px; top: -170px;
  background: radial-gradient(circle at 45% 45%, rgba(31,185,165,0.3), transparent 62%);
}
.page-hero .container { position: relative; z-index: 1; }

/* active nav item */
.site-nav a[aria-current="page"]:not(.nav-cta) { color: var(--plum-lit); }
.site-nav a[aria-current="page"].nav-cta { background: var(--neon-plum); color: #0A141A; }

/* ============ teaser blocks (home) ============ */
.teaser-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 24px; flex-wrap: wrap; margin-bottom: clamp(28px, 4vh, 44px);
}
.teaser-head .section-head { margin-bottom: 0; }
.link-arrow {
  display: inline-flex; align-items: center; gap: 8px; white-space: nowrap;
  font-weight: 700; font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.07em;
  text-decoration: none; padding-bottom: 5px; border-bottom: 2px solid var(--plum);
  transition: gap 0.18s var(--ease-out), color 0.18s ease;
}
.link-arrow:hover { color: var(--plum-lit); gap: 14px; }
.section-dark .link-arrow { border-bottom-color: var(--amber-lit); }
.section-dark .link-arrow:hover { color: var(--amber-lit); }

/* day cards linking through to the program */
.day-cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
.day-card {
  display: block; text-decoration: none; padding: 30px 26px 34px;
  border: 1.5px solid var(--line-light); border-radius: var(--radius);
}
.day-card:hover { background: rgba(246, 224, 218,0.05); border-color: var(--ink); }
.day-card .day-name { display: block; font-family: var(--font-display); text-transform: uppercase; font-size: 1.5rem; }
.day-card .day-hours { display: block; font-family: var(--font-mono); font-size: 0.8rem; color: var(--amber-lit); letter-spacing: 0.1em; margin-top: 8px; }
.day-card .day-peek { display: block; color: rgba(246, 224, 218,0.6); font-size: 0.92rem; margin-top: 16px; }

/* ============ full-width CTA band ============ */
.cta-band { background: var(--plum); color: #fff; text-align: center; padding: clamp(56px, 9vh, 104px) 0; }
.cta-band h2 { font-size: clamp(2rem, 5vw, 3.6rem); }
.cta-band p { max-width: 48ch; margin: 18px auto 0; color: rgba(255,255,255,0.85); }
.cta-band .btn { margin-top: 30px; }
.cta-band .btn-primary { background: var(--deep); color: var(--ink); }
.cta-band .btn-primary:hover { background: var(--neon-brass); color: #0A141A; }
.cta-band .fine-print { color: rgba(255,255,255,0.75); }

/* ============ traders ============ */
.offer-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
.offer {
  background: var(--surface); border: 1.5px solid var(--line); border-radius: var(--radius);
  padding: 26px 24px 30px;
}
.offer h3 { margin-bottom: 10px; }
.offer p { color: var(--gray); font-size: 0.96rem; }

.stand-split { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(28px, 5vw, 64px); align-items: start; }
.stand-list { list-style: none; display: grid; gap: 12px; margin-top: 24px; }
.stand-list li {
  display: grid; grid-template-columns: auto 1fr; gap: 14px; align-items: baseline;
  padding: 14px 0; border-bottom: 1px solid var(--line-light);
}
.stand-list li:last-child { border-bottom: 0; }
.stand-list .mono { color: var(--amber-lit); font-size: 0.8rem; letter-spacing: 0.1em; text-transform: uppercase; }

/* The stand render ships on transparency, so it needs no frame — it sits
   straight on the dark section and the floor fades into it. */
.stand-shot { margin: 0; }
.stand-shot img { display: block; width: 100%; height: auto; }
.stand-shot figcaption {
  margin-top: 10px; color: var(--gray);
  font-size: 0.74rem; letter-spacing: 0.1em; text-transform: uppercase;
}
@media (max-width: 900px) { .stand-shot { max-width: 460px; } }

/* ============ entertainment gallery ============
   Masonry-ish columns so portrait and landscape shots sit together
   without cropping either. */
.gallery-wrap { position: relative; }
.gallery {
  display: flex; gap: 14px; overflow-x: auto; scroll-snap-type: x mandatory;
  scroll-behavior: smooth; padding: 4px 2px 14px;
  scrollbar-width: none; -ms-overflow-style: none;
}
.gallery::-webkit-scrollbar { display: none; }
.gallery figure {
  flex: 0 0 clamp(220px, 26vw, 320px); margin: 0; scroll-snap-align: start;
  aspect-ratio: 3 / 4; overflow: hidden; border-radius: 12px;
  border: 1.5px solid var(--line-light);
}
.gallery figure img { width: 100%; height: 100%; object-fit: cover; }

/* arrows so it can be driven without swiping */
.gallery-btn {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 3;
  width: 48px; height: 48px; display: grid; place-items: center;
  border: 1.5px solid rgba(232, 95, 208, 0.4); border-radius: 50%; cursor: pointer;
  background: rgba(10, 20, 26, 0.85); color: var(--ink); font-size: 1.3rem;
  transition: background 0.18s ease, box-shadow 0.18s ease, opacity 0.18s ease;
}
.gallery-btn:hover { background: var(--plum); box-shadow: var(--glow-md) rgba(232, 95, 208, 0.7); }
.gallery-btn[disabled] { opacity: 0.25; cursor: default; }
.gallery-prev { left: -10px; }
.gallery-next { right: -10px; }
@media (max-width: 720px) {
  .gallery-prev { left: 2px; }
  .gallery-next { right: 2px; }
}
.gallery img {
  width: 100%; height: auto; border-radius: 8px; display: block;
  background: var(--ink-soft);
  transition: transform 0.3s var(--ease-out), filter 0.3s ease;
}
.gallery figure:hover img { transform: scale(1.02); filter: saturate(1.1); }

/* ============ cookie banner ============ */
.cookie {
  position: fixed; z-index: 200; inset: auto 16px 16px 16px;
  max-width: 560px; margin-inline: auto;
  background: var(--deep); color: var(--ink);
  border: 1.5px solid var(--line-light); border-radius: var(--radius);
  padding: 22px 24px;
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.35);
  display: none;
}
.cookie.is-open { display: block; animation: cookieIn 0.4s var(--ease-out); }
/* The notice outranks the mobile menu (z-index 200 vs 99) and was sitting on
   top of the language switcher and pass button. Two stacked sheets is wrong
   anyway — stand the notice down while the menu is open; it returns on close.
   Same for the artist modal, which covers the whole screen at z-index 400. */
body.nav-open .cookie.is-open,
body.amodal-open .cookie.is-open { display: none; }
@keyframes cookieIn { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
.cookie p { font-size: 0.9rem; color: rgba(246, 224, 218, 0.75); margin-bottom: 16px; }
.cookie a { color: var(--amber-lit); }
.cookie-actions { display: flex; gap: 10px; flex-wrap: wrap; }
.cookie .btn { padding: 11px 22px; font-size: 0.8rem; }
.cookie .btn-ghost { border-color: rgba(246, 224, 218, 0.4); color: var(--ink); }
.cookie .btn-ghost:hover { background: var(--ink); color: var(--deep); }

/* ============ contest categories ============ */
.cat-days { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; align-items: start; }
.cat-day {
  background: var(--surface); border: 1.5px solid var(--line); border-radius: var(--radius);
  padding: 26px 24px 28px;
}
.section-dark .cat-day { background: rgba(246, 224, 218, 0.05); border-color: var(--line-light); }
.cat-day-title {
  font-size: 1.05rem; padding-bottom: 14px; margin-bottom: 6px;
  border-bottom: 2px solid var(--plum);
}
.section-dark .cat-day-title { border-bottom-color: var(--amber-lit); }
.cat-list { list-style: none; }
.cat-list li {
  padding: 12px 0 12px 26px; position: relative;
  border-bottom: 1px solid var(--line); font-size: 0.97rem;
}
.section-dark .cat-list li { border-bottom-color: var(--line-light); }
.cat-list li:last-child { border-bottom: 0; }
.cat-list li::before {
  content: "★"; position: absolute; left: 0; top: 12px;
  color: var(--plum-lit); font-size: 0.8rem;
}
.section-dark .cat-list li::before { color: var(--brass); }
.cat-note {
  display: block; font-family: var(--font-mono); font-size: 0.7rem;
  text-transform: uppercase; letter-spacing: 0.1em; color: var(--gray); margin-top: 3px;
}
.section-dark .cat-note { color: rgba(246, 224, 218, 0.55); }

/* ============ contest rules ============ */
.rule-list { list-style: none; counter-reset: rule; display: grid; gap: 2px; }
.rule-list li {
  counter-increment: rule; position: relative;
  padding: 18px 0 18px 54px; border-bottom: 1px solid var(--line);
  font-size: 0.98rem; color: var(--ink-soft);
}
.rule-list li:last-child { border-bottom: 0; }
.rule-list li::before {
  content: counter(rule, decimal-leading-zero);
  position: absolute; left: 0; top: 18px;
  font-family: var(--font-mono); font-size: 0.8rem; font-weight: 600;
  color: var(--plum-lit); letter-spacing: 0.06em;
}

.dq-list { list-style: none; display: grid; gap: 16px; }
.dq-list li {
  border: 1.5px solid var(--rose); border-radius: var(--radius);
  padding: 22px 26px; position: relative;
  color: var(--ink); font-size: 0.98rem;
}
.dq-list li::before {
  content: "!"; display: inline-grid; place-items: center;
  width: 22px; height: 22px; margin-right: 12px; vertical-align: -4px;
  border-radius: 50%; background: var(--rose); color: var(--ink);
  font-family: var(--font-display); font-size: 0.8rem;
}

/* ============ sponsor logo wall ============ */
.logo-wall { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
/* ============ confirmed traders ============
   The logos are opaque, mostly on their own
   black backgrounds, so a near-black square tile lets them sit edge to edge
   with no white frame. */
.trader-wall { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
.trader {
  display: block; text-decoration: none; color: inherit; text-align: center;
  padding: 22px 20px 20px; border-radius: var(--radius);
  border: 1.5px solid var(--line-light); background: rgba(246, 224, 218, 0.05);
}
.trader:hover { border-color: var(--amber-lit); background: rgba(246, 224, 218, 0.09); }
.trader-logo {
  aspect-ratio: 1 / 1; display: flex; align-items: center; justify-content: center;
  overflow: hidden; background: #0C0F13; border-radius: 10px; padding: 10px; margin-bottom: 16px;
}
.trader-logo img { max-width: 100%; max-height: 100%; width: auto; height: auto; object-fit: contain; }
.trader h3 { font-size: 0.95rem; }
.trader .mono {
  font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.12em;
  color: var(--gray); margin-top: 6px;
}
.section-dark .trader .mono { color: rgba(246, 224, 218, 0.5); }
.section-dark .trader-link { color: var(--amber-lit); }
a.trader:hover .trader-link { color: var(--void); }

.tier-head {
  display: flex; align-items: baseline; gap: 14px; margin: 0 0 20px;
  font-family: var(--font-mono); font-size: 0.75rem;
  text-transform: uppercase; letter-spacing: 0.16em; color: var(--plum-lit);
}
.tier-head::after { content: ""; flex: 1; height: 1px; background: var(--line); }
.tier + .tier { margin-top: 48px; }
.next-grid {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  gap: clamp(32px, 5vw, 72px); align-items: center;
}
.next-dates {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  font-family: var(--font-display); font-size: clamp(2rem, 4.5vw, 3.4rem);
  margin: 18px 0 4px; color: var(--rose);
}
.next-dates span {
  font-family: var(--font-mono); font-size: 0.9rem; color: var(--ink);
  text-transform: uppercase; letter-spacing: 0.14em;
}
.next-poster { width: clamp(210px, 24vw, 330px); transform: rotate(-2deg); }
.next-poster img {
  width: 100%; height: auto; border-radius: 6px;
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.45);
}
.prereg .btn-primary { background: var(--rose-deep); }
.prereg .btn-primary:hover { background: var(--ink); color: var(--deep); }

/* Confirmation line under either sign-up form. Teal for "done", red for
   "that failed" — never colour alone, the wording says which it is too.
   These two forms sit on opposite backgrounds, so the colours cannot be
   shared: the pre-registration block is near-black, the newsletter is the
   poster yellow. The light-on-dark pair scores 1.5:1 on yellow, which is
   not a readable message, it is a smudge. */
.form-note {
  font-size: 0.8rem; line-height: 1.5; margin-top: 10px;
  color: var(--amber-lit);
}
.form-note.is-bad { color: #FF9A8C; }

.newsletter .form-note { color: rgba(10, 20, 26, 0.82); }
/* One step deeper than --rose-deep, which only reaches 3.9:1 against the
   poster yellow. This clears AA at 5.6:1 and still reads as the same red. */
.newsletter .form-note.is-bad { color: #A31D13; }
.newsletter-form { flex-wrap: wrap; }
.newsletter-form .form-note { flex-basis: 100%; margin-top: 4px; }

/* ============ stage lineup ============ */
.stage-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.act {
  border: 1.5px solid var(--line-light); border-radius: var(--radius);
  padding: 24px; display: grid; gap: 8px; align-content: start;
}
.act:hover { border-color: var(--amber); }
.act h3 { font-size: 1.15rem; }
.act .act-kind { font-family: var(--font-mono); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.12em; color: var(--amber-lit); }
.act p { color: rgba(246, 224, 218, 0.65); font-size: 0.93rem; }
/* The act's Instagram is a button, not a footnote — for most visitors it is
   the only thing on the card they actually want to click. The handle rides
   inside it so the button still says whose account it opens. */
.act-ig { justify-self: start; margin-top: 4px; }
/* Not scoped to .act-ig: the hostess page uses the same handle-inside-a-button
   pattern, and .btn uppercases its text — a handle is lower case or it is a
   different handle. */
.act-handle {
  margin-left: 8px; font-size: 0.72rem; letter-spacing: 0.04em;
  color: var(--amber-lit); text-transform: lowercase;
}
@media (max-width: 400px) { .act-handle { display: none; } }

/* ============ motion ============
   One easing curve across the whole page so everything feels related:
   a quick start that settles, like a poster being pressed down. */
:root { --ease-out: cubic-bezier(0.22, 0.85, 0.3, 1); --stagger: 55ms; }

.reveal {
  opacity: 0;
  transform: translateY(26px) scale(0.985);
  transition:
    opacity 0.7s var(--ease-out),
    transform 0.7s var(--ease-out);
  transition-delay: calc(var(--i, 0) * var(--stagger));
  will-change: opacity, transform;
}
/* Artist cards drift in with a slight tilt that straightens out. Declared
   before the settled state so one .reveal.is-visible clears every variant —
   a per-variant `.x.reveal.is-visible` reset would outrank the :hover lift
   at the bottom of this file and the card would never leave the page. */
.artist-card.reveal { transform: translateY(30px) rotate(-1.2deg); }

.reveal.is-visible { opacity: 1; transform: none; will-change: auto; }

/* Pillars rise on a shared curve, accent bar sweeps after they land */
.pillar.reveal.is-visible::before {
  transform: scaleX(1);
  transition-delay: calc(var(--i, 0) * var(--stagger) + 0.35s);
}
.pillar:hover::before { transition-delay: 0s; }

/* Timetable rows cascade whenever the day changes */
.tt-enter {
  animation: rowIn 0.55s var(--ease-out) backwards;
  animation-delay: calc(var(--i, 0) * 38ms);
}
@keyframes rowIn {
  from { opacity: 0; transform: translateX(-14px); }
  to { opacity: 1; transform: none; }
}

/* Hero types itself into place on load */
.hero-title .line {
  animation: lineIn 0.9s var(--ease-out) backwards;
}
.hero-title .line:nth-child(1) { animation-delay: 0.05s; }
.hero-title .line:nth-child(2) { animation-delay: 0.16s; }
.hero-title .line:nth-child(3) { animation-delay: 0.27s; }
@keyframes lineIn {
  from { opacity: 0; transform: translateY(0.24em) skewY(2deg); }
  to { opacity: 1; transform: none; }
}
.hero-kicker, .hero-meta {
  animation: fadeUp 0.8s var(--ease-out) backwards;
}
.hero-kicker { animation-delay: 0.02s; }
.hero-meta { animation-delay: 0.42s; }
@keyframes fadeUp {
  from { opacity: 0; transform: translateY(16px); }
  to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; }
  .hero-title .line, .hero-kicker, .hero-meta, .tt-enter { animation: none; }
}

/* ============ responsive ============ */
@media (max-width: 1040px) {
  /* Posters step down before the type gets squeezed */
  .hero-inner, .next-grid { grid-template-columns: 1fr; gap: 36px; }
  .next-poster { width: min(280px, 60vw); margin: 0 auto; }
}

@media (max-width: 960px) {
  .pillars { grid-template-columns: repeat(2, 1fr); }
  /* Three-up on tablets: two would make each card wider than it is on a
     desktop, which reads as broken rather than roomy. */
  .artist-grid { grid-template-columns: repeat(3, 1fr); }
  .day-cards, .offer-grid, .stage-grid, .cat-days { grid-template-columns: 1fr; }
  .value-strip, .logo-wall, .trader-wall, .art-grid { grid-template-columns: repeat(2, 1fr); }
  .stand-split { grid-template-columns: 1fr; }
  .tickets-card, .venue-grid, .newsletter-inner { grid-template-columns: 1fr; }
  .hero-meta { grid-template-columns: 1fr; gap: 24px; }
}

/* The grouped nav needs more room than a phone breakpoint allows, so the
   overlay menu takes over at tablet width while the rest of the layout
   stays desktop until 720px. */
@media (max-width: 900px) {
  /* ---- nav ----
     backdrop-filter would make .site-header the containing block for this
     fixed panel, collapsing it to the header's height. Drop the blur on
     mobile and make the bar solid so the panel resolves against the viewport. */
  .site-header { backdrop-filter: none; background: var(--void); }
  .site-header.is-stuck { background: var(--void); box-shadow: 0 6px 26px rgba(0,0,0,0.5); }

  .site-nav {
    position: fixed; z-index: 99;
    top: var(--header-h, 61px); right: 0; bottom: 0; left: 0;
    flex-direction: column; align-items: stretch; gap: 0;
    background: var(--void); border-top: 2px solid var(--neon-plum);
    padding: 12px 22px 40px;
    display: none; overflow-y: auto;               /* long menu must scroll */
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
  }
  .site-nav.is-open { display: flex; }
  /* Rows share the space above the footer so the sheet reads as a full
     screen rather than a short list with a void under it. They still grow
     past their share when a group is expanded. */
  .site-nav > a,
  .site-nav > .nav-group { flex: 1 1 auto; min-height: 62px; }
  .site-nav > a {
    display: flex; align-items: center;
    padding: 8px 0; border-bottom: 1px solid var(--line); font-size: 1rem;
  }
  .nav-group { display: flex; flex-direction: column; justify-content: center; }

  /* Footer zone sits against the bottom of the panel so the sheet reads as
     full-height rather than a short list with dead space beneath it. */
  .nav-foot {
    display: flex; flex-direction: column; gap: 14px;
    margin-top: auto; padding-top: 26px;
    border-top: 1.5px solid var(--line);
  }
  .lang-switch { align-self: flex-start; margin: 0; }
  .lang-btn { padding: 10px 16px; min-height: 44px; font-size: 0.8rem; }
  .site-nav a.nav-cta {
    border: 0; text-align: center; margin: 0; padding: 17px;
    font-size: 0.95rem; justify-content: center;
  }
  .nav-contact {
    display: block; text-align: center;
    font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.06em;
    text-transform: none; color: var(--gray); padding: 4px 0 2px;
  }

  /* Groups become tap-to-expand accordions so the whole menu fits on screen */
  .nav-group { border-bottom: 1px solid var(--line); }
  .nav-trigger {
    width: 100%; justify-content: space-between;
    padding: 8px 0; min-height: 44px;
    cursor: pointer; font-size: 1rem; letter-spacing: 0.07em; color: inherit;
  }
  .nav-trigger::after { width: 8px; height: 8px; margin-top: -4px; }
  .nav-group[data-open="true"] .nav-trigger { color: var(--plum-lit); }

  .nav-menu {
    position: static; opacity: 1; visibility: visible; transform: none;
    min-width: 0; padding: 0; margin: 0;
    background: none; border: 0; box-shadow: none;
    max-height: 0; overflow: hidden;
    transition: max-height 0.3s var(--ease-out);
  }
  .nav-group[data-open="true"] { max-height: none; }
  .nav-group[data-open="true"] .nav-menu { max-height: 320px; padding-bottom: 10px; }
  .nav-menu a { padding: 12px 0 12px 16px; font-size: 0.92rem; }
  .nav-menu a:hover { background: none; color: var(--plum-lit); }
  .nav-toggle { display: block; }
  .nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(7.5px) rotate(45deg); }
  .nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
  .nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7.5px) rotate(-45deg); }
  /* scroll lock lives on .is-scroll-locked (set in main.js) — overflow:hidden
     alone is ignored by iOS Safari, so the body has to be pinned instead */
  body.nav-open { overflow: hidden; }
}

@media (max-width: 720px) {

  /* ---- rhythm: tighter sections, smaller gaps ---- */
  .section { padding: 56px 0; }
  .container, .hero-inner { padding-left: 20px; padding-right: 20px; }
  .section-head { margin-bottom: 28px; }
  h2 { font-size: clamp(1.75rem, 8vw, 2.3rem); }

  /* ---- hero ---- */
  .hero { padding: 28px 0 44px; }
  .hero-title { font-size: clamp(3.4rem, 21vw, 6rem); }
  .hero-kicker { font-size: 0.7rem; letter-spacing: 0.14em; margin-bottom: 16px; }
  .hero-blurb { font-size: 1rem; }
  .hero-actions .btn { width: 100%; justify-content: center; }
  .hero-dates { flex-wrap: wrap; }

  /* ---- grids collapse ---- */
  .faq-cols, .pillars, .value-strip { grid-template-columns: 1fr; }
  /* Artists stay two-up on phones — one card per row makes each portrait
     enormous and pushes the lineup off the screen. */
  .artist-grid { grid-template-columns: repeat(2, 1fr); gap: 12px; }
  .artist-info { padding: 11px 12px 13px; }
  .artist-info h3 { font-size: 0.85rem; }
  .artist-info p { font-size: 0.63rem; letter-spacing: 0.04em; margin-top: 5px; }
  .stats { grid-template-columns: 1fr; gap: 30px; }
  .stat + .stat::before { left: 22%; right: 22%; top: -15px; bottom: auto; width: auto; height: 1.5px; }
  .logo-wall, .trader-wall { grid-template-columns: repeat(2, 1fr); }
  .art-grid { grid-template-columns: 1fr; }
  .timetable li { grid-template-columns: 74px 1fr; gap: 12px; padding: 14px 4px; }
  .newsletter-form { flex-direction: column; }
  .newsletter-form .btn { justify-content: center; }
  .cookie { inset: auto 12px 12px 12px; padding: 20px; }
  .cookie .btn { flex: 1 1 auto; justify-content: center; min-height: 44px; }
  .prereg-row { flex-direction: column; }
  .prereg .btn { width: 100%; justify-content: center; }
  .prereg input, .prereg select { flex: 1 1 auto; width: 100%; }

  /* ---- comfortable tap targets (44px min) ---- */
  .chip { padding: 12px 18px; }
  .artist-search { max-width: none; }
  /* 16px exactly: iOS Safari zooms the page in on focus for anything
     smaller, which throws the grid off screen mid-search. */
  .artist-search-input { font-size: 16px; padding-top: 14px; padding-bottom: 14px; }
  .artist-search-clear { width: 38px; height: 38px; }
  .day-tab { flex: 1 1 100%; padding: 16px 20px; }
  .grid-footer .btn { width: 100%; justify-content: center; }
  .footer-grid a,
  .footer-legal a { display: flex; align-items: center; min-height: 44px; padding: 4px 0; }
  .link-arrow { min-height: 44px; align-items: center; }
  .brand { min-height: 44px; }
  .faq-list li { padding-top: 14px; padding-bottom: 14px; }

  /* ---- keep small labels legible (never below 12px) ---- */
  .hero-kicker { font-size: 0.8rem; }
  .eyebrow, .value-label, .act .act-kind, .grid-count,
  .stand-list .mono, .footer-grid h4, .artist-info p { font-size: 0.75rem; }
  .fine-print, .grid-note { font-size: 0.78rem; }
  .nav-toggle { padding: 10px; }
  .brand-logo { height: 28px; }

  /* ---- footer stacks ---- */
  .footer-grid { grid-template-columns: 1fr; gap: 30px; padding-bottom: 34px; }
  .footer-legal { flex-direction: column; gap: 10px; }

  /* ---- cards breathe less ---- */
  .pillar { padding: 24px 20px 22px; }
  .tickets-card { padding: 28px 22px; }
  .cta-band { padding: 52px 0; }
  .cta-band .btn { width: 100%; justify-content: center; }
}

@media (max-width: 420px) {
  .logo-wall { grid-template-columns: 1fr; }
  .artist-grid { gap: 10px; }
  .artist-info { padding: 9px 10px 11px; }
  .hero-title { font-size: clamp(3rem, 20vw, 4.6rem); }
}

/* ============================================================
   NEON / INTERACTION LAYER
   Glow is decoration only — every element underneath still meets
   contrast on its own, so nothing depends on the glow rendering.
   ============================================================ */

/* scroll progress ------------------------------------------------ */
.scroll-progress {
  position: fixed; top: 0; left: 0; height: 3px; width: 100%; z-index: 300;
  transform: scaleX(0); transform-origin: 0 50%;
  background: linear-gradient(90deg, var(--neon-plum), var(--neon-brass), var(--neon-amber));
  box-shadow: var(--glow-sm) rgba(232, 95, 208, 0.7);
  pointer-events: none;
}

/* buttons --------------------------------------------------------- */
.btn-primary {
  position: relative;
  box-shadow: var(--glow-sm) rgba(232, 95, 208, 0.35);
}
.btn-primary:hover {
  box-shadow: var(--glow-md) rgba(232, 95, 208, 0.75), 0 8px 22px rgba(20, 38, 46, 0.2);
}
.section-dark .btn-ghost-light:hover,
.cta-band .btn-primary:hover { box-shadow: var(--glow-md) rgba(255, 208, 61, 0.5); }

.nav-cta { box-shadow: var(--glow-sm) rgba(232, 95, 208, 0.4); }
.nav-cta:hover { box-shadow: var(--glow-md) rgba(232, 95, 208, 0.8); }

/* eyebrow pills get a faint halo ---------------------------------- */
.eyebrow { box-shadow: var(--glow-sm) rgba(232, 95, 208, 0.18); }
.section-dark .eyebrow { box-shadow: var(--glow-sm) rgba(232, 95, 208, 0.28); }

/* headings on dark pick up a soft neon edge ----------------------- */
.section-dark h2,
.next-edition h2 { text-shadow: 0 0 34px rgba(232, 95, 208, 0.18); }
.cta-band h2 { text-shadow: 0 0 40px rgba(255, 255, 255, 0.28); }

/* cards ----------------------------------------------------------- */
.offer:hover, .cat-day:hover { border-color: var(--plum); }

/* stats band glows ------------------------------------------------ */
.stats-band { position: relative; overflow: hidden; }
.stats-band::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(60% 120% at 50% 0%, rgba(255, 255, 255, 0.22), transparent 70%);
}
.stat-num { text-shadow: 0 0 30px rgba(20, 38, 46, 0.18); }

/* ticker gets a neon underline ------------------------------------ */
.ticker { box-shadow: inset 0 -3px 0 0 var(--neon-plum), 0 0 24px rgba(232, 95, 208, 0.25); }
.ticker-track i { text-shadow: var(--glow-sm) var(--neon-plum); }

/* links ----------------------------------------------------------- */
.link-arrow { position: relative; }
.link-arrow:hover { text-shadow: var(--glow-sm) rgba(232, 95, 208, 0.6); }
.section-dark .link-arrow:hover { text-shadow: var(--glow-sm) rgba(232, 95, 208, 0.7); }

/* chips ----------------------------------------------------------- */
.chip.is-active { box-shadow: var(--glow-sm) rgba(232, 95, 208, 0.45); }
.day-tab.is-active { box-shadow: var(--glow-md) rgba(232, 95, 208, 0.4); }

/* hero title gets a subtle chromatic lift ------------------------- */
.title-dot { text-shadow: var(--glow-md) rgba(232, 95, 208, 0.8); }
.date-sep { text-shadow: var(--glow-sm) rgba(232, 95, 208, 0.7); }

/* language switcher ----------------------------------------------- */
.lang-btn.is-active { box-shadow: var(--glow-sm) rgba(232, 95, 208, 0.35); }

@media (prefers-reduced-motion: reduce) {
  .section-dark::before { animation: none; }
  .scroll-progress { display: none; }
}

/* ============ artist modal ============ */
.amodal {
  position: fixed; inset: 0; z-index: 400;
  display: grid; place-items: center; padding: 24px;
  background: rgba(10, 20, 26, 0.82);
  backdrop-filter: blur(10px);
  opacity: 0; visibility: hidden;
  transition: opacity 0.28s var(--ease-out), visibility 0.28s;
}
.amodal.is-open { opacity: 1; visibility: visible; }

.amodal-card {
  position: relative; width: min(920px, 100%); max-height: 88vh; overflow: auto;
  display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  background: var(--deep); color: var(--ink);
  border: 1.5px solid rgba(232, 95, 208, 0.28); border-radius: 20px;
  box-shadow: var(--glow-lg) rgba(232, 95, 208, 0.22), 0 30px 80px rgba(0, 0, 0, 0.5);
  transform: translateY(18px) scale(0.97);
  transition: transform 0.32s var(--ease-out);
}
.amodal.is-open .amodal-card { transform: none; }

.amodal-figure { background: var(--surface-2); aspect-ratio: 1; position: relative; }
.shot-btn {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 2;
  width: 40px; height: 40px; display: grid; place-items: center;
  border: 0; border-radius: 50%; cursor: pointer;
  background: rgba(10, 20, 26, 0.8); color: var(--ink); font-size: 1.15rem;
  transition: background 0.15s ease, opacity 0.15s ease, box-shadow 0.15s ease;
}
.shot-btn:hover { background: var(--plum); box-shadow: var(--glow-sm) rgba(232, 95, 208, 0.8); }
.shot-btn[disabled] { opacity: 0.25; cursor: default; }
.shot-prev { left: 10px; }
.shot-next { right: 10px; }
.shot-dots {
  position: absolute; bottom: 12px; left: 0; right: 0; z-index: 2;
  display: flex; justify-content: center; gap: 8px;
}
.shot-dot {
  width: 9px; height: 9px; padding: 0; border: 0; border-radius: 50%; cursor: pointer;
  background: rgba(246, 224, 218, 0.4); transition: background 0.15s ease, box-shadow 0.15s ease;
}
.shot-dot.is-on { background: var(--neon-amber); box-shadow: var(--glow-sm) rgba(232, 95, 208, 0.9); }
.amodal-figure img { width: 100%; height: 100%; object-fit: cover; }

.amodal-body { padding: clamp(24px, 4vw, 40px); display: flex; flex-direction: column; }
.amodal-country {
  font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--neon-amber);
  text-shadow: var(--glow-sm) rgba(232, 95, 208, 0.5); margin-bottom: 12px;
}
.amodal-body h3 {
  font-size: clamp(1.5rem, 3vw, 2.2rem); line-height: 1.05; margin-bottom: 10px;
  text-shadow: 0 0 30px rgba(232, 95, 208, 0.2);
}
.amodal-studio { color: rgba(246, 224, 218, 0.7); font-size: 0.95rem; }
.amodal-actions { margin-top: auto; padding-top: 26px; display: flex; flex-direction: column; gap: 10px; }
.amodal-actions .btn { justify-content: center; }
.amodal-hint {
  font-family: var(--font-mono); font-size: 0.68rem; letter-spacing: 0.1em;
  text-transform: uppercase; color: rgba(246, 224, 218, 0.45); text-align: center;
}

.amodal-close {
  position: absolute; top: 12px; right: 12px; z-index: 2;
  width: 44px; height: 44px; display: grid; place-items: center;
  border: 0; border-radius: 50%; cursor: pointer;
  background: rgba(10, 20, 26, 0.75); color: var(--ink);
  font-size: 1.4rem; line-height: 1;
  transition: background 0.15s ease, box-shadow 0.15s ease;
}
.amodal-close:hover { background: var(--plum); box-shadow: var(--glow-sm) rgba(232, 95, 208, 0.8); }

body.amodal-open { overflow: hidden; }
body.is-scroll-locked { position: fixed; left: 0; right: 0; width: 100%; overflow: hidden; }
/* Pinning the body sets scrollY to 0, so a sticky header has nothing left to
   stick past and drops back to its natural spot — which is now scrolled off
   the top of the screen. Opening the menu after scrolling took the logo and
   the close button with it. While locked the body cannot scroll, so a fixed
   header sits exactly where the sticky one was. */
body.is-scroll-locked .site-header { position: fixed; top: 0; left: 0; right: 0; }

@media (max-width: 720px) {
  .amodal { padding: 0; }
  .amodal-card {
    /* minmax(0, 1fr), not 1fr: a grid item keeps an automatic min-width of its
       min-content, and the figure's aspect-ratio resolves against the row
       height — which pushed the column ~190px wider than the phone and made
       the photo look zoomed in. Pinning the rows makes width drive height. */
    grid-template-columns: minmax(0, 1fr);
    /* Photo takes the slack and the details sit under it. The other way round
       left ~500px of empty card below the studio name on a tall phone. */
    grid-template-rows: minmax(0, 1fr) auto;
    width: 100%;
    height: 100vh; height: 100dvh;          /* dvh so the URL bar can't clip it */
    max-height: 100vh; max-height: 100dvh;
    border-radius: 0; border: 0;
  }
  .amodal-figure { aspect-ratio: auto; min-height: 44vh; min-width: 0; width: 100%; }
  .amodal-body { min-width: 0; padding: 22px 22px 28px; }
  .amodal-actions { margin-top: 20px; padding-top: 0; }
}

/* Keyboard shortcut hint is noise on a touch screen */
@media (hover: none) {
  .amodal-hint { display: none; }
}

/* Respect data-saver and reduced-motion: hold the poster frame instead */
@media (prefers-reduced-motion: reduce) {
  .hero-video video { display: none; }
  .hero-video { background: url("../video/hero-atomium.jpg") center/cover no-repeat; }
}

/* Same treatment when the browser refuses to play inline — in-app webviews
   (Zalo, Messenger, Instagram) hand any play() to the native fullscreen
   player, which is worse than no video at all. main.js sets this class. */
.hero-video.is-poster-only video { display: none; }
.hero-video.is-poster-only { background: url("../video/hero-atomium.jpg") center/cover no-repeat; }

/* ============================================================
   Floating hover
   One lift for every card-like surface, so the whole site reacts the
   same way. Two things make it read as "floating" rather than "sliding":
   the card overshoots slightly on the way up and settles back down more
   slowly than it rose, and a cast shadow grows underneath it — without
   the shadow a translated card just looks nudged, not lifted.
   Accent glows stay per-family through --float-glow.
   ============================================================ */
:root {
  --ease-float: cubic-bezier(0.34, 1.32, 0.5, 1);   /* gentle overshoot */
  --float-lift: -6px;
  --float-cast: 0 18px 34px -14px rgba(20, 38, 46, 0.42);
  --float-glow: 0 0 0 rgba(0, 0, 0, 0);            /* families opt in below */
}
.section-dark, .next-edition { --float-cast: 0 22px 40px -14px rgba(0, 0, 0, 0.55); }

.pillar, .offer, .act, .value, .cat-day, .day-card, .artist-card, .trader,
.tickets-facts li {
  /* base state owns the settle-back: slower, no overshoot */
  transition: transform 0.42s var(--ease-out), box-shadow 0.42s ease,
              border-color 0.28s ease, background 0.28s ease;
}

.pillar:hover, .offer:hover, .act:hover, .value:hover, .cat-day:hover,
.day-card:hover, .trader:hover, .contest-day:hover,
.tickets-facts li:hover,
.artist-card:hover, .artist-card:focus-visible {
  transform: translateY(var(--float-lift));
  box-shadow: var(--float-glow), var(--float-cast);
  transition-duration: 0.32s;
  transition-timing-function: var(--ease-float);
}
.artist-card { --float-glow: var(--glow-md) rgba(232, 95, 208, 0.3); }
.act, .value, .day-card, .trader,
.tickets-facts li { --float-glow: var(--glow-md) rgba(232, 95, 208, 0.22); }
/* Contests are the money pages — they glow brass rather than plum. */
.contest-day { --float-glow: var(--glow-md) rgba(217, 164, 65, 0.22); }

@media (prefers-reduced-motion: reduce) {
  .pillar:hover, .offer:hover, .act:hover, .value:hover, .cat-day:hover,
  .day-card:hover, .trader:hover, .contest-day:hover,
  .tickets-facts li:hover,
  .artist-card:hover, .artist-card:focus-visible {
    transform: none;
  }
}

/* ============ legal / long-form pages ============
   The only place on the site with sustained body copy, so it gets a
   narrow measure and generous rhythm rather than the card grids the
   rest of the pages are built from. */
/* .legal is still a full .container so the copy starts on the same left gutter
   as every other page — the measure is constrained on the children instead. */
.legal > * { max-width: 68ch; }
.legal h2 {
  font-size: clamp(1.15rem, 2.4vw, 1.5rem);
  margin: 52px 0 14px; padding-top: 22px;
  border-top: 1.5px solid var(--line);
}
.legal h2:first-of-type { margin-top: 0; }
.legal p { margin-bottom: 14px; color: var(--ink-soft); }
.legal ul { list-style: none; margin: 0 0 18px; display: grid; gap: 10px; }
.legal li { position: relative; padding-left: 22px; color: var(--ink-soft); }
.legal li::before { content: "—"; position: absolute; left: 0; color: var(--plum); }
.legal a { color: var(--plum); text-underline-offset: 3px; }
.legal a:hover { text-decoration: none; }
.legal code {
  font-family: var(--font-mono); font-size: 0.86em;
  background: rgba(20, 38, 46, 0.07); border-radius: 5px; padding: 2px 6px;
}
.legal strong { color: var(--ink); }
.legal-updated { color: var(--gray); font-size: 0.78rem; letter-spacing: 0.1em; margin-top: 20px; }

/* plain-language summary up top — the part most people actually read */
.legal-summary {
  background: var(--surface); border: 1.5px solid var(--ink); border-radius: var(--radius);
  padding: 28px 30px; margin-bottom: 44px;
}
.legal-summary h2 { margin: 0 0 14px; padding: 0; border: 0; }
.legal-summary ul { margin: 0; }

/* build note for the site owner — deliberately loud so it can't ship by accident */

@media (max-width: 720px) {
  .legal h2 { margin-top: 40px; }
  .legal-summary { padding: 22px 20px; }
}

/* ============ contests ============ */
.contest-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
.contest-day {
  background: var(--surface); border: 1.5px solid var(--line);
  border-radius: var(--radius); padding: 28px 26px;
}
.contest-day h3 {
  font-size: 1.05rem; padding-bottom: 16px; margin-bottom: 4px;
  border-bottom: 1.5px solid var(--line);
}
.contest-list { list-style: none; }
.contest-list li { padding: 14px 0; border-bottom: 1px solid var(--line); }
.contest-list li:last-child { border-bottom: 0; }
.contest-name { display: block; font-weight: 600; font-size: 0.97rem; }
/* Prize money is the reason artists read this page — brass, and never
   competing with the category name for first read. */
.contest-note {
  display: block; margin-top: 4px; font-size: 0.76rem;
  letter-spacing: 0.06em; color: var(--brass);
}

/* ============ FAQ (details/summary) ============ */
.faq-list { display: grid; gap: 12px; max-width: 820px; }
.faq-item {
  background: var(--surface); border: 1.5px solid var(--line);
  border-radius: 12px; overflow: hidden;
}
.faq-item summary {
  list-style: none; cursor: pointer; padding: 20px 54px 20px 24px;
  font-weight: 600; font-size: 1rem; position: relative;
  transition: color 0.15s, background 0.15s;
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary:hover { color: var(--plum-lit); background: rgba(246, 224, 218, 0.03); }
.faq-item summary:focus-visible { outline: 2px solid var(--plum-lit); outline-offset: -3px; }
/* Chevron drawn in CSS so the row needs no icon font and no markup of its own. */
.faq-item summary::after {
  content: ""; position: absolute; right: 24px; top: 50%;
  width: 9px; height: 9px; margin-top: -6px;
  border-right: 2px solid var(--plum-lit); border-bottom: 2px solid var(--plum-lit);
  transform: rotate(45deg); transition: transform 0.22s var(--ease-out);
}
.faq-item[open] summary::after { transform: rotate(-135deg); margin-top: -2px; }
.faq-item[open] summary { color: var(--plum-lit); }
.faq-answer { padding: 0 24px 22px; }
.faq-answer p { color: var(--ink-soft); font-size: 0.95rem; line-height: 1.75; }

/* ============ timetable row kinds ============
   One accent per kind so a day reads as a shape. Arena and contest are the
   two people plan around, so they get the two strongest colours. */
.timetable li.tt-arena  .tt-time { color: var(--rose); }
.timetable li.tt-contest .tt-time { color: var(--brass); }
.timetable li.tt-stage  .tt-time { color: var(--plum-lit); }
.timetable li.tt-fun    .tt-time { color: var(--acid); }
.timetable li.tt-open   .tt-event { font-weight: 700; }
.tt-kind {
  font-size: 0.62rem; text-transform: uppercase; letter-spacing: 0.14em;
  color: var(--gray); justify-self: end;
}
@media (max-width: 720px) { .tt-kind { display: none; } }

/* ============ country select (artists page) ============ */
.artist-filters { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; margin-bottom: 14px; }
.artist-country {
  font-family: var(--font-mono); font-size: 0.8rem; letter-spacing: 0.04em;
  padding: 12px 38px 12px 16px; border-radius: 999px;
  border: 1.5px solid var(--line); background-color: rgba(255, 255, 255, 0.03);
  color: var(--ink); cursor: pointer; appearance: none;
  /* inline chevron, so the control needs no wrapper element */
  background-image: linear-gradient(45deg, transparent 50%, var(--plum-lit) 50%),
                    linear-gradient(135deg, var(--plum-lit) 50%, transparent 50%);
  background-position: right 19px center, right 13px center;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
}
.artist-country:hover { border-color: var(--ink-soft); }
.artist-country:focus { outline: none; border-color: var(--plum-lit); box-shadow: var(--glow-sm) rgba(199, 123, 184, 0.35); }
/* The dropdown list is painted by the OS, which ignores the page's palette —
   set both so the options are not black-on-black. */
.artist-country option { background: var(--surface); color: var(--ink); }

@media (max-width: 900px) { .contest-grid { grid-template-columns: 1fr; } }
@media (max-width: 720px) {
  .artist-filters { flex-direction: column; align-items: stretch; }
  .artist-country { width: 100%; font-size: 16px; }
}

/* ============ acts / offers grids ============ */
.acts { display: grid; grid-template-columns: repeat(2, 1fr); gap: 18px; }
.offers { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
.act-blurb { margin-top: 10px; }
/* The Instagram link is the only interactive thing in the card, so it needs to
   look like one — the card itself is not a link. */
.act-ig { margin-top: 14px; display: inline-block; }

/* A single-image artist has one lonely dot and nothing to step through.
   The disabled arrows are already hidden by the .shot-btn rule above; this
   drops the pointless dot too. */
.shot-dots:not(:has(.shot-dot + .shot-dot)) { display: none; }

@media (max-width: 900px) {
  .acts, .offers { grid-template-columns: 1fr; }
}
@media (max-width: 720px) {
  .signup-form { flex-direction: column; align-items: stretch; }
  .signup-form input[type="email"] { flex: 1 1 auto; font-size: 16px; }
  .signup-form .btn { width: 100%; justify-content: center; }
}

/* The €1 is the entire pitch, so it is set large — but opt-in by class, not
   by position. As `li:first-child` it also blew up "By train" on the info
   page, which reuses this same list for travel facts. */
.tickets-facts li.is-headline strong {
  font-size: clamp(1.7rem, 3.6vw, 2.3rem); line-height: 1;
  color: var(--acid); letter-spacing: -0.01em;
}
.tickets-facts li.is-headline { align-items: center; }

/* ============ hostess ============ */
.hostess-grid { display: grid; grid-template-columns: minmax(0, 360px) minmax(0, 1fr); gap: clamp(28px, 5vw, 56px); align-items: start; }
.hostess-photo { border-radius: var(--radius); overflow: hidden; border: 1.5px solid var(--line); }
.hostess-photo img { display: block; width: 100%; height: auto; }

/* ============ past edition ============ */
.recap { display: grid; grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); gap: clamp(30px, 5vw, 60px); align-items: center; }
.recap-copy .section-lede { margin-top: 16px; }

.recap-player { position: relative; }
/* The facade is a button, not a link: it swaps itself for the iframe in
   place, so nothing navigates and the poster keeps the layout from jumping. */
.recap-play {
  display: block; width: 100%; padding: 0; border: 1.5px solid var(--line);
  border-radius: var(--radius); overflow: hidden; background: var(--deep);
  cursor: pointer; position: relative; line-height: 0;
  transition: border-color 0.2s ease, box-shadow 0.25s ease, transform 0.25s var(--ease-out);
}
.recap-play img { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover;
  transition: opacity 0.25s ease, transform 0.4s var(--ease-out); }
.recap-play::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(10,8,12,0.10) 0%, rgba(10,8,12,0.62) 100%);
  transition: background 0.25s ease;
}
.recap-play:hover { border-color: var(--plum-lit); box-shadow: var(--glow-md) rgba(143, 78, 131, 0.35); transform: translateY(-3px); }
.recap-play:hover img { transform: scale(1.03); }
.recap-play:focus-visible { outline: 2px solid var(--plum-lit); outline-offset: 3px; }

.recap-play-btn {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: 74px; height: 74px; border-radius: 50%; z-index: 1;
  display: grid; place-items: center;
  background: var(--plum); color: #fff;
  box-shadow: var(--glow-md) rgba(143, 78, 131, 0.55);
  transition: background 0.2s ease, transform 0.25s var(--ease-out);
}
.recap-play-btn svg { width: 34px; height: 34px; margin-left: 3px; }
.recap-play:hover .recap-play-btn { background: var(--neon-plum); transform: translate(-50%, -50%) scale(1.08); }

.recap-play-label {
  position: absolute; left: 0; right: 0; bottom: 16px; z-index: 1;
  text-align: center; line-height: 1.4;
  font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.14em; color: var(--ink);
}

/* Same box as the poster it replaces, so pressing play does not shift the page. */
.recap-frame {
  display: block; width: 100%; aspect-ratio: 16 / 9; border: 0;
  border-radius: var(--radius); background: #000;
}
.recap-player.is-playing .recap-note { opacity: 0; pointer-events: none; }
.recap-note { margin-top: 12px; transition: opacity 0.2s ease; }

@media (max-width: 900px) {
  .recap { grid-template-columns: 1fr; }
  .recap-play-btn { width: 62px; height: 62px; }
  .recap-play-btn svg { width: 28px; height: 28px; }
}

@media (max-width: 820px) {
  .hostess-grid { grid-template-columns: 1fr; }
  .hostess-photo { max-width: 340px; }
}

/* ---- footer: parent company + sister shows ---- */
/* The show you are already on is named but not linked — a link back to the
   current site is a dead end. */

/* ============ venue map ============ */
.map { position: relative; margin-top: 30px; border-radius: var(--radius); overflow: hidden; border: 1.5px solid var(--line); }
/* The address panel sits *behind* the iframe: the box is never empty while
   Google is loading, and nothing shifts when the map paints over it. */
.map-facade {
  position: absolute; inset: 0;
  display: grid; place-items: center; gap: 14px; text-align: center;
  padding: 26px;
  background:
    radial-gradient(60% 70% at 50% 40%, rgba(143,78,131,0.16), transparent 70%),
    var(--surface);
}
/* A faint street-grid suggestion, drawn in CSS — no image request for a
   placeholder the real map covers a moment later. */
.map-facade::before {
  content: ""; position: absolute; inset: 0; opacity: 0.28; pointer-events: none;
  background-image:
    linear-gradient(rgba(246,224,218,0.10) 1px, transparent 1px),
    linear-gradient(90deg, rgba(246,224,218,0.10) 1px, transparent 1px);
  background-size: 46px 46px, 46px 46px;
}
.map-facade > * { position: relative; z-index: 1; }
.map-pin { font-size: 1.6rem; line-height: 1; }
.map-address { font-family: var(--font-mono); font-size: 0.86rem; line-height: 1.7; color: var(--ink-soft); }
.map-frame {
  position: relative; z-index: 1;
  display: block; width: 100%; aspect-ratio: 16 / 7; border: 0; background: transparent;
}
@media (max-width: 720px) { .map-facade, .map-frame { aspect-ratio: 4 / 3; } }

/* ============ contact ============
   Form on the left, the direct routes on the right — someone who would rather
   mail or walk in never has to read past the first screen to find how. */
.contact-grid { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 0.85fr); gap: clamp(32px, 5vw, 72px); align-items: start; }
.contact-form { display: grid; gap: 18px; }
.contact-row { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
.field { display: grid; gap: 8px; min-width: 0; }
.field > span { font-family: var(--font-mono); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.12em; color: var(--gray); }
.field input, .field select, .field textarea {
  font: inherit; font-size: 1rem; width: 100%;
  padding: 14px 18px; border-radius: 14px; color: var(--ink);
  border: 1.5px solid var(--line); background: rgba(255, 255, 255, 0.04);
  transition: border-color 0.15s, box-shadow 0.15s, background 0.15s;
}
.field textarea { resize: vertical; min-height: 150px; line-height: 1.6; }
/* The native arrow is drawn in the OS colour and disappears on this dark
   field, so the control draws its own. */
.field select {
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--gray) 50%), linear-gradient(135deg, var(--gray) 50%, transparent 50%);
  background-position: right 22px top 55%, right 16px top 55%;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
}
.field select option { background: var(--surface); color: var(--ink); }
.field input:hover, .field select:hover, .field textarea:hover { border-color: var(--ink-soft); }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--plum-lit);
  background: rgba(255, 255, 255, 0.06);
  box-shadow: var(--glow-sm) rgba(199, 123, 184, 0.4);
}
.contact-actions { display: flex; flex-wrap: wrap; gap: 16px; align-items: center; }
.contact-actions .form-note { margin: 0; min-height: 1.2em; }
/* Off-screen rather than display:none — a bot that skips hidden fields still
   fills this one, which is the whole point. */
.ct-trap { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.contact-form .fine-print { margin-top: 0; }
.contact-aside { border: 1.5px solid var(--line); border-radius: var(--radius); padding: 30px; background: var(--surface); }
.contact-aside-title { font-size: 1.15rem; margin-bottom: 16px; }
.contact-list { list-style: none; display: grid; gap: 16px; margin-bottom: 32px; }
.contact-list li { display: grid; gap: 3px; }
.contact-list .mono { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.12em; color: var(--gray); }
.contact-list a { color: var(--ink); text-decoration: none; word-break: break-word; }
.contact-list a:hover { color: var(--plum-lit); }
.contact-hours { font-size: 0.8rem; color: var(--gray); margin: 12px 0 22px; letter-spacing: 0.06em; }
.contact-aside .venue-address { margin-bottom: 0; }

/* ============ ticket conditions ============
   A numbered list where the number carries the weight, so the eight lines
   scan as terms rather than as body copy. */
.conditions { list-style: none; counter-reset: cond; display: grid; gap: 2px; max-width: 780px; }
.conditions li {
  counter-increment: cond;
  position: relative; padding: 15px 0 15px 52px;
  border-bottom: 1px solid var(--line-light);
  color: var(--ink-soft); font-size: 0.98rem; line-height: 1.55;
}
.conditions li:last-child { border-bottom: 0; }
.conditions li::before {
  content: counter(cond, decimal-leading-zero);
  position: absolute; left: 0; top: 15px;
  font-family: var(--font-mono); font-size: 0.8rem; letter-spacing: 0.08em;
  color: var(--plum-lit);
}
.conditions a { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
.conditions a:hover { color: var(--plum-lit); }

@media (max-width: 900px) {
  .contact-grid { grid-template-columns: 1fr; }
}
@media (max-width: 720px) {
  .contact-row { grid-template-columns: 1fr; }
  .field input, .field select, .field textarea { font-size: 16px; }
  .contact-actions .btn { width: 100%; justify-content: center; }
}

/* ============ feature blocks ============
   Partner events under the convention pillars. Wider and quieter than a
   pillar so they read as "also happening", not as a fifth pillar. */
.features { display: grid; grid-template-columns: repeat(2, 1fr); gap: 18px; margin-top: 18px; }
.features[hidden] { display: none; }
.feature {
  display: block; text-decoration: none; color: inherit;
  background: var(--surface-2); border: 1.5px solid var(--line);
  border-radius: var(--radius); padding: 30px 28px;
  position: relative; overflow: hidden;
  transition: transform 0.42s var(--ease-out), box-shadow 0.42s ease, border-color 0.28s ease;
}
/* Brass edge: these are the fight/championship strand, same colour the
   contests and prize money use elsewhere. */
.feature::before {
  content: ""; position: absolute; inset: 0 auto 0 0; width: 3px;
  background: var(--brass);
}
.feature-kind {
  font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.14em;
  color: var(--brass); margin-bottom: 10px;
}
.feature h3 { font-size: 1.25rem; margin-bottom: 10px; }
.feature-blurb, .feature-detail { color: var(--ink-soft); font-size: 0.95rem; line-height: 1.7; }
.feature-detail { margin-top: 10px; color: var(--gray); }
.feature-more {
  display: inline-block; margin-top: 16px;
  font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.14em;
  color: var(--brass);
}
a.feature:hover {
  border-color: var(--brass); transform: translateY(var(--float-lift));
  box-shadow: var(--glow-md) rgba(217, 164, 65, 0.22), var(--float-cast);
}
@media (max-width: 900px) { .features { grid-template-columns: 1fr; } }
@media (prefers-reduced-motion: reduce) { a.feature:hover { transform: none; } }

/* ============ arena partner strip (program page) ============
   The sanctioning bodies behind the fight nights, sat between the heading
   and the three day cards. All three marks ship on transparency, so they
   need no plates — they read as one row of logos, not three boxes. Heights
   are tuned per mark rather than shared: the WBC lockup is nearly square
   and would tower over two wordmarks at a common height. */
.partner-strip {
  list-style: none; display: flex; flex-wrap: wrap; align-items: center;
  gap: clamp(28px, 6vw, 64px); margin: 30px 0 6px; padding: 0;
}
.partner-strip img { display: block; width: auto; object-fit: contain; }
/* Sized per mark, not by position: these marks are wildly different shapes —
   a near-square lockup next to a 4:1 wordmark — so a shared height makes one
   of them shout. Keyed by class so reordering or adding one cannot silently
   re-assign somebody else's size. */
.partner-strip .pl-wbc   img { height: 66px; }
.partner-strip .pl-rank1 img { height: 40px; }
.partner-strip .pl-12r   img { height: 48px; }
.partner-strip .pl-vkbmo img { height: 50px; }
@media (max-width: 620px) {
  .partner-strip { gap: 22px 26px; }
  .partner-strip .pl-wbc   img { height: 46px; }
  .partner-strip .pl-rank1 img { height: 28px; }
  .partner-strip .pl-12r   img { height: 34px; }
  .partner-strip .pl-vkbmo img { height: 36px; }
}

/* A feature block with a logo shows the logo instead of a typeset title —
   the mark is the name. The <h3> stays in the DOM for screen readers. */
/* A fixed box rather than a fixed height: partners send marks in wildly
   different shapes, and matching on height alone leaves a near-square lockup
   looking like a thumbnail beside a wide wordmark. contain + a left origin
   fits each mark to the same optical area and reserves the space up front. */
/* The partner marks lead the card. Matched on height rather than boxed: they
   sit on one baseline as a row, the way a sponsor line reads, and a common
   height is what makes marks of different widths look like a set. */
.feature-logos {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: clamp(18px, 3vw, 30px); margin-bottom: 20px; min-height: 52px;
}
.feature-logo {
  display: block; width: auto; height: 52px; max-width: 100%;
  object-fit: contain; object-position: left center;
}
@media (max-width: 620px) {
  .feature-logos { gap: 16px; min-height: 42px; }
  .feature-logo { height: 42px; }
}

/* ============ album rails (venue + hostess) ============
   Ported from the Art of Ink Show build: one scroll-snap strip driven by
   arrows, keyboard and auto-advance. Same markup, same js/main.js wiring —
   only the palette and the frame shapes differ. */
.album, .album-wrap { min-width: 0; }

.album-head {
  display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap;
  margin-bottom: 14px; padding-bottom: 12px; border-bottom: 1px solid var(--line);
}
.album-head h3 { font-size: clamp(1.05rem, 2vw, 1.35rem); }
.album-head .mono { font-size: 0.72rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--brass); }

.album-wrap { position: relative; }
.album-rail {
  display: flex; gap: 14px; overflow-x: auto; scroll-snap-type: x mandatory;
  scroll-behavior: smooth; scrollbar-width: none;
  /* room for the snap to breathe at both ends */
  padding: 2px 2px 6px;
  /* the rail is focusable for keyboard users; keep the ring off the images */
  border-radius: var(--radius);
}
.album-rail::-webkit-scrollbar { display: none; }
.album-rail:focus-visible { outline: 2px solid var(--amber-lit); outline-offset: 3px; }

.album-item {
  flex: 0 0 auto; margin: 0; scroll-snap-align: start;
  width: clamp(210px, 26vw, 300px); aspect-ratio: 1 / 1;
  border-radius: 12px; overflow: hidden; border: 1.5px solid var(--line);
  background: linear-gradient(140deg, rgba(143, 78, 131, 0.20), rgba(201, 138, 46, 0.10));
  transition: border-color 0.2s ease, transform 0.3s var(--ease-out);
}
.album-item img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 0.45s var(--ease-out); }
.album-item:hover { border-color: var(--amber); transform: translateY(-4px); }
.album-item:hover img { transform: scale(1.04); }

.album-btn {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 2;
  width: 44px; height: 44px; display: grid; place-items: center;
  font-size: 1.5rem; line-height: 1; cursor: pointer;
  border-radius: 50%; border: 1.5px solid var(--line-light);
  background: rgba(10, 8, 12, 0.84); color: var(--ink);
  backdrop-filter: blur(6px);
  transition: background 0.18s ease, opacity 0.18s ease, box-shadow 0.2s ease;
}
.album-btn:hover { background: var(--amber); color: var(--void); box-shadow: var(--glow-md) rgba(201, 138, 46, 0.45); }
.album-btn[disabled] { opacity: 0; pointer-events: none; }
.album-prev { left: -14px; }
.album-next { right: -14px; }
/* Fewer works than fit the row — no controls at all. */
.album-wrap.is-static .album-btn { display: none; }

@media (hover: none) {
  /* Touch scrolls directly; arrows would just cover the artwork. */
  .album-btn { display: none; }
  .album-rail { scroll-snap-type: x proximity; }
}

/* ============ venue photos ============
   A carousel rather than a grid: these are wide interior shots, and four of
   them stacked two-up pushed the FAQ well below the fold. Built on the same
   album rail as the art exhibition — the only difference is the frame shape. */
.venue-photos { margin-top: 34px; min-width: 0; }
.venue-rail .album-item {
  /* landscape, not the square the artwork tiles use */
  width: clamp(280px, 52vw, 560px); aspect-ratio: 3 / 2;
}

/* Portrait frames for the hostess rail — the venue shots are wide interiors,
   these are shoot photographs and cropping them to 3:2 loses the subject. */
.hostess-shots { margin-top: 30px; min-width: 0; }
.hostess-rail .album-item { width: clamp(200px, 30vw, 300px); aspect-ratio: 3 / 4; }

/* ============ "new artists added every day" ============
   A standing note wherever the line-up is the subject. The dot pulses so it
   reads as a live status rather than another line of copy — and stops for
   anyone who has asked for reduced motion. */
.live-note {
  display: inline-flex; align-items: center; gap: 9px;
  margin: 14px 0 18px; padding: 7px 14px 7px 12px;
  border: 1px solid rgba(217, 164, 65, 0.4); border-radius: 999px;
  font-size: 0.72rem; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--brass);
}
.live-dot {
  width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0;
  background: var(--brass); box-shadow: 0 0 0 0 rgba(217, 164, 65, 0.55);
  animation: live-pulse 2.4s ease-out infinite;
}
@keyframes live-pulse {
  70%  { box-shadow: 0 0 0 7px rgba(217, 164, 65, 0); }
  100% { box-shadow: 0 0 0 0 rgba(217, 164, 65, 0); }
}
@media (prefers-reduced-motion: reduce) { .live-dot { animation: none; } }
