/* ============================================================
   Kings of the Rollers - UK Tour, autumn 2026
   Presale signup. Client: Louder Entertainment.

   DIRECTION - the illuminated quest map.
   The client sent a hand-drawn treasure map, flat, with no layers
   ("no image layers on this one"), so unlike the layered builds in
   this engine's lineage the poster is NOT rebuilt live - it is
   shown whole, as a map sheet laid on the table, artwork left and
   sign-up right. What IS rebuilt is the ground: the map furniture
   that already lives at the edges of the client's crops (compass
   rose, mountains, rocks, the dashed quest trail, the kings) is
   kept as an illuminated border and the middle returns to bare
   parchment, so the poster and the form sit on a clean field
   instead of on top of a second copy of themselves.

   This is a LIGHT build, against the fleet's dark default. The
   artwork is cream paper and sepia ink; a dark glass panel would
   fight it, so the panel is a sheet of vellum, not a smoked card.

   COLOUR - every value is a literal pixel out of the supplied
   artwork, not an interpretation:
     #FEFDD8  lit parchment      (the paper's highlight)
     #F6F4CA  parchment          (the dominant paper tone)
     #38382F  the linework ink
     #E24D39  the quest trail / royal red
     #9B863E  the illuminated gold of the wordmark
   Measured: the trail red is only 3.44:1 on the panel, so it is
   ORNAMENT ONLY and never carries text. Text and the CTA use a
   deepened draw of the same red (#B8321F, 5.24:1) so the page
   still reads as two colours without failing contrast.

   TYPE - Fraunces variable, run wonky and soft (WONK 1, SOFT 55-62)
   at display sizes. The poster's own face is hand-lettered, so a
   grotesque would read as two unrelated voices; an old-style with
   real stroke contrast and irregular terminals shares its pen
   without cosplaying blackletter. Body copy is the system stack
   and stays quiet - the boldness is spent in one place.

   SIGNATURE - the quest trail. The artwork already links its
   cities with a dashed red line, so that line does the structural
   work here: it is the step spine, the divider on the shows rack,
   and the marker on a selected date. Numbered waypoints are
   earned - this genuinely is a sequence (sign up, verify, confirm).
   ============================================================ */

@font-face {
  font-family: "Fraunces";
  src: url("/assets/fonts/Fraunces-var.woff2?v=20260908-10") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

:root {
  --paper:      #FEFDD8;   /* lit parchment - page ground */
  --parchment:  #F6F4CA;   /* the dominant paper tone */
  --panel:      #F5F2C6;   /* the charter sheet laid on the map */
  --field:      #FFFEF0;   /* input wells - OPAQUE, see the autofill note */
  --rule:       #CDC195;   /* hairlines, sheet edges */
  --rule-deep:  #B6A876;   /* stronger rules, focus rings */
  --ink:        #38382F;   /* the linework black - body copy, 10.37:1 */
  --ink-soft:   #5E5D50;   /* secondary copy, 5.83:1 */
  --ink-faint:  #78766A;   /* placeholders */
  --scarlet:    #E24D39;   /* the quest trail - ORNAMENT ONLY, 3.44:1 */
  --scarlet-dp: #B8321F;   /* the same red deepened for text + CTA, 5.24:1 */
  --gold:       #9B863E;   /* the illuminated wordmark gold */
  --danger:     #A32A18;
  --whatsapp:   #128C4B;

  --display: "Fraunces", Georgia, "Times New Roman", serif;
  --body:    "Helvetica Neue", Helvetica, Arial, sans-serif;

  --maxw: 1220px;
}

*, *::before, *::after { box-sizing: border-box; }

/* The `hidden` attribute is only display:none in the UA stylesheet, the
   weakest layer of the cascade, so ANY author rule that sets display beats it
   and the element stays on screen with no error anywhere. Keep this rule ABOVE
   everything that sets display, and never remove it. */
[hidden] { display: none !important; }

/* Ground colour lives on html, NOT body: an opaque body background paints over
   the z-index:-2 .bg layer and the artwork disappears. */
html {
  -webkit-text-size-adjust: 100%;
  background: var(--paper);
}

body {
  margin: 0;
  min-height: 100vh;
  min-height: 100svh;
  font-family: var(--body);
  color: var(--ink);
  background: transparent;
  display: flex;
  flex-direction: column;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* ---------- the map, rebuilt as an illuminated border ----------
   Four plates, chosen by aspect ratio rather than width alone: width-only
   breakpoints leave a gap at squarish window shapes where neither the phone
   nor the desktop plate applies. The <link rel=preload> conditions in the head
   mirror these four rules exactly, so nothing preloads unused. */
.bg {
  position: fixed;
  inset: 0;
  z-index: -2;
  background-color: var(--paper);
  background-image: url("/assets/images/bg-mobile-sm.webp?v=20260908-10");
  background-position: center;
  background-size: cover;
}
@media (max-aspect-ratio: 7/10) and (min-width: 501px) {
  .bg { background-image: url("/assets/images/bg-mobile.webp?v=20260908-10"); }
}
@media (min-aspect-ratio: 7/10) {
  .bg { background-image: url("/assets/images/bg-desktop-sm.webp?v=20260908-10"); }
}
@media (min-aspect-ratio: 7/10) and (min-width: 1501px) {
  .bg { background-image: url("/assets/images/bg-desktop.webp?v=20260908-10"); }
}

/* Scrim, inverted from the fleet's usual dark wash: this build is light, so
   the middle is LIFTED rather than sunk. One gradient, weighted to the centre
   where the sheet and the form sit. */
.bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(118% 80% at 50% 48%,
      rgba(255,254,240,.70) 0%, rgba(255,254,240,.34) 48%, rgba(255,254,240,0) 100%);
}

/* Paper tooth. Functional, not decoration: the plates are flat cream over
   large areas and WebP bands visibly across them without a little grain on
   top. Multiply rather than overlay - on a light ground overlay lifts the
   noise into visible speckle. */
.grain {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: .055;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ============================================================
   STAGE
   ============================================================ */
.stage {
  flex: 1 0 auto;
  width: 100%;
  max-width: var(--maxw);
  margin: 0 auto;                 /* auto at EVERY breakpoint - never plain 0 */
  padding: clamp(22px, 4vw, 54px) clamp(16px, 4vw, 40px);
  display: flex;
  align-items: center;
}
.stage__inner {
  width: 100%;
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(26px, 4vw, 56px);
  align-items: center;
}

/* ---------- the poster, shown whole ----------
   The client's crop is the artwork and it carries the full billing, so the
   <img> alt IS the page heading. A fine sepia rule and a low shadow are all
   it gets: the sheet's own paper matches the ground, so without an edge it
   would dissolve into the background instead of reading as a map laid on it. */
.bill {
  justify-self: center;
  width: 100%;
  max-width: 620px;
}
.bill__h1 { margin: 0; }
.bill__poster {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--rule);
  border-radius: 2px;
  box-shadow: 0 22px 44px -26px rgba(56,56,47,.55), 0 2px 0 rgba(255,255,255,.5);
  animation: riseIn .85s cubic-bezier(.16,.84,.36,1) both;
}
@keyframes riseIn {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

/* ============================================================
   SIGNUP PANEL
   ============================================================ */
.signup { justify-self: center; width: 100%; max-width: 500px; }
.panel {
  width: 100%;
  position: relative;
  isolation: isolate;             /* keeps the country dropdown above the top rule */
  background: var(--panel);
  border: 1px solid var(--rule);
  border-radius: 3px;
  box-shadow: 0 30px 60px -34px rgba(56,56,47,.55);
  animation: riseIn .85s .12s cubic-bezier(.16,.84,.36,1) both;
  overflow: visible;
}
/* the quest trail drawn along the top edge of the sheet - the one place the
   artwork's red touches the panel outline */
.panel::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 4px;
  border-radius: 3px 3px 0 0;
  background-image: linear-gradient(90deg, var(--scarlet) 0 26px, transparent 26px 42px);
  background-size: 42px 100%;
  opacity: .9;
  z-index: 0;
}
.panel__inner { position: relative; z-index: 1; padding: clamp(24px, 3.2vw, 36px); }

/* --- state machine (app.js flips data-form-state on .panel) --- */
.panel__state { display: none; }
.panel[data-form-state="idle"]    .panel__idle    { display: block; }
.panel[data-form-state="otp"]     .panel__otp     { display: block; }
.panel[data-form-state="success"] .panel__success { display: block; }

/* ============================================================
   STEP SPINE - the signature element
   Three waypoints strung on the artwork's own dashed trail, driven by the same
   data-form-state the form logic already sets. Sits OUTSIDE the state wrappers
   because it is panel chrome, not state content. Numbered because it genuinely
   is a sequence: sign up, verify the number, confirm the email.
   ============================================================ */
.spine {
  position: relative;
  display: flex;
  list-style: none;
  margin: 0 0 24px;
  padding: 0;
}
/* the trail itself, drawn behind the waypoints */
.spine::before {
  content: "";
  position: absolute;
  /* three equal flex cells, so the waypoint centres sit at 1/6, 3/6 and 5/6.
     Terminating the trail exactly on the outer centres lets the opaque
     circles cap it; a wider run leaves dashes dangling past the ends. */
  left: 16.667%; right: 16.667%;
  top: 11px;
  height: 3px;
  background-image: linear-gradient(90deg, var(--scarlet) 0 11px, transparent 11px 20px);
  background-size: 20px 100%;
  opacity: .55;
}
.spine__step {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
  font-family: var(--body);
  font-weight: 600;
  font-size: 10.5px;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--ink-soft);
  transition: color .25s ease;
}
.spine__n {
  flex: 0 0 auto;
  width: 25px; height: 25px;
  display: grid;
  place-items: center;
  background: var(--panel);
  border: 1.5px solid var(--rule-deep);
  border-radius: 50%;
  font-family: var(--display);
  font-variation-settings: "opsz" 14, "wght" 600, "SOFT" 40, "WONK" 1;
  font-size: 13px;
  line-height: 1;
  letter-spacing: 0;
}
.spine__t { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }

/* current step */
.panel[data-form-state="idle"]    .spine__step:nth-child(1),
.panel[data-form-state="otp"]     .spine__step:nth-child(2),
.panel[data-form-state="success"] .spine__step:nth-child(3) { color: var(--scarlet-dp); }
.panel[data-form-state="idle"]    .spine__step:nth-child(1) .spine__n,
.panel[data-form-state="otp"]     .spine__step:nth-child(2) .spine__n,
.panel[data-form-state="success"] .spine__step:nth-child(3) .spine__n {
  background: var(--scarlet-dp);
  border-color: var(--scarlet-dp);
  color: var(--field);
}
/* completed steps: the numeral is replaced by a tick */
.panel[data-form-state="otp"]     .spine__step:nth-child(1),
.panel[data-form-state="success"] .spine__step:nth-child(1),
.panel[data-form-state="success"] .spine__step:nth-child(2) { color: var(--ink-soft); }
.panel[data-form-state="otp"]     .spine__step:nth-child(1) .spine__n,
.panel[data-form-state="success"] .spine__step:nth-child(1) .spine__n,
.panel[data-form-state="success"] .spine__step:nth-child(2) .spine__n {
  font-size: 0;                    /* hide the digit, keep the ring */
  border-color: var(--scarlet-dp);
  background: var(--field);
}
.panel[data-form-state="otp"]     .spine__step:nth-child(1) .spine__n::after,
.panel[data-form-state="success"] .spine__step:nth-child(1) .spine__n::after,
.panel[data-form-state="success"] .spine__step:nth-child(2) .spine__n::after {
  content: "";
  width: 9px; height: 5px;
  border: 2px solid var(--scarlet-dp);
  border-top: 0;
  border-right: 0;
  transform: rotate(-45deg) translate(1px, -1px);
}
@media (max-width: 400px) {
  .spine__step { font-size: 9px; letter-spacing: .03em; gap: 5px; }
  .spine__n { width: 22px; height: 22px; font-size: 12px; }
  .spine::before { top: 9px; }
}

/* ============================================================
   PANEL COPY
   ============================================================ */
.panel__title {
  margin: 0 0 12px;
  font-family: var(--display);
  font-variation-settings: "opsz" 72, "wght" 650, "SOFT" 58, "WONK" 1;
  font-weight: 650;
  font-size: clamp(1.62rem, 4.4vw, 2.06rem);
  line-height: 1.06;
  letter-spacing: -.005em;
  color: var(--ink);
  text-wrap: balance;
}
/* House pattern across the fleet: the second line of the title carries the
   accent. <em> is used for the hook rather than a span so the emphasis is in
   the markup, not only the paint - reset from italic because the deepened red
   is doing the work. */
.panel__title em { font-style: normal; color: var(--scarlet-dp); }
.panel__lede {
  margin: 0 0 10px;
  font-size: 15px;
  color: var(--ink-soft);
  max-width: 46ch;
}
.panel__lede--last { margin-bottom: 22px; }
.panel__lede strong { color: var(--ink); font-weight: 600; }
.panel__success-note { margin: 0 0 12px; color: var(--scarlet-dp); font-size: 14.5px; }

/* ============================================================
   FORM
   ============================================================ */
.form__row { margin: 0 0 13px; }
/* labels stay for screen readers; placeholders carry the meaning visually */
.form__label {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.form__input {
  width: 100%;
  padding: 13px 14px;
  font-family: var(--body);
  font-size: 16px;                /* 16px minimum or iOS zooms the page on focus */
  color: var(--ink);
  background: var(--field);       /* OPAQUE - see the autofill rule below */
  border: 1px solid var(--rule);
  border-radius: 2px;
  transition: border-color .18s ease, box-shadow .18s ease;
}
.form__input::placeholder { color: var(--ink-faint); }
.form__input:focus {
  outline: none;
  border-color: var(--scarlet-dp);
  box-shadow: 0 0 0 3px rgba(184,50,31,.15);
}
.form__input--otp {
  font-family: var(--display);
  font-variation-settings: "opsz" 32, "wght" 600, "SOFT" 30, "WONK" 0;
  font-size: 22px;
  letter-spacing: .42em;
  text-align: center;
  text-indent: .42em;             /* re-centres text that tracking pushes left */
}

/* Chrome paints autofilled inputs pale lavender and IGNORES background /
   background-color on :-webkit-autofill - a huge inset box-shadow is the only
   reliable override. A box-shadow cannot be semi-transparent, so the colour
   must be the FLATTENED OPAQUE equivalent of the field's rendered stack. That
   is trivially --field here because the field was made opaque on purpose; keep
   it opaque, or this value has to be recomputed by compositing field over
   panel over the background plate. */
.form__input:-webkit-autofill,
.form__input:-webkit-autofill:hover,
.form__input:-webkit-autofill:focus,
.form__input:-webkit-autofill:active {
  -webkit-box-shadow: 0 0 0 1000px var(--field) inset !important;
          box-shadow: 0 0 0 1000px var(--field) inset !important;
  -webkit-text-fill-color: var(--ink) !important;
  caret-color: var(--ink);
  transition: background-color 9999s ease-in-out 0s;   /* stops the lavender flashing in */
}

.form__error { margin: 7px 0 0; font-size: 13px; color: var(--danger); }
.form__error--global { margin-top: 14px; }

/* Honeypot. display:none ONLY - off-screen positioning stays an autofill
   target in Chrome/Edge, which fills it and silently blocks real signups. */
.hp-row { display: none !important; }

/* ============================================================
   SHOWS RACK
   Seven dates, multi-select. The submitted values are the CRM option strings
   BYTE FOR BYTE (five carry an en dash, two a plain hyphen) - the CRM routes a
   signup to an audience group by exact string lookup, so a tidied dash is
   accepted and then routed nowhere, silently. See the note in app.js.
   ============================================================ */
.shows { margin: 0 0 18px; padding: 0; border: 0; min-width: 0; }
.shows__legend {
  display: block;
  width: 100%;
  padding: 0;
  margin: 0 0 10px;
  font-family: var(--display);
  font-variation-settings: "opsz" 20, "wght" 600, "SOFT" 45, "WONK" 1;
  font-size: 16px;
  color: var(--ink);
}
.shows__hint {
  display: block;
  margin-top: 2px;
  font-family: var(--body);
  font-size: 12.5px;
  font-weight: 400;
  color: var(--ink-soft);
}

/* --- the collapsed control ---------------------------------------------
   Shaped like the email and mobile fields on purpose: it has to read as a
   standard dropdown at a glance, because that is what it is standing in for.
   The menu is absolutely positioned so opening it overlays the consent line
   and the button instead of pushing them down the page. */
.picker { position: relative; }
.picker__trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  padding: 13px 14px;
  font-family: var(--body);
  font-size: 16px;                /* 16px minimum or iOS zooms the page on focus */
  text-align: left;
  color: var(--ink);
  background: var(--field);
  border: 1px solid var(--rule);
  border-radius: 2px;
  cursor: pointer;
  transition: border-color .18s ease, box-shadow .18s ease;
}
.picker__trigger:hover { border-color: var(--rule-deep); }
.picker[data-open="true"] .picker__trigger,
.picker__trigger:focus-visible {
  outline: none;
  border-color: var(--scarlet-dp);
  box-shadow: 0 0 0 3px rgba(184,50,31,.15);
}
/* nothing chosen yet: the trigger is a prompt, so it takes placeholder colour */
.picker__value { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.picker__value[data-empty="true"] { color: var(--ink-faint); }
.picker__caret {
  flex: 0 0 auto;
  width: 8px; height: 8px;
  border: 2px solid var(--ink-soft);
  border-top: 0;
  border-left: 0;
  transform: translateY(-2px) rotate(45deg);
  transition: transform .18s ease;
}
.picker[data-open="true"] .picker__caret { transform: translateY(1px) rotate(-135deg); }

.picker__menu {
  position: absolute;
  z-index: 20;                    /* below the iti country list at 50 */
  top: calc(100% + 6px);
  left: 0; right: 0;
  max-height: 296px;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  border: 1px solid var(--rule-deep);
  border-radius: 2px;
  background: var(--field);
  box-shadow: 0 22px 44px -18px rgba(56,56,47,.5);
}

.shows__rack { background: var(--field); }
.show { position: relative; display: block; cursor: pointer; }
.show + .show { border-top: 1px solid var(--rule); }
.show input {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.show__plate {
  position: relative;
  display: grid;
  grid-template-columns: 20px 66px minmax(0, 1fr);
  align-items: center;
  gap: 11px;
  padding: 10px 13px 10px 12px;
  transition: background-color .16s ease;
}
.show__tick {
  display: grid;
  place-items: center;
  width: 18px; height: 18px;
  border: 1.5px solid var(--rule-deep);
  border-radius: 2px;
  background: var(--field);
  transition: background-color .16s ease, border-color .16s ease;
}
.show__date {
  font-size: 12.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: .01em;
  color: var(--ink-soft);
  white-space: nowrap;
}
.show__where { min-width: 0; }
.show__city {
  display: block;
  font-size: 14.5px;
  font-weight: 600;
  color: var(--ink);
  line-height: 1.25;
}
.show__venue {
  display: block;
  font-size: 12.5px;
  color: var(--ink-soft);
  line-height: 1.3;
}
.show:hover .show__plate { background: rgba(226,77,57,.05); }
/* a waypoint reached: the trail's red marks the sheet's edge */
.show input:checked + .show__plate { background: rgba(226,77,57,.09); }
.show input:checked + .show__plate::before {
  content: "";
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 3px;
  background: var(--scarlet);
}
.show input:checked + .show__plate .show__tick {
  background: var(--scarlet-dp);
  border-color: var(--scarlet-dp);
}
.show input:checked + .show__plate .show__tick::after {
  content: "";
  width: 8px; height: 4px;
  border: 2px solid var(--field);
  border-top: 0;
  border-right: 0;
  transform: rotate(-45deg) translate(1px, -1px);
}
.show input:focus-visible + .show__plate {
  outline: 2px solid var(--scarlet-dp);
  outline-offset: -2px;
}
@media (max-width: 360px) {
  .show__plate { grid-template-columns: 18px 60px minmax(0, 1fr); gap: 9px; padding-left: 10px; }
  .show__date { font-size: 11.5px; }
  .show__city { font-size: 13.5px; }
}

.form__row--check { margin: 17px 0 19px; }
.form__check {
  display: flex;
  align-items: flex-start;
  gap: 11px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink-soft);
  cursor: pointer;
}
.form__check input {
  flex: 0 0 auto;
  width: 17px; height: 17px;
  margin: 1px 0 0;
  accent-color: var(--scarlet-dp);
  cursor: pointer;
}
.form__check a { color: var(--ink); text-decoration: underline; text-underline-offset: 2px; }
.form__check a:hover { color: var(--scarlet-dp); }

/* ---------- the on-sale note ----------
   Birmingham and Nottingham are already selling, so they are deliberately not
   in the rack above. Sits under the button because that is where someone
   looking for a missing city ends up. */
.onsale {
  margin: 18px 0 0;
  padding: 13px 15px 13px 16px;
  border: 1px dashed var(--rule-deep);
  border-left: 3px solid var(--scarlet);
  border-radius: 2px;
  background: rgba(226,77,57,.05);
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--ink-soft);
}
.onsale strong { color: var(--ink); font-weight: 600; }

.form__resend {
  margin: 14px 0 0;
  font-size: 13px;
  color: var(--ink-soft);
  text-align: center;
}
.form__resend-btn {
  font: inherit;
  color: var(--scarlet-dp);
  background: none;
  border: 0;
  padding: 0;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
.form__resend-btn:disabled { color: var(--ink-soft); cursor: default; text-decoration: none; }

/* ---------- buttons ---------- */
.btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  padding: 15px 18px;
  font-family: var(--display);
  font-variation-settings: "opsz" 24, "wght" 700, "SOFT" 45, "WONK" 0;
  font-weight: 700;
  font-size: clamp(.92rem, 3.1vw, 1.06rem);
  letter-spacing: clamp(.005em, .2vw, .02em);
  white-space: nowrap;            /* shrink the type before it can ever wrap */
  text-align: center;
  text-decoration: none;          /* <a class="btn"> needs this, <button> doesn't */
  border: 0;
  border-radius: 2px;
  cursor: pointer;
  transition: transform .12s ease, filter .18s ease;
}
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: .62; cursor: default; }
/* Paper on the deepened trail red: 5.89:1. The raw artwork red would be
   3.86:1 and fails, which is exactly why --scarlet never carries type. */
.btn--primary {
  color: var(--field);
  background: var(--scarlet-dp);
  box-shadow: 0 12px 26px -14px rgba(184,50,31,.75);
}
.btn--primary:hover:not(:disabled) { filter: brightness(1.08); }
.btn--whatsapp {
  color: #FFFFFF;
  background: var(--whatsapp);
  margin-top: 4px;
}
.btn--whatsapp:hover { filter: brightness(1.08); }
.btn__icon { flex: 0 0 auto; width: 19px; height: 19px; }

.wa-hook { margin: 18px 0 12px; font-size: 13.5px; color: var(--ink-soft); }
.wa-hook strong { color: var(--ink); font-weight: 600; }

/* ============================================================
   DATES RACK - gensale.html only, scoped to body.gensale
   The nine shows live INSIDE the right-hand panel, so the general-sale page
   keeps the same shape as the sign-up it replaces: poster left, the one thing
   you came to do on the right.

   The brief was also "not too long", and nine rows is where a page gets away
   from you. Three things keep it to about one screen:
     1. one LINE per row, not two - date, city and venue share a baseline
     2. the panel widens to 560px (there is no form here to constrain it) and
        the poster gives up the width, so that line has room
     3. the poster is height-capped, since a 4:5 sheet at full column width is
        775px tall on its own
   The row is a flex-wrap, so if a long venue ever does run out of room it drops
   to a second line by itself rather than truncating or overflowing.
   ============================================================ */
body.gensale .signup { max-width: 560px; }
body.gensale .bill   { max-width: 520px; }
body.gensale .bill__poster {
  max-height: calc(100svh - 210px);
  width: auto;
  /* max-width is LOAD-BEARING, not a tidy-up. Switching width to auto hands
     sizing to max-height, and the image then scales from its 2399x3000
     intrinsic ratio with nothing capping the horizontal: at a 1080px-tall
     viewport that is 870px of height and 696px of width inside a 520px column,
     so ~176px of poster ran under the panel. The overlap only appears on TALL
     viewports, which is why a 1440x900 check missed it. */
  max-width: 100%;
  margin: 0 auto;
}
body.gensale .panel__title { margin-bottom: 8px; }
/* The base .panel__lede cap (46ch, ~384px at 15px) is narrower than the
   ~410px ticket-page lede, which pushed "Pick your city." onto its own line
   inside a 560px panel. Uncapped here; text-wrap: pretty stops a lone
   "city." orphan on phones, where the sentence has to wrap anyway. */
body.gensale .panel__lede--last { margin-bottom: 16px; max-width: none; text-wrap: pretty; }

.dates { margin: 0; }
.datelist {
  list-style: none;
  margin: 0;
  padding: 0;
  border: 1px solid var(--rule);
  border-radius: 2px;
  background: var(--field);
  overflow: hidden;
}
.daterow { display: block; padding: 10px 12px 11px; }
.daterow + .daterow { border-top: 1px solid var(--rule); }
.daterow__where {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px 9px;
  min-width: 0;
}
.daterow__date {
  flex: 0 0 auto;
  font-size: 12px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: .03em;
  color: var(--scarlet-dp);
}
.daterow__city  { font-size: 15px; font-weight: 600; color: var(--ink); line-height: 1.2; }
.daterow__venue { font-size: 12.5px; color: var(--ink-soft); line-height: 1.2; }
.daterow__note  { font-size: 11.5px; font-style: italic; color: var(--ink-soft); line-height: 1.2; }
.daterow__cta   { display: block; margin-top: 9px; }

/* "Click here for tickets" is 22 characters. Shrink the type before it can ever
   wrap - gotcha 26, which has recurred on phillyblunt and forward-motion.
   text-decoration and text-align are set because this is an <a>, not a
   <button>, and inherits neither. */
.tbtn {
  display: block;
  width: 100%;
  padding: 9px 12px;
  font-family: var(--display);
  font-variation-settings: "opsz" 18, "wght" 700, "SOFT" 45, "WONK" 0;
  font-size: clamp(.74rem, 2.6vw, .84rem);
  letter-spacing: .01em;
  white-space: nowrap;
  text-align: center;
  text-decoration: none;
  color: var(--field);
  background: var(--scarlet-dp);
  border: 1px solid var(--scarlet-dp);
  border-radius: 2px;
  cursor: pointer;
  transition: filter .18s ease, transform .12s ease;
}
.tbtn:hover  { filter: brightness(1.08); }
.tbtn:active { transform: translateY(1px); }

/* No ticket URL dropped in yet. The button ships with the FINAL copy so that a
   JS failure on a linked page still reads correctly; the script downgrades it
   to this muted, unclickable state only while data-href is a REPLACE_
   placeholder. Fails in the safe direction either way. */
.tbtn[aria-disabled="true"] {
  color: var(--ink-soft);
  background: transparent;
  border-color: var(--rule);
  cursor: default;
  pointer-events: none;
  font-variation-settings: "opsz" 18, "wght" 500, "SOFT" 45, "WONK" 0;
}

/* Two-column layout is live and the panel has settled at 560px (about 488px of
   content), so the button moves alongside the text. That is ~35px saved on
   every one of the nine rows, which is the difference between one screen and
   two. */
@media (min-width: 900px) and (min-aspect-ratio: 7/10) {
  body.gensale .stage__inner { grid-template-columns: minmax(0, 1fr) minmax(0, 560px); }
  .daterow {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 12px;
    padding: 7px 11px 8px;
  }
  .daterow__cta { margin-top: 0; }
  .tbtn { width: auto; padding: 7px 13px; font-size: .76rem; }
}

/* Landscape phones: the poster cap has to come off the SHORT side here, and the
   rack needs its tightest rows or the page runs away below the fold. */
@media (min-width: 640px) and (min-aspect-ratio: 7/10) and (max-height: 520px) {
  body.gensale .bill__poster { max-height: calc(100svh - 40px); }
  .daterow { padding: 5px 10px 6px; }
  .daterow__city { font-size: 13.5px; }
  .tbtn { padding: 6px 11px; font-size: .72rem; }
}

/* ============================================================
   intl-tel-input v25
   ============================================================ */
.iti { width: 100%; display: block; }
/* app.js re-measures and sets padding-left inline; this is the sane default
   before it runs. Anything >= 80px breaks 320-390px viewports. */
.iti input.form__input { padding-left: calc(52px + 0.7rem); }
.iti__country-container { z-index: 3; }
.iti--inline-dropdown .iti__dropdown-content { z-index: 50; }
/* Until the vendor stylesheet loads, the hidden state does not exist and the
   whole list plus search box flashes open on first paint. */
.iti__dropdown-content.iti__hide { display: none !important; }

.iti__dropdown-content {
  background: var(--field);
  border: 1px solid var(--rule-deep);
  border-radius: 3px;
  box-shadow: 0 26px 52px -20px rgba(56,56,47,.5);
  overflow: hidden;
}
.iti__search-input {
  /* Keep the vendor's horizontal padding reservation: 30px left clears the
     absolutely positioned search icon, 28px right clears the clear button. A
     padding SHORTHAND that drops them puts the magnifier on top of the
     placeholder text. Set the vertical values, keep the horizontal ones. */
  padding: 10px 30px 10px 32px;
  width: 100%;
  font-family: var(--body);
  font-size: 14px;
  color: var(--ink);
  background: var(--field);
  border: 0;
  border-bottom: 1px solid var(--rule);
}
.iti__search-input::placeholder { color: var(--ink-faint); }
.iti__search-input:focus { outline: none; background: #FFFFFA; }
.iti__country-list { background: var(--field); max-height: 240px; }
.iti__country {
  padding: 9px 12px;
  font-family: var(--body);
  font-size: 14px;
  color: var(--ink);
}
.iti__country:hover,
.iti__country.iti__highlight { background: rgba(226,77,57,.10); }
.iti__dial-code { color: var(--ink-soft); }
.iti__country-name { color: var(--ink); }
.iti__selected-country { border-radius: 2px 0 0 2px; }
.iti__selected-country:hover,
.iti__selected-country-primary:hover { background: rgba(226,77,57,.08); }
.iti__selected-dial-code { color: var(--ink); font-family: var(--body); font-size: 15px; }
.iti__arrow { border-top-color: var(--ink-soft); }
.iti__arrow--up { border-bottom-color: var(--ink-soft); }

/* ============================================================
   FOOTER - standard fleet band (basslayerz pattern)
   ============================================================ */
.foot {
  flex-shrink: 0;
  width: 100%;
  margin: 0;
  padding: 18px clamp(16px, 4vw, 40px) 26px;
  background: rgba(246,244,202,.72);
  border-top: 1px solid var(--rule);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
}
.foot__left { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.foot__legal { margin: 0; font-size: 12px; color: var(--ink-soft); letter-spacing: .02em; }
.foot__legal a { color: var(--ink-soft); text-decoration: none; }
.foot__legal a:hover { color: var(--scarlet-dp); }
.site-built { margin: 0; }
/* The credit sits in a pill, matching basslayerz - that is the house footer
   this build was asked to follow, and the chip is part of it, not just the
   markup. Same geometry (5px 11px, 999px radius, 1px hairline); only the
   tokens change. */
.site-built a {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 11px;
  letter-spacing: .04em;
  color: var(--ink-soft);
  text-decoration: none;
  padding: 5px 11px;
  border: 1px solid var(--rule);
  border-radius: 999px;
  transition: border-color .16s ease, color .16s ease;
}
.site-built a:hover { border-color: var(--scarlet-dp); color: var(--ink); }
/* The credit mark is drawn for dark bands: a white FURIOSA wordmark with a
   teal roundel and teal "CRM". On this paper it has to be darkened, but NOT
   inverted - invert() rotates the teal to red and the mark renders a muddy
   maroon (#2A0D0B measured), which loses the brand entirely. Darken and push
   saturation instead: the roundel stays teal, the wordmark lands at #2E5053,
   7.83:1 on the band and about the same weight as the footer text. */
.site-built img { display: block; opacity: .9; filter: brightness(.36) saturate(1.45); }

/* ============================================================
   RESPONSIVE
   Aspect-ratio thresholds, not width alone.
   ============================================================ */

/* --- two column: poster left, panel right --- */
@media (min-width: 900px) and (min-aspect-ratio: 7/10) {
  .stage__inner {
    grid-template-columns: minmax(0, 1fr) minmax(0, 500px);
    gap: clamp(36px, 4.5vw, 66px);
    align-items: center;
  }
  .bill   { justify-self: end; max-width: 620px; }
  .signup { justify-self: start; }
  .foot   { justify-content: space-between; }
}

@media (max-width: 899px) {
  .foot { justify-content: center; text-align: center; }
  .foot__left { justify-content: center; }
}

/* Phones: stack the footer rather than relying on the flex row wrapping.
   Around 390px the copyright + "built by" row is JUST wide enough to fill the
   band, so centring it is indistinguishable from it running edge to edge - it
   reads as left-aligned even though justify-content is centre. Below 480px,
   force a centred column so every width stacks the same way instead of
   flipping at whatever width the text happens to overflow. */
@media (max-width: 480px) {
  .foot {
    flex-direction: column;
    align-items: center;
    gap: 10px;
    padding-bottom: 22px;
  }
  .foot__left {
    flex-direction: column;
    align-items: center;
    gap: 10px;
  }
  /* Portrait phones: hold the poster back so the form clears the fold. It is
     a 4:5 sheet, so every 10vw of width costs 12.5vw of height. */
  .bill { max-width: min(340px, 74vw); }
  .stage { padding-top: clamp(16px, 3vw, 54px); }
  .stage__inner { gap: 22px; }
}

/* --- landscape phones are a first-class layout ---
   A rotated phone (844x390, 932x430, 667x375) satisfies both conditions above
   while having almost no height, so the poster and panel would render cramped
   and the page would scroll badly. Compact side-by-side, poster height-capped,
   tighter type. Placed AFTER the desktop block so it wins at equal specificity. */
@media (min-width: 640px) and (min-aspect-ratio: 7/10) and (max-height: 520px) {
  .stage { padding: 14px clamp(12px, 3vw, 26px); align-items: flex-start; }
  .stage__inner {
    grid-template-columns: minmax(0, .78fr) minmax(0, 1fr);
    gap: 20px;
    align-items: start;
  }
  .bill { justify-self: center; max-width: none; min-height: 0; }
  .bill__poster { max-height: calc(100svh - 40px); width: auto; margin: 0 auto; }
  .signup { justify-self: stretch; max-width: none; min-height: 0; }
  .panel__inner { padding: 16px 18px; }
  .spine { margin-bottom: 14px; }
  .panel__title { font-size: 1.32rem; margin-bottom: 8px; }
  .panel__lede { font-size: 13px; margin-bottom: 7px; }
  .panel__lede--last { margin-bottom: 12px; }
  .form__row { margin-bottom: 10px; }
  .form__input { padding: 10px 13px; }
  .shows { margin-bottom: 13px; }
  .shows__legend { font-size: 14.5px; margin-bottom: 7px; }
  .show__plate { padding: 7px 12px 7px 11px; }
  .picker__trigger { padding: 10px 13px; }
  .picker__menu { max-height: calc(100svh - 150px); }
  .show__city { font-size: 13.5px; }
  .form__row--check { margin: 12px 0 13px; }
  .btn { padding: 12px 16px; }
  .onsale { margin-top: 13px; padding: 10px 13px; }
  .iti__country-list { max-height: 150px; }
}

/* --- small phones --- */
@media (max-width: 400px) {
  .panel__inner { padding: 22px 18px; }
}

/* ============================================================
   ACCESSIBILITY
   ============================================================ */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
:focus-visible {
  outline: 2px solid var(--scarlet-dp);
  outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}
