/* ============================================================
   ANDROMEDIK INVITES - andromedik.live
   London, Outernet, Sat 13 Feb 2027 (sign-up) + Antwerp Expo, Fri 30 Oct
   2026 (on sale, Paylogic). Client: Louder Entertainment.

   Art left, sign-up right (Adam's standard format). The brief's hard rule:
   "the artist and the background are never covered by any assets". So the
   plate lives in its OWN track (.stage), nothing in the UI overlaps it, and
   it is bottom-anchored so the cover-crop only ever takes stripes off the
   sides or the top, never the DJ or the booth. The lockup is its own image,
   placed in the stripes above his head.

   The two events are a ROUTE: two stops on a vertical light stripe lifted
   from the LED wall, with the lockup's orbit glyph as the stop markers. A lit
   marker = on sale now (Antwerp, on top as a compact stop; Adam preferred
   the on-sale button above). London is the expanded stop with the sign-up.

   Palette (Adam, 2026-10-08: the first build's brown-red ember column
   "doesn't seem to fit"). The art has exactly two clean grounds, the stage
   floor's pure black and the wall's orange-red, so the column takes one of
   them, sampled from literal pixels of the plates:
     DEFAULT "floor"  --ground #000000, the stage floor. On phones the plate's
                      black floor runs straight into the sign-up with no seam.
                      CTAs are lit stripes (orange -> hot core -> orange) with
                      near-black ink, and on desktop the wall's light spills
                      onto the column's left edge (--edge).
     html[data-theme="wall"]  --ground #C2340F, the wall's orange-red, white
                      type, black CTAs. Dev comparison via ?theme=wall.
   Fields are OPAQUE (--field) so the autofill inset shadow is that same
   value, with no flattening sum to get wrong.

   Type: Archivo variable (OFL, self-hosted) set EXPANDED (wdth 125) to echo
   the lockup's wide caps; the city names are tracked out like its INVITES.
   ============================================================ */

@font-face {
  font-family: "Archivo";
  src: url("/assets/fonts/Archivo-var.woff2?v=20261008-1") format("woff2");
  font-weight: 100 900; font-stretch: 62% 125%; font-style: normal; font-display: swap;
}

:root {
  --ground:     #000000;
  --field:      #130A07;   /* opaque, see header */
  --field-2:    #1E100B;   /* country search box */
  --field-3:    #2A160E;   /* country search box, focused */
  --cream:      #F4EBE3;
  --cream-soft: rgba(244, 235, 227, .82);
  --cream-dim:  rgba(244, 235, 227, .6);
  --line:       rgba(244, 235, 227, .22);
  --filament:   #FDC6A4;   /* a hot stripe's core: lit markers, focus, checks */
  --flare:      #FF8A3D;   /* the wall's orange: title accent + rail, 8.2:1 on black */
  --cta-bg:     linear-gradient(90deg, #FF5A1A 0%, #FFA466 50%, #FF5A1A 100%);
  --cta-ink:    #120402;   /* 6.5:1 at the button's orange ends, 12:1 at its core */
  --danger:     #FFB4A0;
  --edge:       inset 1px 0 0 rgba(255, 106, 40, .45), inset 34px 0 70px -40px rgba(255, 90, 26, .5);
  --floor:      #000000;

  --display: "Archivo", "Arial Black", Arial, sans-serif;
  --body:    "Archivo", "Helvetica Neue", Helvetica, Arial, sans-serif;

  /* The art track must stay at least ~0.68 as wide as tall or the cover-crop
     reaches the speakers, so the column gives way on squarish windows. */
  --col-w: max(300px, min(clamp(380px, 34vw, 540px), calc(100vw - 70svh)));
}

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

/* The `hidden` attribute is only display:none in the UA stylesheet, the
   weakest rule there is; any display we set on a class beats it. Restore it. */
[hidden] { display: none !important; }

html { background: var(--ground); -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  min-height: 100svh;
  color: var(--cream);
  font-family: var(--body);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
img { max-width: 100%; }

.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;
}

/* ============================================================
   THE STAGE - phones first: a tight band, just the lockup and the DJ, then
   straight into the sign-up (Adam, 2026-10-08: "just the logo and the DJ and
   then straight into sign-up"). plate-phone is pre-cropped from the bottom of
   the tall plate at exactly this 100:84 shape (build_images.py), so it is
   sharp on 3x screens. Four plate rules, mirrored exactly by the four
   <link rel=preload> in index.html.
   ============================================================ */
.page { min-height: 100svh; }

.stage {
  position: relative;
  height: 84vw;
  margin: 0;
  background: var(--floor) url("/assets/images/plate-phone-sm.webp?v=20261008-1") 50% 100% / cover no-repeat;
}
@media (min-width: 501px) {
  .stage { background-image: url("/assets/images/plate-phone.webp?v=20261008-1"); }
}

/* Everything here scales with the width, so the geometry is fixed: the DJ's
   head is 48vw down the stage (his raised hand ~44vw), the lockup's ink ends
   ~32vw down. Checked by compositing the two at 390px before building. */
.stage__lockup {
  position: absolute;
  top: 3vw;
  left: 50%;
  transform: translateX(-50%);
  width: 74vw;
  margin: 0;
  line-height: 0;
}
.stage__lockup img { display: block; width: 100%; height: auto; }

/* ============================================================
   THE ROUTE
   ============================================================ */
.route {
  display: flex;
  flex-direction: column;
  padding: 26px 20px 0;
  background: var(--ground);
}
.stops {
  list-style: none;
  width: 100%;
  max-width: 440px;
  margin: 0 auto;
  padding: 0;
}
.stop { position: relative; padding-left: 42px; }
.stop + .stop { margin-top: 34px; }

/* the orbit glyph from the lockup, redrawn as a marker */
.stop__mark {
  position: absolute;
  left: 0; top: -4px;
  width: 30px; height: 30px;
  fill: none;
  stroke: var(--cream-dim);
  stroke-width: 1.5;
}
.stop__star { fill: var(--cream-dim); stroke: none; }
.stop--live .stop__mark { stroke: var(--filament); filter: drop-shadow(0 0 5px rgba(255, 140, 80, .85)); }
.stop--live .stop__star { fill: var(--filament); }

/* The rail: one lit stripe from each marker down to the next, burning
   brightest at the on-sale stop and cooling towards the next one. */
.stop:not(:last-child)::after {
  content: "";
  position: absolute;
  left: 14px;
  top: 34px;
  bottom: -30px;
  width: 2px;
  border-radius: 2px;
  background: linear-gradient(to bottom, var(--filament), var(--flare) 55%, rgba(255, 154, 92, .3));
  box-shadow: 0 0 10px rgba(255, 120, 60, .55);
}

.stop__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 14px;
}
.stop__city {
  margin: 0;
  font-family: var(--display);
  font-stretch: 125%;
  font-weight: 640;
  font-size: 20px;
  line-height: 1.1;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--cream);
}
.chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 3px 10px;
  font-size: 12.5px;
  font-weight: 650;
  line-height: 1.5;
  color: var(--cream-soft);
  border: 1px solid var(--line);
  border-radius: 999px;
}
.chip--live {
  color: var(--filament);
  border-color: rgba(253, 198, 164, .55);
  background: rgba(253, 198, 164, .1);
}
.chip--live::before {
  content: "";
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--filament);
  box-shadow: 0 0 6px 1px rgba(255, 140, 80, .9);
}
.stop__when { margin: 6px 0 16px; font-size: 15px; color: var(--cream-soft); }

/* Stacked layouts (phones, portrait tablets): NO markers or rail. Their 42px
   indent against a 20px right gutter pushed the whole column visibly right of
   centre (Adam, 2026-10-08: "Maybe lose that on mobile"). Even gutters, and a
   hairline between the two stops instead of the rail. The live chip still
   marks Antwerp as on sale. Exactly the inverse of the two-column condition. */
@media (max-aspect-ratio: 5/4), (max-width: 639px) {
  .stop { padding-left: 0; }
  .stop__mark,
  .stop:not(:last-child)::after { display: none; }
  .stop + .stop { margin-top: 30px; padding-top: 28px; border-top: 1px solid var(--line); }
}

/* --- state machine (app.js flips data-form-state on .panel) --- */
.panel { width: 100%; }
.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; }

.panel__title {
  margin: 4px 0 12px;
  font-family: var(--display);
  font-stretch: 125%;
  font-weight: 780;
  font-size: clamp(28px, 8vw, 38px);
  line-height: 1;
  letter-spacing: -.005em;
  text-transform: uppercase;
  color: var(--cream);
  text-wrap: balance;
}
/* House pattern: the second line carries the accent. */
.panel__title em { font-style: normal; color: var(--flare); }
.panel__lede {
  margin: 0 0 10px;
  font-size: 15px;
  line-height: 1.55;
  color: var(--cream-soft);
  max-width: 42ch;
}
.panel__lede--last { margin-bottom: 20px; }
.panel__lede strong { color: var(--cream); font-weight: 700; }
.panel__success-note { margin: 0 0 12px; color: var(--filament); font-size: 14.5px; font-weight: 700; }

/* ============================================================
   FORM
   ============================================================ */
.form__row { margin: 0 0 12px; }
/* 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 {
  display: block;
  width: 100%;
  min-height: 54px;
  padding: 14px 16px;
  font-family: var(--body);
  font-size: 16px;            /* 16px stops iOS zooming on focus */
  color: var(--cream);
  background: var(--field);
  border: 1.5px solid var(--line);
  border-radius: 6px;
  outline: none;
  transition: border-color .15s ease, box-shadow .15s ease;
  -webkit-appearance: none;
          appearance: none;
}
.form__input::placeholder { color: var(--cream-dim); opacity: 1; }
.form__input:focus {
  border-color: var(--filament);
  box-shadow: 0 0 0 3px rgba(253, 198, 164, .22);
}
.form__input--otp {
  font-family: var(--display);
  font-stretch: 110%;
  font-weight: 700;
  font-size: 26px;
  letter-spacing: .4em;
  text-align: center;
  font-variant-numeric: tabular-nums;
  color: var(--filament);
}
.form__input--otp::placeholder { color: rgba(253, 198, 164, .3); }

/* Chrome paints autofilled inputs pale lavender and IGNORES background /
   background-color on :-webkit-autofill - a huge inset box-shadow is the only
   reliable override. It must be the field's FLATTENED OPAQUE colour, which is
   simply --field here because the field is opaque on purpose. */
.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(--cream) !important;
  caret-color: var(--cream);
  transition: background-color 9999s ease-in-out 0s;   /* stops the lavender flashing in */
}

.form__error { margin: 7px 0 0; font-size: 13.5px; font-weight: 650; 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.
   (The row also carries the hidden attribute; belt and braces.) */
.hp-row { display: none !important; }

.form__row--check { margin: 16px 0 18px; }
.form__check {
  display: grid;
  grid-template-columns: 22px 1fr;
  gap: 12px;
  align-items: start;
  font-size: 13px;
  line-height: 1.5;
  color: var(--cream-soft);
  cursor: pointer;
}
.form__check input {
  -webkit-appearance: none;
          appearance: none;
  width: 22px; height: 22px;
  margin: 1px 0 0;
  border: 1.5px solid var(--cream-dim);
  border-radius: 4px;
  background: var(--field);
  display: grid;
  place-items: center;
  cursor: pointer;
}
.form__check input::after {
  content: "";
  width: 10px; height: 6px;
  border-left: 2.5px solid #120402;
  border-bottom: 2.5px solid #120402;
  transform: translateY(-1px) rotate(-45deg) scale(0);
  transition: transform .12s ease;
}
.form__check input:checked { background: var(--filament); border-color: var(--filament); }
.form__check input:checked::after { transform: translateY(-1px) rotate(-45deg) scale(1); }
.form__check a { color: var(--cream); font-weight: 650; text-decoration: underline; text-underline-offset: 2px; }
.form__check a:hover { color: var(--filament); }

.form__resend { margin: 16px 0 0; font-size: 14px; color: var(--cream-dim); }
.form__resend-btn {
  padding: 0;
  font: inherit;
  font-weight: 650;
  color: var(--cream);
  background: none;
  border: 0;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
.form__resend-btn:hover { color: var(--filament); }
.form__resend-btn:disabled { color: var(--cream-dim); cursor: default; text-decoration: none; }

/* ---------- buttons ----------
   Both CTAs share one look. Type shrinks before
   it can wrap (gotcha 26): "Click here for tickets" is 22 characters in
   expanded caps inside a column already indented for the rail. Black
   theme: a lit stripe, orange ends burning to the hot core. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  min-height: 56px;
  padding: 0 14px;
  font-family: var(--display);
  font-stretch: 112%;
  font-weight: 760;
  font-size: clamp(13px, 3.7vw, 16px);
  letter-spacing: clamp(.02em, .3vw, .07em);
  text-transform: uppercase;
  text-decoration: none;
  text-align: center;
  white-space: nowrap;
  border: 0;
  border-radius: 6px;
  cursor: pointer;
  transition: transform .12s ease, box-shadow .2s ease, filter .15s ease;
}
.btn:disabled { opacity: .65; cursor: default; }
.btn--primary,
.btn--ticket {
  color: var(--cta-ink);
  background: var(--cta-bg);
  box-shadow: 0 10px 30px -12px rgba(255, 120, 60, .7);
}
.btn--primary:hover:not(:disabled),
.btn--ticket:hover { box-shadow: 0 0 0 4px rgba(253, 198, 164, .22), 0 12px 34px -10px rgba(255, 120, 60, .8); }
.btn--primary:active:not(:disabled),
.btn--ticket:active { transform: translateY(2px); box-shadow: 0 0 0 2px rgba(253, 198, 164, .3); }
.btn--whatsapp {
  color: #FFFFFF;
  background: #128C4A;       /* WhatsApp green darkened to 4.9:1 under white */
}
.btn--whatsapp:hover { filter: brightness(1.08); }
.btn--whatsapp:active { transform: translateY(2px); }
.btn__icon { flex: 0 0 auto; width: 20px; height: 20px; }

.wa-hook { margin: 18px 0 12px; font-size: 14px; color: var(--cream-soft); }
.wa-hook strong { color: var(--cream); font-weight: 700; }

/* ============================================================
   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: 1.5px solid var(--line);
  border-radius: 6px;
  box-shadow: 0 22px 44px -16px rgba(0,0,0,.9);
  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: 15px;
  color: var(--cream);
  background: var(--field-2);
  border: 0;
  border-bottom: 1.5px solid var(--line);
}
.iti__search-input::placeholder { color: var(--cream-dim); }
.iti__search-input:focus { outline: none; background: var(--field-3); }
.iti__search-icon { color: var(--cream-dim); }
.iti__country-list { background: var(--field); max-height: 240px; }
.iti__country {
  padding: 9px 12px;
  font-family: var(--body);
  font-size: 14px;
  color: var(--cream);
}
.iti__country:hover,
.iti__country.iti__highlight { background: rgba(253, 198, 164, .16); }
.iti__dial-code { color: var(--cream-dim); }
.iti__country-name { color: var(--cream); }
.iti__selected-country { border-radius: 6px 0 0 6px; }
.iti__selected-country:hover,
.iti__selected-country-primary:hover { background: rgba(253, 198, 164, .1); }
.iti__selected-dial-code { color: var(--cream); font-family: var(--body); font-size: 16px; }
.iti__arrow { border-top-color: var(--cream-dim); }
.iti__arrow--up { border-bottom-color: var(--cream-dim); }

/* ============================================================
   FOOTER - house footer, credit in a pill. Dark band, so the credit
   logo (white wordmark + teal roundel) is used as drawn.
   ============================================================ */
.foot {
  margin-top: auto;
  padding: 40px 0 22px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  text-align: center;
}
.foot__legal { margin: 0; font-size: 12px; color: var(--cream-dim); letter-spacing: .01em; }
.foot__legal a { color: var(--cream-dim); text-decoration: underline; text-underline-offset: 2px; }
.foot__legal a:hover { color: var(--cream); }
/* privacy + T&Cs of entry side by side, wrapping onto two centred lines on narrow phones */
.foot__links { display: flex; flex-wrap: wrap; justify-content: center; gap: 4px 18px; }
.site-built { margin: 0; }
.site-built a {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 11px;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 12px;
  color: var(--cream-dim);
  text-decoration: none;
  transition: border-color .18s ease, color .18s ease;
}
.site-built a:hover { color: var(--cream); border-color: var(--filament); }
.site-built img { display: block; opacity: .9; }

/* ============================================================
   TWO COLUMNS: art track left, route right. Aspect-ratio threshold, not
   orientation (gotcha 20); it matches the desktop plate rules exactly.
   5/4, not the engine's 7/10: below it the art track would be narrower
   than ~0.68 of its height and the cover-crop would reach the speakers.
   ============================================================ */
@media (min-aspect-ratio: 5/4) and (min-width: 640px) {
  .page {
    display: grid;
    grid-template-columns: minmax(0, 1fr) var(--col-w);
  }
  .stage {
    position: sticky;
    top: 0;
    height: 100svh;
    background-image: url("/assets/images/plate-desktop-sm.webp?v=20261008-1");
  }
  /* The DJ's head is 61% down the 3:2 plate; with the plate bottom-anchored
     it never rises above 47% of the track, even on a 21:9 monitor. The lockup
     ends by 8% + 31svh. */
  .stage__lockup { top: 8%; width: min(54%, 62svh); }
  .route {
    min-height: 100svh;
    padding: clamp(28px, 6svh, 64px) clamp(24px, 3vw, 52px) 0;
    box-shadow: var(--edge);
  }
  .stops { margin-top: auto; margin-bottom: auto; }
  .foot { margin-top: 0; padding-top: 34px; }
}
@media (min-aspect-ratio: 5/4) and (min-width: 1501px) {
  .stage { background-image: url("/assets/images/plate-desktop.webp?v=20261008-1"); }
}

/* --- landscape phones are a first-class layout (gotcha 27) ---
   844x390, 932x430, 667x375: two columns, almost no height. Tighter type;
   the route scrolls with the page while the stage stays put. Placed AFTER
   the desktop block so it wins at equal specificity. */
@media (min-aspect-ratio: 5/4) and (min-width: 640px) and (max-height: 520px) {
  :root { --col-w: min(50vw, 400px); }
  .route { padding: 18px 22px 0; }
  .stage__lockup { top: 6%; width: min(54%, 60svh); }
  .stop + .stop { margin-top: 24px; }
  .stop__city { font-size: 17px; }
  .stop__when { margin-bottom: 12px; font-size: 14px; }
  .panel__title { font-size: 26px; margin-bottom: 8px; }
  .panel__lede { font-size: 14px; }
  .panel__lede--last { margin-bottom: 14px; }
  .form__input { min-height: 48px; padding-top: 11px; padding-bottom: 11px; }
  .btn { min-height: 48px; }
  .foot { padding-top: 22px; }
}

/* ============================================================
   THEME "wall": the column in the wall's own orange-red (dev comparison,
   ?theme=wall). White type 5.6:1, title accent + CTAs in black.
   ============================================================ */
html[data-theme="wall"] {
  --ground:     #C2340F;
  --field:      #9C290B;
  --field-2:    #AE2E0D;
  --field-3:    #8A2409;
  --cream-soft: rgba(255, 246, 240, .94);
  --cream-dim:  rgba(255, 246, 240, .78);
  --line:       rgba(255, 246, 240, .4);
  --filament:   #FFE1CC;
  --flare:      #1A0602;
  --cta-bg:     #120402;
  --cta-ink:    #FDC6A4;
  --danger:     #FFFFFF;
  --edge:       inset 1px 0 0 rgba(0, 0, 0, .25);
}
html[data-theme="wall"] .btn--primary,
html[data-theme="wall"] .btn--ticket { box-shadow: 0 10px 26px -14px rgba(0, 0, 0, .8); }

/* ============================================================
   ACCESSIBILITY
   ============================================================ */
:focus-visible {
  outline: 2.5px solid var(--filament);
  outline-offset: 3px;
}
.form__input:focus-visible { outline: none; }   /* the ring + border carry focus */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}
